markdown-maker 1.10.2 → 1.10.3

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/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
+ });