markdown-maker 1.10.2 → 1.10.3

Sign up to get free protection for your applications and to get access to all the features.
package/src/templates.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { MDMError, MDMNonParserError } from "./errors";
2
+
1
3
  const templates: { [key: string]: string } = {};
2
4
 
3
5
  /**
@@ -6,7 +8,9 @@ const templates: { [key: string]: string } = {};
6
8
  * @param content The replacement string
7
9
  */
8
10
  export function new_template(name: string, content: string) {
9
- templates[name] = content;
11
+ if (name in templates)
12
+ throw new MDMNonParserError(`Template "${name}" already exists`);
13
+ templates[name] = content;
10
14
  }
11
15
 
12
16
  /* initialize default templates */
package/src/types.ts ADDED
@@ -0,0 +1,33 @@
1
+ import { HTMLElement } from "node-html-parser";
2
+ import { Command } from "./commands";
3
+
4
+ export type CommandGroupType = {
5
+ preparse: Command[];
6
+ parse: Command[];
7
+ postparse: Command[];
8
+ };
9
+
10
+ type TaggedElementArguments = {
11
+ repeat?: number;
12
+ };
13
+
14
+ export type TaggedElement = {
15
+ "html-tag": string;
16
+ "var-tag": string;
17
+ _raw: string;
18
+ args: TaggedElementArguments;
19
+ node: HTMLElement;
20
+ };
21
+
22
+ export enum CommandType {
23
+ PREPARSE,
24
+ PARSE,
25
+ POSTPARSE,
26
+ }
27
+
28
+ export enum TargetType {
29
+ HTML,
30
+ MARKDOWN,
31
+ }
32
+
33
+ export type Checksum = string;
@@ -0,0 +1,44 @@
1
+ import fs from "fs";
2
+ import Parser from "../src/parser";
3
+ import path from "path";
4
+ import { expect, jest, test } from "@jest/globals";
5
+ import { TargetType } from "../src/types";
6
+
7
+ beforeAll(() => {
8
+ return new Promise((res, rej) => {
9
+ fs.mkdir(path.join("tests", "test-files"), res);
10
+ });
11
+ });
12
+ // afterAll(() => {
13
+ // return new Promise((res, rej) => {
14
+ // fs.rm(path.join("tests", "test-files"), { recursive: true }, res);
15
+ // });
16
+ // });
17
+
18
+ function put(text: string | NodeJS.ArrayBufferView, file: string) {
19
+ fs.writeFileSync(path.join("tests", "test-files", file), text);
20
+ }
21
+ function putDir(name: string) {
22
+ fs.mkdirSync(path.join("tests", "test-files", name));
23
+ }
24
+
25
+ beforeEach(() => {
26
+ return new Promise((res, rej) => {
27
+ fs.mkdir("tests/test-files", res);
28
+ });
29
+ });
30
+
31
+ afterEach(() => {
32
+ return new Promise((res, rej) => {
33
+ fs.rm("tests/test-files", { recursive: true }, res);
34
+ });
35
+ });
36
+
37
+ export default {
38
+ expect,
39
+ path,
40
+ Parser,
41
+ put,
42
+ putDir,
43
+ TargetType,
44
+ };
@@ -0,0 +1,92 @@
1
+ import util from "./_test-util";
2
+
3
+ describe("Use of templates", function () {
4
+ it("should import presentation template as expected", function () {
5
+ const output = new util.Parser("#mdtemplate<presentation>").get();
6
+ 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>`;
7
+
8
+ util.expect(output).toBe(template + "\n\n");
9
+ });
10
+
11
+ it("should use custom templates from project extensions.js file", () => {
12
+ util.put(
13
+ "module.exports = {main: (new_template, _) => {new_template('hi', 'hello');}};",
14
+ "extensions.js"
15
+ );
16
+ util.put("#mdtemplate<hi>", "sample1.md");
17
+
18
+ util.expect(new util.Parser("tests/test-files/sample1.md").get()).toBe(
19
+ "hello\n\n"
20
+ );
21
+ });
22
+
23
+ it("should use custom commands from project extensions.js file", () => {
24
+ util.put(
25
+ 'module.exports = {main: (_, new_command) => {new_command(/#teep/, () => "#peet")}};',
26
+ "extensions.js"
27
+ );
28
+ util.put("#teep", "sample1.md");
29
+
30
+ const parser = new util.Parser("tests/test-files/sample1.md");
31
+ const output = parser.get();
32
+
33
+ util.expect(output).toEqual("#peet\n\n");
34
+ });
35
+ });
36
+
37
+ describe("Use of markdown hooks for SSR", () => {
38
+ it("should allow hooks hooks to be used", () => {
39
+ util.put("#mdhook<t1>\n<p::var>\n#mdendhook<t1>", "sample1.md");
40
+
41
+ const parser = new util.Parser("tests/test-files/sample1.md", {
42
+ allow_undefined: true,
43
+ });
44
+ parser.add_hook("t1", (map) => {
45
+ map["var"].node.textContent = "complete";
46
+ });
47
+
48
+ const output = parser.get();
49
+
50
+ util.expect(output).toBe("<p>complete</p>\n\n");
51
+ });
52
+
53
+ it("should allow for extracting a node from the document as a template using map", () => {
54
+ util.put(
55
+ `<html><body>#mdhook<template><b::name><p::class>#mdendhook<template></body></html>`,
56
+ "sample1.html"
57
+ );
58
+
59
+ const parser = new util.Parser("tests/test-files/sample1.html", {
60
+ allow_undefined: true,
61
+ });
62
+
63
+ parser.add_hook("template", (map) => {
64
+ map["name"].node.textContent = "bold";
65
+ map["class"].node.textContent = "paragraph";
66
+ });
67
+ const output = parser.get();
68
+
69
+ util.expect(output).toBe(
70
+ "<html><body><b>bold</b><p>paragraph</p></body></html>\n\n"
71
+ );
72
+ });
73
+ it("should allow for nested hooks to be used", () => {
74
+ util.put(
75
+ "#mdhook<t1><p::outer1>#mdhook<t2><p::inner>#mdendhook<t2><p::outer2>#mdendhook<t1>",
76
+ "sample1.md"
77
+ );
78
+
79
+ const parser = new util.Parser("tests/test-files/sample1.md", {});
80
+ parser.add_hook("t1", (map) => {
81
+ map["outer1"].node.textContent = "hello";
82
+ map["outer2"].node.textContent = "world";
83
+ });
84
+ parser.add_hook("t2", (map) => {
85
+ map["inner"].node.textContent = "!";
86
+ });
87
+
88
+ const output = parser.get();
89
+
90
+ util.expect(output).toBe("<p>hello</p><p>!</p><p>world</p>\n\n");
91
+ });
92
+ });
@@ -0,0 +1,68 @@
1
+ import util from "./_test-util";
2
+ import { MDMError } from "../src/errors";
3
+
4
+ describe("Basic features", () => {
5
+ it("should join two files with include", () => {
6
+ util.put("hello\n#mdinclude<sample2.md>", "sample1.md");
7
+ util.put("there", "sample2.md");
8
+
9
+ const parser = new util.Parser("tests/test-files/sample1.md");
10
+ const output = parser.get();
11
+
12
+ util.expect(output).toEqual("hello\nthere\n\n");
13
+ });
14
+ it("should make a table of contents", () => {
15
+ const output = new util.Parser(
16
+ "# yo\n## bruh nugget\n#mdmaketoc"
17
+ ).get();
18
+
19
+ util.expect(output).toBe(
20
+ "# yo\n## bruh nugget\n* [yo](#yo)\n * [bruh nugget](#bruh-nugget)\n\n"
21
+ );
22
+ });
23
+ it("should allow quotation marks in titles for toc", () => {
24
+ const parser = new util.Parser("# mac's farm\n#mdmaketoc");
25
+ const markdown = parser.get();
26
+
27
+ util.expect(markdown).toBe(
28
+ "# mac's farm\n* [mac's farm](#macs-farm)\n\n"
29
+ );
30
+ });
31
+ it("should allow variables in toc", () => {
32
+ const output = new util.Parser(
33
+ "#mddef<name=Foobar>\n# mr. #mdvar<name>\n#mdmaketoc<>"
34
+ ).get();
35
+
36
+ util.expect(output).toBe(
37
+ "\n# mr. Foobar\n* [mr. Foobar](#mr-foobar)\n\n"
38
+ );
39
+ });
40
+ it("should not exceed max include depth", () => {
41
+ util.put("#mdinclude<sample2.md>", "sample1.md");
42
+ util.put("yo.md>", "sample2.md");
43
+
44
+ function get() {
45
+ const parser = new util.Parser("tests/test-files/sample1.md", {
46
+ max_depth: 0,
47
+ });
48
+ parser.get();
49
+ }
50
+
51
+ util.expect(get).toThrow(MDMError);
52
+ });
53
+ it("should be able to reference toc elements, even if they are below toc-level", () => {
54
+ const parser = new util.Parser(`### Title\n#mdref<Title>`);
55
+
56
+ util.expect(parser.get()).toBe("### Title\n[Title](#title)\n\n");
57
+ });
58
+ it("should include file with same name as folder when including a folder", () => {
59
+ util.put("#mdinclude<sample_fld>", "sample1.md");
60
+ util.putDir("sample_fld");
61
+ util.put("hello", util.path.join("sample_fld", "sample_fld.md"));
62
+
63
+ const parser = new util.Parser("tests/test-files/sample1.md");
64
+ const output = parser.get();
65
+
66
+ util.expect(output).toBe("hello\n\n");
67
+ });
68
+ });
@@ -0,0 +1,50 @@
1
+ import util from "./_test-util";
2
+
3
+ describe("Command Line Arguments", () => {
4
+ it("--use-underscore should replace '-' with '_' in toc", () => {
5
+ const output = new util.Parser("# foo bar\n#mdmaketoc", {
6
+ use_underscore: true,
7
+ }).get();
8
+
9
+ util.expect(output).toBe("# foo bar\n* [foo bar](#foo_bar)\n\n");
10
+ });
11
+ it("--toc-level should exclude subsection with lower level", () => {
12
+ const output = new util.Parser("# foo bar\n### baz\n#mdmaketoc", {
13
+ toc_level: 2,
14
+ }).get();
15
+
16
+ util.expect(output).toBe(
17
+ "# foo bar\n### baz\n* [foo bar](#foo-bar)\n\n"
18
+ );
19
+ });
20
+ it("--allow-undef should not throw when variable is not defined", () => {
21
+ const output = new util.Parser("#mdvar<zum>", {
22
+ allow_undefined: true,
23
+ }).get();
24
+
25
+ util.expect(output).toBe("<zum>\n\n");
26
+ });
27
+ });
28
+ describe("Conditional imports", () => {
29
+ it("should be able to conditionally import documents", () => {
30
+ util.put("hello\n#mdinclude<sample2.md, YES>", "sample1.md");
31
+ util.put("there", "sample2.md");
32
+
33
+ const parser = new util.Parser("tests/test-files/sample1.md");
34
+ parser.opts.args.push("YES");
35
+
36
+ const output = parser.get();
37
+
38
+ util.expect(output).toBe("hello\nthere\n\n");
39
+ });
40
+ it("shouldn't include a document when flag is unset", () => {
41
+ util.put("hello\n#mdinclude<sample2.md,YES>", "sample1.md");
42
+ util.put("there", "sample2.md");
43
+
44
+ const parser = new util.Parser("tests/test-files/sample1.md");
45
+
46
+ const output = parser.get();
47
+
48
+ util.expect(output).toBe("hello\n\n");
49
+ });
50
+ });
@@ -0,0 +1,64 @@
1
+ import { MDMError, MDMNonParserError } from "../src/errors";
2
+ import util from "./_test-util";
3
+
4
+ describe("Error handling", () => {
5
+ it("should dissallow undefined templates", () => {
6
+ util.put("#mdtemplate<UNDEF>", "sample1.md");
7
+
8
+ const parser = new util.Parser("tests/test-files/sample1.md");
9
+
10
+ let answer =
11
+ 'Template "UNDEF" not found!' +
12
+ "\n...on line 1 in tests/test-files/sample1.md".grey(15);
13
+
14
+ util.expect(() => parser.get()).toThrow(MDMError);
15
+ });
16
+ it("should dissallow loading a folder without an entry file", () => {
17
+ util.put("#mdinclude<sample_fld>", "sample1.md");
18
+ util.putDir("sample_fld");
19
+
20
+ function get() {
21
+ const parser = new util.Parser("tests/test-files/sample1.md");
22
+ parser.get();
23
+ }
24
+
25
+ let answer =
26
+ 'No entry file found in folder "sample_fld". Looking for "tests/test-files/sample_fld/sample_fld.md"' +
27
+ "\n...on line 1 in tests/test-files/sample1.md".grey(15);
28
+
29
+ util.expect(get).toThrow(MDMError);
30
+ util.expect(get).toThrow(answer);
31
+ });
32
+ it("should dissallow adding more than one hook with the same name", () => {
33
+ const parser = new util.Parser("tests/test-files/sample1.md");
34
+
35
+ parser.add_hook("test", () => {});
36
+ util.expect(() => parser.add_hook("test", () => {})).toThrow(
37
+ MDMNonParserError
38
+ );
39
+ });
40
+ describe("Duplicate key errors", () => {
41
+ it("should dissallow adding more than one template with the same name", () => {
42
+ /* */
43
+ util.put(
44
+ `module.exports = {main: (new_template, new_command) =>
45
+ {
46
+ new_template('test', 'hello');
47
+ new_template('test', 'hello');
48
+ }
49
+ };`,
50
+ "extensions.js"
51
+ );
52
+
53
+ util.put("", "sample1.md");
54
+
55
+ function get() {
56
+ const parser = new util.Parser("tests/test-files/sample1.md");
57
+ parser.get();
58
+ }
59
+
60
+ util.expect(get).toThrow(MDMNonParserError);
61
+ util.expect(get).toThrow('Template "test" already exists');
62
+ });
63
+ });
64
+ });
@@ -0,0 +1,23 @@
1
+ import util from "./_test-util";
2
+
3
+ describe("HTML Emitting", () => {
4
+ it("should generate valid html", () => {
5
+ const parser = new util.Parser("# cool title\nwith a cool paragraph");
6
+ parser.opts.html = true;
7
+
8
+ const output = parser.html();
9
+
10
+ util.expect(output).toBe(
11
+ '<h1 id="cool-title">cool title</h1><p>with a cool paragraph</p>\n'
12
+ );
13
+ });
14
+ it("should be able to include html documents, and not parse", () => {
15
+ util.put("#mdinclude<sample2.html>", "sample1.md");
16
+ util.put("#mdvar<lul>", "sample2.html");
17
+
18
+ const parser = new util.Parser("tests/test-files/sample1.md");
19
+ const output = parser.get();
20
+
21
+ util.expect(output).toBe("#mdvar<lul>\n\n");
22
+ });
23
+ });
@@ -0,0 +1,21 @@
1
+ import util from "./_test-util";
2
+
3
+ describe("Managing blank lines", () => {
4
+ it("should always end with 2 blank lines, even with no input", () => {
5
+ const output = new util.Parser("").get();
6
+ util.expect(output).toBe("\n\n");
7
+ });
8
+
9
+ it("should reduce blank lines to 2", () => {
10
+ const output1 = new util.Parser("\n\n\n\n").get();
11
+ util.expect(output1).toBe("\n\n");
12
+
13
+ const output2 = new util.Parser("\n\n\n\nHello!").get();
14
+ util.expect(output2).toBe("\n\nHello!\n\n");
15
+ });
16
+
17
+ it("should allow words when removing blank lines", () => {
18
+ const output = new util.Parser("hii\n\n\n").get();
19
+ util.expect(output).toBe("hii\n\n");
20
+ });
21
+ });
@@ -0,0 +1,40 @@
1
+ import util from "./_test-util";
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.expect(output).toBe(
13
+ '<blockquote class="one" >\n<p>hello </p></blockquote>'
14
+ );
15
+ });
16
+ it("should add multiple class to blockquotes", () => {
17
+ const parser = new util.Parser("> hello {.one .two}", {
18
+ use_underscore: true,
19
+ html: true,
20
+ });
21
+
22
+ const output = parser.html();
23
+
24
+ util.expect(output).toBe(
25
+ '<blockquote class="one two" >\n<p>hello </p></blockquote>'
26
+ );
27
+ });
28
+ it("should add a single class and id to blockquotes", () => {
29
+ const parser = new util.Parser("> hello {.one #myid}", {
30
+ use_underscore: true,
31
+ html: true,
32
+ });
33
+
34
+ const output = parser.html();
35
+
36
+ util.expect(output).toBe(
37
+ '<blockquote class="one" id="myid">\n<p>hello </p></blockquote>'
38
+ );
39
+ });
40
+ });
@@ -0,0 +1,41 @@
1
+ import util from "./_test-util";
2
+
3
+ describe("Target specific functionality", () => {
4
+ describe("HTML", () => {
5
+ it("Should include `#mdlabel` command, when compiling HTML", () => {
6
+ const parser = new util.Parser("#mdlabel<0,Cool!>");
7
+ const html = parser.get(util.TargetType.HTML);
8
+
9
+ util.expect(html).toBe('<span id="cool"></span>\n\n');
10
+ });
11
+
12
+ it("Should link to sections with #mdref", () => {
13
+ const parser = new util.Parser(
14
+ "#mdlabel<0,Cool!>\n#mdlabel<1,coolzz>\n#mdref<Cool!>"
15
+ );
16
+ const html = parser.get(util.TargetType.HTML);
17
+
18
+ util.expect(html).toBe(
19
+ '<span id="cool"></span>\n<span id="coolzz"></span>\n<a href="#cool">Cool!</a>\n\n'
20
+ );
21
+ });
22
+ });
23
+
24
+ describe("Markdown", () => {
25
+ it("Should not include `#mdlabel` command, when compiling Markdown", () => {
26
+ const parser = new util.Parser("#mdlabel<0,Cool!>");
27
+
28
+ const md = parser.get(util.TargetType.MARKDOWN);
29
+ util.expect(md).toBe("\n\n");
30
+ });
31
+ it("Should include #mdref to title elements in markdown", () => {
32
+ const output = new util.Parser(
33
+ "# Some Title!\n#mdref<Some Title!>"
34
+ ).get();
35
+
36
+ util.expect(output).toBe(
37
+ "# Some Title!\n[Some Title!](#some-title)\n\n"
38
+ );
39
+ });
40
+ });
41
+ });
@@ -0,0 +1,45 @@
1
+ import { MDMError } from "../src/errors";
2
+ import util from "./_test-util";
3
+
4
+ describe("Use variables", () => {
5
+ it("should replace var with the value", () => {
6
+ const output = new util.Parser("#mddef<hi=yo>\n#mdvar<hi>").get();
7
+
8
+ util.expect(output).toBe("\nyo\n\n");
9
+ });
10
+ it("should use variable shorthand", () => {
11
+ const output = new util.Parser("#mddef<hi=yo>\n!<hi>").get();
12
+
13
+ util.expect(output).toBe("\nyo\n\n");
14
+ });
15
+ it("should use variables across files", () => {
16
+ util.put("#mddef<hi=yo>\n#mdinclude<sample2.md>", "sample1.md");
17
+ util.put("!<hi>", "sample2.md");
18
+
19
+ const output = new util.Parser("tests/test-files/sample1.md").get();
20
+
21
+ util.expect(output).toBe("\nyo\n\n");
22
+ });
23
+ it("should throw if undefined variable", () => {
24
+ const parser = new util.Parser("!<yo>");
25
+
26
+ /* should throw an error */
27
+ function get() {
28
+ parser.get();
29
+ }
30
+ util.expect(get).toThrow();
31
+ });
32
+
33
+ it("should preserve whatever comes after", () => {
34
+ const output = new util.Parser("#mddef<hi=yo>\n!<hi>,").get();
35
+ util.expect(output).toBe("\nyo,\n\n");
36
+ });
37
+
38
+ it("should replace underscore with space", () => {
39
+ const output = new util.Parser(
40
+ "#mddef<name=Mr_Sir>\n#mdvar<name>"
41
+ ).get();
42
+
43
+ util.expect(output).toBe("\nMr Sir\n\n");
44
+ });
45
+ });