markdown-maker 1.7.11 → 1.9.2
Sign up to get free protection for your applications and to get access to all the features.
- package/.github/workflows/node.js.yml +13 -8
- package/README.md +1 -0
- package/doc/.mdmconfig.json +3 -2
- package/package.json +10 -8
- 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 +103 -112
- 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;
|
@@ -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,6 +111,7 @@ 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(
|
@@ -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
|
195
|
-
}
|
196
|
-
|
197
|
-
parseToken(token) {
|
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}`);
|
174
|
+
return this.parse_commands(blob, commands.parse);
|
222
175
|
}
|
223
176
|
|
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,22 @@ 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
|
-
hor.repeat(Math.max(sec.level - 1, 0)) +
|
298
|
-
|
299
|
-
`[${title}](#${link})`;
|
240
|
+
hor.repeat(Math.max(sec.level - 1, 0)) + beg + `[${title}](#${link})`;
|
241
|
+
|
300
242
|
__blob.push(__line);
|
301
243
|
});
|
302
244
|
return __blob.join("\n");
|
303
245
|
}
|
304
246
|
|
247
|
+
line_num_from_index(index: number) {
|
248
|
+
return this.raw.substring(0, index).split("\n").length + 1;
|
249
|
+
}
|
250
|
+
|
305
251
|
remove_double_blank_lines(blob) {
|
306
252
|
/* replace all triple newlines, and EOF by double newline */
|
307
253
|
blob = blob.replace(/(\r\n|\n){3,}/g, "\n\n");
|
@@ -310,25 +256,27 @@ class Parser {
|
|
310
256
|
}
|
311
257
|
|
312
258
|
/* output the parsed document to bundle */
|
313
|
-
to(bundleName,
|
259
|
+
to(bundleName: string, callback: (fileName: string) => void) {
|
314
260
|
const dir = path.dirname(bundleName);
|
315
261
|
var called = false;
|
316
|
-
if (
|
262
|
+
if (callback === undefined) callback = () => {};
|
317
263
|
|
318
264
|
if (!fs.existsSync(dir)) {
|
319
|
-
fs.mkdirSync(dir);
|
265
|
+
fs.mkdirSync(dir, { recursive: true });
|
320
266
|
}
|
321
267
|
this.get(TargetType.MARKDOWN, (blob) => {
|
322
268
|
fs.writeFile(bundleName, blob, () => {
|
323
|
-
if (!
|
324
|
-
|
269
|
+
if (!this.opts.html) {
|
270
|
+
callback(bundleName);
|
271
|
+
called = true;
|
272
|
+
}
|
325
273
|
});
|
326
274
|
});
|
327
275
|
|
328
276
|
if (this.opts.html) {
|
329
277
|
const htmlFileName = bundleName.replace(".md", ".html");
|
330
278
|
fs.writeFile(htmlFileName, this.html(), () => {
|
331
|
-
if (!called)
|
279
|
+
if (!called) callback(htmlFileName);
|
332
280
|
called = true;
|
333
281
|
});
|
334
282
|
}
|
@@ -336,13 +284,18 @@ class Parser {
|
|
336
284
|
|
337
285
|
html() {
|
338
286
|
const htmlFormatted = marked(this.get(TargetType.HTML));
|
339
|
-
|
287
|
+
if (this.opts.watch) {
|
288
|
+
return (
|
289
|
+
`<script>w=new WebSocket("ws:localhost:7788");w.addEventListener("message",(e)=>{if(e.data=="refresh")location.reload();});</script>\n` +
|
290
|
+
htmlFormatted
|
291
|
+
);
|
292
|
+
}
|
340
293
|
return htmlFormatted;
|
341
294
|
}
|
342
295
|
|
343
|
-
get(targetType
|
296
|
+
get(targetType?: TargetType, callback?) {
|
344
297
|
/* If target type is undefined, markdown is the default */
|
345
|
-
if (targetType
|
298
|
+
if (targetType === undefined) targetType = TargetType.MARKDOWN;
|
346
299
|
if (this.blobs[targetType]) {
|
347
300
|
if (callback) {
|
348
301
|
callback(this.blobs[targetType]);
|
@@ -361,9 +314,11 @@ class Parser {
|
|
361
314
|
let p: Parser = this;
|
362
315
|
|
363
316
|
do {
|
364
|
-
|
365
|
-
p.
|
366
|
-
|
317
|
+
if (error instanceof MDMError)
|
318
|
+
traceback += `\n...on line ${p.line_num_from_index(
|
319
|
+
error.match.index
|
320
|
+
)} in ${p.file}`.grey(15);
|
321
|
+
else traceback += `\n...on line ${p.line_num} in ${p.file}`.grey(15);
|
367
322
|
if (p.parent) p = p.parent;
|
368
323
|
} while (p.parent);
|
369
324
|
|
@@ -379,6 +334,42 @@ class Parser {
|
|
379
334
|
}
|
380
335
|
}
|
381
336
|
|
337
|
+
export function splice(
|
338
|
+
str: string,
|
339
|
+
startIndex: number,
|
340
|
+
width: number,
|
341
|
+
newSubStr: string
|
342
|
+
) {
|
343
|
+
const start = str.slice(0, startIndex);
|
344
|
+
const end = str.slice(startIndex + width);
|
345
|
+
return start + newSubStr + end;
|
346
|
+
}
|
347
|
+
|
348
|
+
/* add extention to marked */
|
349
|
+
marked.use({
|
350
|
+
renderer: {
|
351
|
+
blockquote(quote) {
|
352
|
+
/* find the ending, and if not, return the default */
|
353
|
+
const ending = quote.match(/\{(.+)\}\s*<\/p>/);
|
354
|
+
if (!ending) return `<blockquote>${quote}</blockquote>`;
|
355
|
+
|
356
|
+
const args = ending[1].split(" ");
|
357
|
+
|
358
|
+
const classes = args.filter((arg) => arg.startsWith("."));
|
359
|
+
const id = args.filter((arg) => arg.startsWith("#"));
|
360
|
+
|
361
|
+
const classNames = classes.map((c) => c.slice(1));
|
362
|
+
const classText = classes.length > 0 ? `class="${classNames.join(" ")}"` : "";
|
363
|
+
const idText = id.length > 0 ? `id="${id[0].slice(1)}"` : "";
|
364
|
+
|
365
|
+
/* remove the ending from the quote */
|
366
|
+
quote = quote.replace(/\{(.+)\}\s*<\/p>/, "</p>");
|
367
|
+
|
368
|
+
return `<blockquote ${classText} ${idText}>\n${quote.trim()}</blockquote>`;
|
369
|
+
},
|
370
|
+
},
|
371
|
+
});
|
372
|
+
|
382
373
|
module.exports = Parser;
|
383
374
|
|
384
375
|
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
|
};
|
package/tsconfig.json
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
15
15
|
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
16
16
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
17
|
-
|
17
|
+
"sourceMap": true, /* Generates corresponding '.map' file. */
|
18
18
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
19
19
|
"outDir": "./build" /* Redirect output structure to the directory. */,
|
20
20
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
package/argparsetest.js
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
const { ArgumentParser } = require("argparse");
|
2
|
-
const argParser = new ArgumentParser();
|
3
|
-
|
4
|
-
argParser.add_argument("src");
|
5
|
-
argParser.add_argument("-o", "--output");
|
6
|
-
|
7
|
-
console.log(process.argv);
|
8
|
-
|
9
|
-
const args = argParser.parse_args(["-o", "output", "hi"]);
|
10
|
-
|
11
|
-
console.log(args);
|