markdown-maker 1.7.11 → 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 +3 -2
- package/package.json +9 -7
- package/prettierrc.yaml +1 -1
- package/re-test.js +10 -0
- package/src/cltool.ts +35 -22
- package/src/commands.ts +145 -73
- package/src/parse.ts +107 -111
- 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 +4 -9
- package/test/clargs.test.js +2 -2
- package/test/errors.test.js +14 -53
- 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/argparsetest.js +0 -11
- package/build/cltool.d.ts +0 -1
- package/build/cltool.js +0 -141
- package/build/commands.d.ts +0 -9
- package/build/commands.js +0 -140
- package/build/parse.d.ts +0 -57
- package/build/parse.js +0 -298
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,
|
@@ -107,12 +111,13 @@ class Parser {
|
|
107
111
|
* preprocessing, parsing and postprocess
|
108
112
|
**/
|
109
113
|
parse() {
|
114
|
+
load_extensions(this);
|
110
115
|
if (this.opts.verbose || this.opts.debug) {
|
111
116
|
console.log(
|
112
117
|
Colors.colors(
|
113
118
|
"magenta",
|
114
|
-
"parsing " + this.file + ": depth=" + this.opts.depth
|
115
|
-
)
|
119
|
+
"parsing " + this.file + ": depth=" + this.opts.depth,
|
120
|
+
),
|
116
121
|
);
|
117
122
|
}
|
118
123
|
|
@@ -138,11 +143,10 @@ class Parser {
|
|
138
143
|
return __blob;
|
139
144
|
}
|
140
145
|
|
141
|
-
mainparse(blob) {
|
146
|
+
mainparse(blob: string) {
|
142
147
|
if (this.opts.verbose || this.opts.debug) {
|
143
148
|
console.debug(`beginning mainparse of '${this.file}'`.blue);
|
144
149
|
}
|
145
|
-
let __blob = "";
|
146
150
|
|
147
151
|
/* main parser instance loop */
|
148
152
|
blob.split("\n").forEach((line, lnum) => {
|
@@ -157,17 +161,7 @@ class Parser {
|
|
157
161
|
|
158
162
|
/* implement toc level */
|
159
163
|
let level = titleMatch[1].length;
|
160
|
-
|
161
|
-
/**
|
162
|
-
* parse elements of title
|
163
|
-
* such as variables */
|
164
|
-
let title = titleMatch[2]
|
165
|
-
.trim()
|
166
|
-
.split(" ")
|
167
|
-
.map((s) =>
|
168
|
-
s.startsWith(Parser.TOKEN) ? this.parseToken(s) : s
|
169
|
-
)
|
170
|
-
.join("_");
|
164
|
+
let title = titleMatch[2];
|
171
165
|
|
172
166
|
this.opts.secs.push({ level, title });
|
173
167
|
|
@@ -175,101 +169,49 @@ class Parser {
|
|
175
169
|
console.log("updated sections:", { level, title });
|
176
170
|
}
|
177
171
|
}
|
178
|
-
|
179
|
-
let __line_tokens = [];
|
180
|
-
/* split line into tokens */
|
181
|
-
line.split(" ").forEach((token) => {
|
182
|
-
/* if token is not #md token,
|
183
|
-
* just add it and continue */
|
184
|
-
if (token.startsWith(Parser.TOKEN)) {
|
185
|
-
token = this.parseToken(token);
|
186
|
-
}
|
187
|
-
|
188
|
-
__line_tokens.push(token);
|
189
|
-
});
|
190
|
-
/* put line back properly */
|
191
|
-
__blob += __line_tokens.join(" ") + "\n";
|
192
172
|
});
|
193
173
|
|
194
|
-
return
|
174
|
+
return this.parse_commands(blob, commands.parse);
|
195
175
|
}
|
196
176
|
|
197
|
-
|
198
|
-
/* iterate over all commands,
|
199
|
-
* and if command is valid, execute it */
|
200
|
-
|
201
|
-
if (this.opts.verbose || this.opts.debug)
|
202
|
-
console.log("found mdtoken: " + token);
|
203
|
-
|
204
|
-
for (let i = 0; i < commands.parse.length; i++) {
|
205
|
-
const command = commands.parse[i];
|
206
|
-
|
207
|
-
if (command.valid(token, this)) {
|
208
|
-
return command.act(token, this);
|
209
|
-
}
|
210
|
-
}
|
211
|
-
|
212
|
-
/* check if the command is for later */
|
213
|
-
for (let i = 0; i < commands.postparse.length; i++) {
|
214
|
-
const command = commands.postparse[i];
|
215
|
-
|
216
|
-
if (command.valid(token, this)) {
|
217
|
-
return token;
|
218
|
-
}
|
219
|
-
}
|
220
|
-
|
221
|
-
throw new SyntaxError(`Unknown token: ${token}`);
|
222
|
-
}
|
223
|
-
|
224
|
-
preprocess(blob) {
|
177
|
+
preprocess(blob: string) {
|
225
178
|
if (this.opts.verbose || this.opts.debug) {
|
226
179
|
console.debug(`beginning preprocess of '${this.file}'`.blue);
|
227
180
|
}
|
228
|
-
let __blob = "";
|
229
|
-
const lines = blob.split("\n");
|
230
|
-
|
231
|
-
lines.forEach((line) => {
|
232
|
-
let __line_tokens = [];
|
233
|
-
line.split(" ").forEach((token) => {
|
234
|
-
for (const command of commands.preparse) {
|
235
|
-
if (command.valid(token, this)) {
|
236
|
-
token = command.act(token, this);
|
237
|
-
}
|
238
|
-
}
|
239
181
|
|
240
|
-
|
241
|
-
});
|
242
|
-
__blob += __line_tokens.join(" ") + "\n";
|
243
|
-
});
|
244
|
-
return __blob;
|
182
|
+
return this.parse_commands(blob, commands.preparse);
|
245
183
|
}
|
246
184
|
|
247
|
-
postprocess(blob) {
|
185
|
+
postprocess(blob: string) {
|
248
186
|
if (this.opts.verbose || this.opts.debug) {
|
249
187
|
console.debug(`beginning postprocess of '${this.file}'`.blue);
|
250
188
|
}
|
251
|
-
let __blob = "";
|
252
|
-
const lines = blob.split("\n");
|
253
|
-
|
254
|
-
lines.forEach((line) => {
|
255
|
-
let __line_tokens = [];
|
256
|
-
line.split(" ").forEach((token) => {
|
257
|
-
// only look
|
258
|
-
|
259
|
-
for (const command of commands.postparse) {
|
260
|
-
if (command.valid(token, this)) {
|
261
|
-
token = command.act(token, this);
|
262
|
-
}
|
263
|
-
}
|
264
189
|
|
265
|
-
|
266
|
-
});
|
267
|
-
__blob += __line_tokens.join(" ") + "\n";
|
268
|
-
});
|
190
|
+
blob = this.parse_commands(blob, commands.postparse);
|
269
191
|
|
270
192
|
/* remove double empty lines */
|
271
|
-
|
272
|
-
|
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;
|
273
215
|
}
|
274
216
|
|
275
217
|
titleId(title: string) {
|
@@ -290,18 +232,24 @@ class Parser {
|
|
290
232
|
|
291
233
|
this.opts.secs.forEach((sec) => {
|
292
234
|
if (sec.level > this.opts.toc_level) return;
|
293
|
-
|
294
|
-
|
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,13 +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?) {
|
344
299
|
/* If target type is undefined, markdown is the default */
|
345
|
-
if (targetType
|
300
|
+
if (targetType === undefined) targetType = TargetType.MARKDOWN;
|
346
301
|
if (this.blobs[targetType]) {
|
347
302
|
if (callback) {
|
348
303
|
callback(this.blobs[targetType]);
|
@@ -361,9 +316,13 @@ class Parser {
|
|
361
316
|
let p: Parser = this;
|
362
317
|
|
363
318
|
do {
|
364
|
-
|
365
|
-
p.
|
366
|
-
|
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);
|
367
326
|
if (p.parent) p = p.parent;
|
368
327
|
} while (p.parent);
|
369
328
|
|
@@ -379,6 +338,43 @@ class Parser {
|
|
379
338
|
}
|
380
339
|
}
|
381
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
|
+
|
382
378
|
module.exports = Parser;
|
383
379
|
|
384
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,11 +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
|
-
const output = new util.Parser("#mdNON<>").get();
|
7
|
-
}, SyntaxError);
|
8
|
-
});
|
9
4
|
it("should join two files with include", () => {
|
10
5
|
util.put("hello\n#mdinclude<sample2.md>", "sample1.md");
|
11
6
|
util.put("there", "sample2.md");
|
@@ -35,12 +30,12 @@ describe("Basic features", () => {
|
|
35
30
|
);
|
36
31
|
});
|
37
32
|
it("should allow variables in toc", () => {
|
38
|
-
const
|
39
|
-
"#mddef<name=Foobar>\n# mr. #mdvar<name>\n#mdmaketoc<>"
|
40
|
-
);
|
33
|
+
const output = new util.Parser(
|
34
|
+
"#mddef<name= Foobar>\n# mr. #mdvar<name>\n#mdmaketoc<>"
|
35
|
+
).get();
|
41
36
|
|
42
37
|
util.assert.strictEqual(
|
43
|
-
|
38
|
+
output,
|
44
39
|
"\n# mr. Foobar\n* [mr. Foobar](#mr-foobar)\n\n"
|
45
40
|
);
|
46
41
|
});
|
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
|
});
|
@@ -0,0 +1,43 @@
|
|
1
|
+
const util = require("./tester.test.js");
|
2
|
+
|
3
|
+
describe("Marked extentions", () => {
|
4
|
+
it("should add a single class to blockquotes", () => {
|
5
|
+
const parser = new util.Parser("> hello {.one}", {
|
6
|
+
use_underscore: true,
|
7
|
+
html: true,
|
8
|
+
});
|
9
|
+
|
10
|
+
const output = parser.html();
|
11
|
+
|
12
|
+
util.assert.strictEqual(
|
13
|
+
output,
|
14
|
+
'<blockquote class="one" >\n<p>hello </p></blockquote>'
|
15
|
+
);
|
16
|
+
});
|
17
|
+
it("should add multiple class to blockquotes", () => {
|
18
|
+
const parser = new util.Parser("> hello {.one .two}", {
|
19
|
+
use_underscore: true,
|
20
|
+
html: true,
|
21
|
+
});
|
22
|
+
|
23
|
+
const output = parser.html();
|
24
|
+
|
25
|
+
util.assert.strictEqual(
|
26
|
+
output,
|
27
|
+
'<blockquote class="one two" >\n<p>hello </p></blockquote>'
|
28
|
+
);
|
29
|
+
});
|
30
|
+
it("should add a single class and id to blockquotes", () => {
|
31
|
+
const parser = new util.Parser("> hello {.one #myid}", {
|
32
|
+
use_underscore: true,
|
33
|
+
html: true,
|
34
|
+
});
|
35
|
+
|
36
|
+
const output = parser.html();
|
37
|
+
|
38
|
+
util.assert.strictEqual(
|
39
|
+
output,
|
40
|
+
'<blockquote class="one" id="myid">\n<p>hello </p></blockquote>'
|
41
|
+
);
|
42
|
+
});
|
43
|
+
});
|
package/test/target.test.js
CHANGED
@@ -26,11 +26,9 @@ describe("Target specific functionality", () => {
|
|
26
26
|
util.assert.strictEqual(md, '\n\n')
|
27
27
|
});
|
28
28
|
it("Should include #mdref to title elements in markdown", () => {
|
29
|
-
const
|
29
|
+
const output = new util.Parser("# Some Title!\n#mdref<Some Title!>").get();
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
util.assert.strictEqual(md, '# Some Title!\n[Some Title!](#some-title)\n\n')
|
31
|
+
util.assert.strictEqual(output, '# Some Title!\n[Some Title!](#some-title)\n\n')
|
34
32
|
});
|
35
33
|
|
36
34
|
})
|
package/test/tester.test.js
CHANGED
@@ -1,28 +1,30 @@
|
|
1
|
-
const fs = require(
|
2
|
-
const assert = require(
|
3
|
-
const Parser = require(
|
1
|
+
const fs = require("fs");
|
2
|
+
const assert = require("assert");
|
3
|
+
const Parser = require("../build/parse");
|
4
|
+
|
5
|
+
|
4
6
|
|
5
7
|
/* make folder for temporary files, if it doesn't exist */
|
6
8
|
if (
|
7
|
-
|
8
|
-
|
9
|
+
!fs.existsSync("test/test-files") ||
|
10
|
+
!fs.lstatSync("test/test-files").isDirectory()
|
9
11
|
) {
|
10
|
-
|
12
|
+
fs.mkdirSync("test/test-files");
|
11
13
|
}
|
12
14
|
|
13
15
|
function put(text, file) {
|
14
|
-
|
16
|
+
fs.writeFileSync("test/test-files/" + file, text);
|
15
17
|
}
|
16
18
|
|
17
19
|
const TargetType = {
|
18
|
-
|
19
|
-
|
20
|
+
HTML: 0,
|
21
|
+
MARKDOWN: 1,
|
20
22
|
};
|
21
23
|
|
22
24
|
module.exports = {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
fs,
|
26
|
+
assert,
|
27
|
+
Parser,
|
28
|
+
put,
|
29
|
+
TargetType,
|
28
30
|
};
|