markdown-maker 1.7.10 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/node.js.yml +13 -8
- package/README.md +1 -0
- package/doc/.mdmconfig.json +7 -0
- package/package.json +9 -7
- package/prettierrc.yaml +1 -1
- package/re-test.js +10 -0
- package/src/cltool.ts +42 -13
- package/src/commands.ts +152 -80
- package/src/parse.ts +114 -116
- package/src/templates/mathjax.js +3 -0
- package/src/templates/presentation.js +3 -0
- package/src/templates.ts +18 -0
- package/test/advanced.test.js +35 -0
- package/test/basic.test.js +29 -22
- package/test/clargs.test.js +2 -2
- package/test/errors.test.js +14 -53
- package/test/html.test.js +9 -3
- package/test/marked.test.js +43 -0
- package/test/target.test.js +2 -4
- package/test/tester.test.js +16 -14
- package/tsconfig.json +1 -1
- package/build/cltool.d.ts +0 -1
- package/build/cltool.js +0 -124
- package/build/commands.d.ts +0 -1
- package/build/commands.js +0 -137
- package/build/parse.d.ts +0 -57
- package/build/parse.js +0 -295
package/src/parse.ts
CHANGED
@@ -4,7 +4,7 @@ const path = require("path"); /* for handling file paths */
|
|
4
4
|
import Colors = require("colors.ts"); /* for adding colours to strings */
|
5
5
|
Colors.enable();
|
6
6
|
const marked = require("marked");
|
7
|
-
|
7
|
+
import { Command, commands, load_extensions, MDMError } from "./commands";
|
8
8
|
|
9
9
|
enum TargetType {
|
10
10
|
HTML,
|
@@ -18,6 +18,7 @@ class Parser {
|
|
18
18
|
parent?: Parser;
|
19
19
|
line_num: number;
|
20
20
|
wd: string;
|
21
|
+
wd_full: string;
|
21
22
|
blobs: {
|
22
23
|
[key: number]: string | undefined;
|
23
24
|
};
|
@@ -36,8 +37,9 @@ class Parser {
|
|
36
37
|
max_depth: number;
|
37
38
|
use_underscore: boolean;
|
38
39
|
toc_level: number;
|
39
|
-
|
40
|
+
allow_undefined: boolean;
|
40
41
|
html: boolean;
|
42
|
+
watch: boolean;
|
41
43
|
targetType: TargetType | undefined;
|
42
44
|
only_warn: boolean;
|
43
45
|
parent?: Parser;
|
@@ -53,7 +55,7 @@ class Parser {
|
|
53
55
|
opts?: {
|
54
56
|
parent?: Parser;
|
55
57
|
isFileCallback?: (s: string) => false | string;
|
56
|
-
}
|
58
|
+
},
|
57
59
|
) {
|
58
60
|
/* this.working_directory */
|
59
61
|
this.file = filename;
|
@@ -65,6 +67,7 @@ class Parser {
|
|
65
67
|
|
66
68
|
this.line_num = 0;
|
67
69
|
this.wd = path.dirname(filename);
|
70
|
+
this.wd_full = path.resolve(this.wd);
|
68
71
|
|
69
72
|
/* finished blob */
|
70
73
|
this.blobs = {};
|
@@ -80,8 +83,9 @@ class Parser {
|
|
80
83
|
max_depth: 5,
|
81
84
|
use_underscore: false,
|
82
85
|
toc_level: 3,
|
83
|
-
|
86
|
+
allow_undefined: false,
|
84
87
|
html: false,
|
88
|
+
watch: false,
|
85
89
|
targetType: undefined,
|
86
90
|
only_warn: false,
|
87
91
|
parent: undefined,
|
@@ -94,6 +98,7 @@ class Parser {
|
|
94
98
|
if (!clargs) {
|
95
99
|
clargs = {};
|
96
100
|
}
|
101
|
+
|
97
102
|
/* append all commandline arguments to this */
|
98
103
|
Object.assign(this.opts, clargs);
|
99
104
|
Object.assign(this.opts, opts);
|
@@ -106,12 +111,13 @@ class Parser {
|
|
106
111
|
* preprocessing, parsing and postprocess
|
107
112
|
**/
|
108
113
|
parse() {
|
114
|
+
load_extensions(this);
|
109
115
|
if (this.opts.verbose || this.opts.debug) {
|
110
116
|
console.log(
|
111
117
|
Colors.colors(
|
112
118
|
"magenta",
|
113
|
-
"parsing " + this.file + ": depth=" + this.opts.depth
|
114
|
-
)
|
119
|
+
"parsing " + this.file + ": depth=" + this.opts.depth,
|
120
|
+
),
|
115
121
|
);
|
116
122
|
}
|
117
123
|
|
@@ -137,11 +143,10 @@ class Parser {
|
|
137
143
|
return __blob;
|
138
144
|
}
|
139
145
|
|
140
|
-
mainparse(blob) {
|
146
|
+
mainparse(blob: string) {
|
141
147
|
if (this.opts.verbose || this.opts.debug) {
|
142
148
|
console.debug(`beginning mainparse of '${this.file}'`.blue);
|
143
149
|
}
|
144
|
-
let __blob = "";
|
145
150
|
|
146
151
|
/* main parser instance loop */
|
147
152
|
blob.split("\n").forEach((line, lnum) => {
|
@@ -156,121 +161,57 @@ class Parser {
|
|
156
161
|
|
157
162
|
/* implement toc level */
|
158
163
|
let level = titleMatch[1].length;
|
164
|
+
let title = titleMatch[2];
|
159
165
|
|
160
|
-
|
161
|
-
* parse elements of title
|
162
|
-
* such as variables */
|
163
|
-
if (level <= this.opts.toc_level) {
|
164
|
-
let title = titleMatch[2]
|
165
|
-
.trim()
|
166
|
-
.split(" ")
|
167
|
-
.map((s) =>
|
168
|
-
s.startsWith(Parser.TOKEN) ? this.parseToken(s) : s
|
169
|
-
)
|
170
|
-
.join("_");
|
171
|
-
|
172
|
-
this.opts.secs.push({ level, title });
|
173
|
-
|
174
|
-
if (this.opts.debug) {
|
175
|
-
console.log("updated sections:", { level, title });
|
176
|
-
}
|
177
|
-
}
|
178
|
-
}
|
166
|
+
this.opts.secs.push({ level, title });
|
179
167
|
|
180
|
-
|
181
|
-
|
182
|
-
line.split(" ").forEach((token) => {
|
183
|
-
/* if token is not #md token,
|
184
|
-
* just add it and continue */
|
185
|
-
if (token.startsWith(Parser.TOKEN)) {
|
186
|
-
token = this.parseToken(token);
|
168
|
+
if (this.opts.debug) {
|
169
|
+
console.log("updated sections:", { level, title });
|
187
170
|
}
|
188
|
-
|
189
|
-
__line_tokens.push(token);
|
190
|
-
});
|
191
|
-
/* put line back properly */
|
192
|
-
__blob += __line_tokens.join(" ") + "\n";
|
193
|
-
});
|
194
|
-
|
195
|
-
return __blob;
|
196
|
-
}
|
197
|
-
|
198
|
-
parseToken(token) {
|
199
|
-
/* iterate over all commands,
|
200
|
-
* and if command is valid, execute it */
|
201
|
-
|
202
|
-
if (this.opts.verbose || this.opts.debug)
|
203
|
-
console.log("found mdtoken: " + token);
|
204
|
-
|
205
|
-
for (let i = 0; i < commands.parse.length; i++) {
|
206
|
-
const command = commands.parse[i];
|
207
|
-
|
208
|
-
if (command.valid(token, this)) {
|
209
|
-
return command.act(token, this);
|
210
171
|
}
|
211
|
-
}
|
212
|
-
|
213
|
-
/* check if the command is for later */
|
214
|
-
for (let i = 0; i < commands.postparse.length; i++) {
|
215
|
-
const command = commands.postparse[i];
|
216
|
-
|
217
|
-
if (command.valid(token, this)) {
|
218
|
-
return token;
|
219
|
-
}
|
220
|
-
}
|
172
|
+
});
|
221
173
|
|
222
|
-
|
174
|
+
return this.parse_commands(blob, commands.parse);
|
223
175
|
}
|
224
176
|
|
225
|
-
preprocess(blob) {
|
177
|
+
preprocess(blob: string) {
|
226
178
|
if (this.opts.verbose || this.opts.debug) {
|
227
179
|
console.debug(`beginning preprocess of '${this.file}'`.blue);
|
228
180
|
}
|
229
|
-
let __blob = "";
|
230
|
-
const lines = blob.split("\n");
|
231
|
-
|
232
|
-
lines.forEach((line) => {
|
233
|
-
let __line_tokens = [];
|
234
|
-
line.split(" ").forEach((token) => {
|
235
|
-
for (const command of commands.preparse) {
|
236
|
-
if (command.valid(token, this)) {
|
237
|
-
token = command.act(token, this);
|
238
|
-
}
|
239
|
-
}
|
240
181
|
|
241
|
-
|
242
|
-
});
|
243
|
-
__blob += __line_tokens.join(" ") + "\n";
|
244
|
-
});
|
245
|
-
return __blob;
|
182
|
+
return this.parse_commands(blob, commands.preparse);
|
246
183
|
}
|
247
184
|
|
248
|
-
postprocess(blob) {
|
185
|
+
postprocess(blob: string) {
|
249
186
|
if (this.opts.verbose || this.opts.debug) {
|
250
187
|
console.debug(`beginning postprocess of '${this.file}'`.blue);
|
251
188
|
}
|
252
|
-
let __blob = "";
|
253
|
-
const lines = blob.split("\n");
|
254
|
-
|
255
|
-
lines.forEach((line) => {
|
256
|
-
let __line_tokens = [];
|
257
|
-
line.split(" ").forEach((token) => {
|
258
|
-
// only look
|
259
|
-
|
260
|
-
for (const command of commands.postparse) {
|
261
|
-
if (command.valid(token, this)) {
|
262
|
-
token = command.act(token, this);
|
263
|
-
}
|
264
|
-
}
|
265
189
|
|
266
|
-
|
267
|
-
});
|
268
|
-
__blob += __line_tokens.join(" ") + "\n";
|
269
|
-
});
|
190
|
+
blob = this.parse_commands(blob, commands.postparse);
|
270
191
|
|
271
192
|
/* remove double empty lines */
|
272
|
-
|
273
|
-
|
193
|
+
blob = this.remove_double_blank_lines(blob);
|
194
|
+
blob = blob.trimEnd() + "\n\n";
|
195
|
+
return blob;
|
196
|
+
}
|
197
|
+
|
198
|
+
parse_commands(blob: string, commands: Command[]) {
|
199
|
+
commands.forEach((command) => {
|
200
|
+
/* Add global flag to RegExp */
|
201
|
+
const re = new RegExp(
|
202
|
+
command.validator.source,
|
203
|
+
(command.validator.flags || "") + "g",
|
204
|
+
);
|
205
|
+
blob = blob.replace(re, (...args) => command.act(args, this) || "");
|
206
|
+
});
|
207
|
+
return blob;
|
208
|
+
}
|
209
|
+
|
210
|
+
parse_all_commands(blob: string, commands: { [key: string]: Command[] }) {
|
211
|
+
Object.keys(commands).forEach((key) => {
|
212
|
+
blob = this.parse_commands(blob, commands[key]);
|
213
|
+
});
|
214
|
+
return blob;
|
274
215
|
}
|
275
216
|
|
276
217
|
titleId(title: string) {
|
@@ -290,18 +231,25 @@ class Parser {
|
|
290
231
|
const hor = " ".repeat(tabSize);
|
291
232
|
|
292
233
|
this.opts.secs.forEach((sec) => {
|
293
|
-
|
294
|
-
|
234
|
+
if (sec.level > this.opts.toc_level) return;
|
235
|
+
let title = sec.title.replace(/_/g, " ");
|
236
|
+
title = this.parse_all_commands(title, commands);
|
237
|
+
const link = this.titleId(title);
|
295
238
|
|
296
239
|
let __line =
|
297
240
|
hor.repeat(Math.max(sec.level - 1, 0)) +
|
298
241
|
beg +
|
299
242
|
`[${title}](#${link})`;
|
243
|
+
|
300
244
|
__blob.push(__line);
|
301
245
|
});
|
302
246
|
return __blob.join("\n");
|
303
247
|
}
|
304
248
|
|
249
|
+
line_num_from_index(index: number) {
|
250
|
+
return this.raw.substring(0, index).split("\n").length + 1;
|
251
|
+
}
|
252
|
+
|
305
253
|
remove_double_blank_lines(blob) {
|
306
254
|
/* replace all triple newlines, and EOF by double newline */
|
307
255
|
blob = blob.replace(/(\r\n|\n){3,}/g, "\n\n");
|
@@ -310,25 +258,27 @@ class Parser {
|
|
310
258
|
}
|
311
259
|
|
312
260
|
/* output the parsed document to bundle */
|
313
|
-
to(bundleName,
|
261
|
+
to(bundleName: string, callback: (fileName: string) => void) {
|
314
262
|
const dir = path.dirname(bundleName);
|
315
263
|
var called = false;
|
316
|
-
if (
|
264
|
+
if (callback === undefined) callback = () => {};
|
317
265
|
|
318
266
|
if (!fs.existsSync(dir)) {
|
319
267
|
fs.mkdirSync(dir);
|
320
268
|
}
|
321
269
|
this.get(TargetType.MARKDOWN, (blob) => {
|
322
270
|
fs.writeFile(bundleName, blob, () => {
|
323
|
-
if (!
|
324
|
-
|
271
|
+
if (!this.opts.html) {
|
272
|
+
callback(bundleName);
|
273
|
+
called = true;
|
274
|
+
}
|
325
275
|
});
|
326
276
|
});
|
327
277
|
|
328
278
|
if (this.opts.html) {
|
329
279
|
const htmlFileName = bundleName.replace(".md", ".html");
|
330
280
|
fs.writeFile(htmlFileName, this.html(), () => {
|
331
|
-
if (!called)
|
281
|
+
if (!called) callback(htmlFileName);
|
332
282
|
called = true;
|
333
283
|
});
|
334
284
|
}
|
@@ -336,11 +286,18 @@ class Parser {
|
|
336
286
|
|
337
287
|
html() {
|
338
288
|
const htmlFormatted = marked(this.get(TargetType.HTML));
|
339
|
-
|
289
|
+
if (this.opts.watch) {
|
290
|
+
return (
|
291
|
+
`<script>w=new WebSocket("ws:localhost:7788");w.addEventListener("message",(e)=>{if(e.data=="refresh")location.reload();});</script>\n` +
|
292
|
+
htmlFormatted
|
293
|
+
);
|
294
|
+
}
|
340
295
|
return htmlFormatted;
|
341
296
|
}
|
342
297
|
|
343
|
-
get(targetType
|
298
|
+
get(targetType?: TargetType, callback?) {
|
299
|
+
/* If target type is undefined, markdown is the default */
|
300
|
+
if (targetType === undefined) targetType = TargetType.MARKDOWN;
|
344
301
|
if (this.blobs[targetType]) {
|
345
302
|
if (callback) {
|
346
303
|
callback(this.blobs[targetType]);
|
@@ -359,9 +316,13 @@ class Parser {
|
|
359
316
|
let p: Parser = this;
|
360
317
|
|
361
318
|
do {
|
362
|
-
|
363
|
-
p.
|
364
|
-
|
319
|
+
if (error instanceof MDMError)
|
320
|
+
traceback += `\n...on line ${p.line_num_from_index(
|
321
|
+
error.match.index,
|
322
|
+
)} in ${p.file}`.grey(15);
|
323
|
+
else
|
324
|
+
traceback +=
|
325
|
+
`\n...on line ${p.line_num} in ${p.file}`.grey(15);
|
365
326
|
if (p.parent) p = p.parent;
|
366
327
|
} while (p.parent);
|
367
328
|
|
@@ -377,6 +338,43 @@ class Parser {
|
|
377
338
|
}
|
378
339
|
}
|
379
340
|
|
341
|
+
export function splice(
|
342
|
+
str: string,
|
343
|
+
startIndex: number,
|
344
|
+
width: number,
|
345
|
+
newSubStr: string,
|
346
|
+
) {
|
347
|
+
const start = str.slice(0, startIndex);
|
348
|
+
const end = str.slice(startIndex + width);
|
349
|
+
return start + newSubStr + end;
|
350
|
+
}
|
351
|
+
|
352
|
+
/* add extention to marked */
|
353
|
+
marked.use({
|
354
|
+
renderer: {
|
355
|
+
blockquote(quote) {
|
356
|
+
/* find the ending, and if not, return the default */
|
357
|
+
const ending = quote.match(/\{(.+)\}\s*<\/p>/);
|
358
|
+
if (!ending) return `<blockquote>${quote}</blockquote>`;
|
359
|
+
|
360
|
+
const args = ending[1].split(" ");
|
361
|
+
|
362
|
+
const classes = args.filter((arg) => arg.startsWith("."));
|
363
|
+
const id = args.filter((arg) => arg.startsWith("#"));
|
364
|
+
|
365
|
+
const classNames = classes.map((c) => c.slice(1));
|
366
|
+
const classText =
|
367
|
+
classes.length > 0 ? `class="${classNames.join(" ")}"` : "";
|
368
|
+
const idText = id.length > 0 ? `id="${id[0].slice(1)}"` : "";
|
369
|
+
|
370
|
+
/* remove the ending from the quote */
|
371
|
+
quote = quote.replace(/\{(.+)\}\s*<\/p>/, "</p>");
|
372
|
+
|
373
|
+
return `<blockquote ${classText} ${idText}>\n${quote.trim()}</blockquote>`;
|
374
|
+
},
|
375
|
+
},
|
376
|
+
});
|
377
|
+
|
380
378
|
module.exports = Parser;
|
381
379
|
|
382
380
|
export default Parser;
|
@@ -0,0 +1,3 @@
|
|
1
|
+
const template = `<style>html {width: 100vw;height: 100vh;}.slide {padding: 5%;border-radius: 25px;margin: 0;}div > .slide-num {position: absolute;top: 12.5%;right: 15%;/* font-size: 150%; */}body {margin: 5% 15%;}img {max-width: 100%;max-height: 40vh;}</style><script>document.addEventListener("DOMContentLoaded", () => {let current_slide = 0;const all_slides = document.querySelectorAll("div.slide");const num_slides = all_slides.length;all_slides.forEach((slide) => {const num_elem = document.createElement("p");num_elem.classList.add("slide-num");slide.appendChild(num_elem);});onkeydown = (ev) => {if (ev.key == "ArrowRight" && current_slide < all_slides.length - 1)update_slide(++current_slide);else if (ev.key == "ArrowLeft" && current_slide > 0)update_slide(--current_slide);};const update_slide = (index) => {all_slides.forEach((slide) => (slide.style.display = "none"));all_slides[current_slide].style.display = "block";all_slides[current_slide].lastChild.textContent = \`\${current_slide + 1} / \${num_slides}\`;};update_slide(current_slide);});</script>`;
|
2
|
+
|
3
|
+
module.exports = template;
|
package/src/templates.ts
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
const templates: { [key: string]: string } = {};
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Function to add a template to the templates object. Similar to definitions and variables, but reside as an extension.
|
5
|
+
* @param name The name of the template
|
6
|
+
* @param content The replacement string
|
7
|
+
*/
|
8
|
+
export function new_template(name: string, content: string) {
|
9
|
+
templates[name] = content;
|
10
|
+
}
|
11
|
+
|
12
|
+
/* initialize default templates */
|
13
|
+
const presentation_template = require("../src/templates/presentation.js");
|
14
|
+
const mathjax_template = require("../src/templates/mathjax.js");
|
15
|
+
new_template("presentation", presentation_template);
|
16
|
+
new_template("mathjax", mathjax_template);
|
17
|
+
|
18
|
+
export default templates;
|
@@ -0,0 +1,35 @@
|
|
1
|
+
const util = require("./tester.test.js");
|
2
|
+
|
3
|
+
util.put(
|
4
|
+
"module.exports = {main: (new_template, new_command) => {new_template('hi', 'hello'); new_command(/#test_cmd/, (t,p) => 'yeet', 0);}};",
|
5
|
+
"extensions.js"
|
6
|
+
);
|
7
|
+
|
8
|
+
describe("Use of templates", () => {
|
9
|
+
it("should import presentation template as expected", () => {
|
10
|
+
const output = new util.Parser("#mdtemplate<presentation>").get();
|
11
|
+
const template = `<style>html {width: 100vw;height: 100vh;}.slide {padding: 5%;border-radius: 25px;margin: 0;}div > .slide-num {position: absolute;top: 12.5%;right: 15%;/* font-size: 150%; */}body {margin: 5% 15%;}img {max-width: 100%;max-height: 40vh;}</style><script>document.addEventListener("DOMContentLoaded", () => {let current_slide = 0;const all_slides = document.querySelectorAll("div.slide");const num_slides = all_slides.length;all_slides.forEach((slide) => {const num_elem = document.createElement("p");num_elem.classList.add("slide-num");slide.appendChild(num_elem);});onkeydown = (ev) => {if (ev.key == "ArrowRight" && current_slide < all_slides.length - 1)update_slide(++current_slide);else if (ev.key == "ArrowLeft" && current_slide > 0)update_slide(--current_slide);};const update_slide = (index) => {all_slides.forEach((slide) => (slide.style.display = "none"));all_slides[current_slide].style.display = "block";all_slides[current_slide].lastChild.textContent = \`\${current_slide + 1} / \${num_slides}\`;};update_slide(current_slide);});</script>`;
|
12
|
+
|
13
|
+
util.assert.strictEqual(output, template + "\n\n");
|
14
|
+
});
|
15
|
+
|
16
|
+
it("should use custom templates from project extensions.js file", () => {
|
17
|
+
util.put("#mdtemplate<hi>", "sample1.md");
|
18
|
+
|
19
|
+
util.assert.strictEqual(
|
20
|
+
new util.Parser("test/test-files/sample1.md").get(),
|
21
|
+
"hello\n\n"
|
22
|
+
);
|
23
|
+
|
24
|
+
/* make sure to remove after, to not mess with future tests */
|
25
|
+
});
|
26
|
+
|
27
|
+
it("should use custom commands from project extensions.js file", () => {
|
28
|
+
util.put("#test_cmd", "sample1.md");
|
29
|
+
|
30
|
+
const parser = new util.Parser("test/test-files/sample1.md");
|
31
|
+
util.assert.strictEqual(parser.get(), "yeet\n\n");
|
32
|
+
|
33
|
+
/* make sure to remove after, to not mess with future tests */
|
34
|
+
});
|
35
|
+
});
|
package/test/basic.test.js
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
const util = require("./tester.test.js");
|
2
2
|
|
3
3
|
describe("Basic features", () => {
|
4
|
-
it("should raise an error if invalid token", () => {
|
5
|
-
util.assert.throws(
|
6
|
-
() => {
|
7
|
-
const output = new util.Parser("#mdNON<>").get();
|
8
|
-
},
|
9
|
-
SyntaxError
|
10
|
-
)
|
11
|
-
});
|
12
4
|
it("should join two files with include", () => {
|
13
5
|
util.put("hello\n#mdinclude<sample2.md>", "sample1.md");
|
14
6
|
util.put("there", "sample2.md");
|
@@ -19,32 +11,47 @@ describe("Basic features", () => {
|
|
19
11
|
util.assert.strictEqual(output, "hello\nthere\n\n");
|
20
12
|
});
|
21
13
|
it("should make a table of contents", () => {
|
22
|
-
const output = new util.Parser(
|
14
|
+
const output = new util.Parser(
|
15
|
+
"# yo\n## bruh nugget\n#mdmaketoc"
|
16
|
+
).get();
|
23
17
|
|
24
|
-
util.assert.strictEqual(
|
18
|
+
util.assert.strictEqual(
|
19
|
+
output,
|
20
|
+
"# yo\n## bruh nugget\n* [yo](#yo)\n * [bruh nugget](#bruh-nugget)\n\n"
|
21
|
+
);
|
25
22
|
});
|
26
23
|
it("should allow quotation marks in titles for toc", () => {
|
27
|
-
const parser = new util.Parser("# mac's farm\n#mdmaketoc")
|
24
|
+
const parser = new util.Parser("# mac's farm\n#mdmaketoc");
|
28
25
|
const markdown = parser.get();
|
29
26
|
|
30
|
-
util.assert.strictEqual(
|
27
|
+
util.assert.strictEqual(
|
28
|
+
markdown,
|
29
|
+
"# mac's farm\n* [mac's farm](#macs-farm)\n\n"
|
30
|
+
);
|
31
31
|
});
|
32
32
|
it("should allow variables in toc", () => {
|
33
|
-
const
|
33
|
+
const output = new util.Parser(
|
34
|
+
"#mddef<name= Foobar>\n# mr. #mdvar<name>\n#mdmaketoc<>"
|
35
|
+
).get();
|
34
36
|
|
35
|
-
util.assert.strictEqual(
|
37
|
+
util.assert.strictEqual(
|
38
|
+
output,
|
39
|
+
"\n# mr. Foobar\n* [mr. Foobar](#mr-foobar)\n\n"
|
40
|
+
);
|
36
41
|
});
|
37
42
|
it("should not exceed max include depth", () => {
|
38
43
|
util.put("#mdinclude<sample2.md>", "sample1.md");
|
39
44
|
util.put("yo.md>", "sample2.md");
|
40
45
|
|
41
|
-
util.assert.throws(
|
42
|
-
()
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
)
|
46
|
+
util.assert.throws(() => {
|
47
|
+
const parser = new util.Parser("test/test-files/sample1.md");
|
48
|
+
parser.opts.max_depth = 0;
|
49
|
+
parser.get();
|
50
|
+
}, Error);
|
51
|
+
});
|
52
|
+
it("should be able to reference toc elements, even if they are below toc-level", () => {
|
53
|
+
const parser = new util.Parser(`### Title\n#mdref<Title>`);
|
54
|
+
|
55
|
+
util.assert.strictEqual(parser.get(), "### Title\n[Title](#title)\n\n");
|
49
56
|
});
|
50
57
|
});
|
package/test/clargs.test.js
CHANGED
@@ -20,14 +20,14 @@ describe("Command Line Arguments", () => {
|
|
20
20
|
});
|
21
21
|
it("--allow-undef should not throw when variable is not defined", () => {
|
22
22
|
const output = new util.Parser("#mdvar<zum>", {
|
23
|
-
|
23
|
+
allow_undefined: true,
|
24
24
|
}).get();
|
25
25
|
|
26
26
|
util.assert.strictEqual(output, "<zum>\n\n");
|
27
27
|
});
|
28
28
|
describe("Conditional imports", () => {
|
29
29
|
it("should be able to conditionally import documents", () => {
|
30
|
-
util.put("hello\n#mdinclude<sample2.md,YES>", "sample1.md");
|
30
|
+
util.put("hello\n#mdinclude<sample2.md, YES>", "sample1.md");
|
31
31
|
util.put("there", "sample2.md");
|
32
32
|
|
33
33
|
const parser = new util.Parser("test/test-files/sample1.md");
|
package/test/errors.test.js
CHANGED
@@ -1,65 +1,26 @@
|
|
1
|
+
const { Parser } = require("marked");
|
1
2
|
const util = require("./tester.test.js");
|
2
3
|
|
3
4
|
describe("Error handling", () => {
|
4
|
-
it("should
|
5
|
-
util.put("
|
5
|
+
it("should dissallow undefined templates", () => {
|
6
|
+
util.put("#mdtemplate<UNDEF>", "sample1.md");
|
6
7
|
|
7
8
|
const parser = new util.Parser("test/test-files/sample1.md");
|
8
9
|
|
9
10
|
let e;
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
e = _e;
|
17
|
-
throw _e;
|
18
|
-
}
|
11
|
+
util.assert.throws(() => {
|
12
|
+
try {
|
13
|
+
parser.get();
|
14
|
+
} catch (_e) {
|
15
|
+
e = _e;
|
16
|
+
throw _e;
|
19
17
|
}
|
20
|
-
)
|
18
|
+
}, Error);
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
*/
|
26
|
-
util.assert.strictEqual(
|
27
|
-
e.message,
|
28
|
-
"Unknown token: #mdNON" +
|
29
|
-
"\n...on line 4 in test/test-files/sample1.md".grey(15)
|
30
|
-
)
|
20
|
+
let answer =
|
21
|
+
'Template "UNDEF" not found!' +
|
22
|
+
"\n...on line 1 in test/test-files/sample1.md".grey(15);
|
31
23
|
|
32
|
-
|
33
|
-
it("should traceback across file includes", () => {
|
34
|
-
util.put("\n#mdinclude<sample2.md>", "sample1.md");
|
35
|
-
util.put("#mdNON", "sample2.md");
|
36
|
-
|
37
|
-
const parser = new util.Parser("test/test-files/sample1.md");
|
38
|
-
|
39
|
-
let e;
|
40
|
-
|
41
|
-
/* should throw SyntaxError */
|
42
|
-
util.assert.throws(
|
43
|
-
/* run parser, but store error for further inspection */
|
44
|
-
() => {
|
45
|
-
try {
|
46
|
-
parser.get();
|
47
|
-
} catch (_e) {
|
48
|
-
e = _e;
|
49
|
-
throw _e;
|
50
|
-
}
|
51
|
-
},
|
52
|
-
SyntaxError
|
53
|
-
);
|
54
|
-
|
55
|
-
/* ...where the error message is the traceback on line 2 -> */
|
56
|
-
let answer = "Unknown token: #mdNON" +
|
57
|
-
"\n...on line 1 in test/test-files/sample2.md".grey(15) +
|
58
|
-
"\n...on line 2 in test/test-files/sample1.md".grey(15);
|
59
|
-
|
60
|
-
util.assert.strictEqual(
|
61
|
-
e.message.replace(/(\\)+/g, "/"),
|
62
|
-
answer
|
63
|
-
);
|
24
|
+
util.assert.strictEqual(e.message.replace(/(\\)+/g, "/"), answer);
|
64
25
|
});
|
65
26
|
});
|
package/test/html.test.js
CHANGED
@@ -7,7 +7,10 @@ describe("HTML Emitting", () => {
|
|
7
7
|
parser.opts.quiet = true;
|
8
8
|
|
9
9
|
parser.to("test/test-files/dist/bundle.md", () => {
|
10
|
-
util.assert.strictEqual(
|
10
|
+
util.assert.strictEqual(
|
11
|
+
util.fs.existsSync("test/test-files/dist/bundle.html"),
|
12
|
+
true
|
13
|
+
);
|
11
14
|
done();
|
12
15
|
});
|
13
16
|
});
|
@@ -17,7 +20,10 @@ describe("HTML Emitting", () => {
|
|
17
20
|
|
18
21
|
const output = parser.html();
|
19
22
|
|
20
|
-
util.assert.strictEqual(
|
23
|
+
util.assert.strictEqual(
|
24
|
+
output,
|
25
|
+
'<h1 id="cool-title">cool title</h1>\n<p>with a cool paragraph</p>\n'
|
26
|
+
);
|
21
27
|
});
|
22
28
|
it("should be able to include html documents, and not parse", () => {
|
23
29
|
util.put("#mdinclude<sample2.html>", "sample1.md");
|
@@ -28,4 +34,4 @@ describe("HTML Emitting", () => {
|
|
28
34
|
|
29
35
|
util.assert.strictEqual(output, "#mdvar<lul>\n\n");
|
30
36
|
});
|
31
|
-
})
|
37
|
+
});
|