markdown-maker 1.7.11 → 1.9.2
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 +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);
|