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.
@@ -3,11 +3,7 @@
3
3
 
4
4
  name: Mocha
5
5
 
6
- on:
7
- push:
8
- branches: [ main ]
9
- pull_request:
10
- branches: [ main ]
6
+ on: [push, pull_request]
11
7
 
12
8
  jobs:
13
9
  build:
@@ -25,6 +21,15 @@ jobs:
25
21
  uses: actions/setup-node@v1
26
22
  with:
27
23
  node-version: ${{ matrix.node-version }}
28
- - run: npm ci
29
- - run: npm run build --if-present
30
- - run: npm test
24
+ - name: yarn install
25
+ uses: borales/actions-yarn@v3.0.0
26
+ with:
27
+ cmd: install # will run `yarn install` command
28
+ - name: yarn build
29
+ uses: borales/actions-yarn@v3.0.0
30
+ with:
31
+ cmd: build # will run `yarn build` command
32
+ - name: yarn test
33
+ uses: borales/actions-yarn@v3.0.0
34
+ with:
35
+ cmd: test # will run `yarn test` command
package/README.md CHANGED
@@ -14,6 +14,7 @@ Currently supports the following features
14
14
  * Automatic Table of Contents generation with `#mdmaketoc`
15
15
  * HTML emitting with custom styling
16
16
  * Easy extention of custom commands, see `src/commands.js` for implementations
17
+ * Usage of templates with the `#mdtemplate<...>` command.
17
18
 
18
19
  ## Usage
19
20
  Download the [latest release](https://github.com/blitzher/markdown-maker/releases), and write your document.
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "opts": {
3
3
  "src": "main.md",
4
- "use-underscore": true
4
+ "use-underscore": true,
5
+ "html": true
5
6
  }
6
- }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdown-maker",
3
- "version": "1.7.11",
3
+ "version": "1.9.1",
4
4
  "description": "",
5
5
  "main": "src/cltool.ts",
6
6
  "bin": {
@@ -13,8 +13,8 @@
13
13
  "node_modules/colors/*",
14
14
  "node_modules/colors./*",
15
15
  "node_modules/marked/*",
16
- "node_modules/open/*",
17
- "build/cltool.js"
16
+ "build/cltool.js",
17
+ "src/templates/*"
18
18
  ],
19
19
  "targets": [
20
20
  "node12-macos-x64",
@@ -26,7 +26,7 @@
26
26
  "test": "mocha",
27
27
  "test:yarn": "mocha",
28
28
  "bundle": "tsc --project tsconfig.json",
29
- "main": "node build/cltool.js document/main.md -o dist/bundle.md",
29
+ "main": "node build/cltool.js document/main.md -o dist/bundle.md --debug",
30
30
  "debug": "node src/cltool.js -db document/main.md -o dist/bundle.md",
31
31
  "build": "npm run bundle && pkg --output bin/mdparse .",
32
32
  "build:yarn": "yarn bundle && pkg --output bin/mdparse .",
@@ -46,18 +46,20 @@
46
46
  "@types/chokidar": "^2.1.3",
47
47
  "@types/colors": "^1.2.1",
48
48
  "@types/node": "^15.6.1",
49
+ "@types/ws": "^8.5.3",
49
50
  "argparse": "^2.0.1",
50
51
  "chokidar": "^3.5.1",
51
52
  "colors": "^1.4.0",
52
53
  "colors.ts": "^1.0.20",
53
54
  "marked": "^2.0.1",
54
- "open": "^8.0.5"
55
+ "require-runtime": "^2.0.0",
56
+ "ws": "^8.8.1"
55
57
  },
56
58
  "devDependencies": {
57
59
  "cloc": "^2.7.0",
58
60
  "mocha": "^8.3.1",
61
+ "pkg": "^4.4.9",
59
62
  "prettier": "^2.3.0",
60
- "typescript": "^4.3.2",
61
- "pkg": "^4.4.9"
63
+ "typescript": "^4.3.2"
62
64
  }
63
65
  }
package/prettierrc.yaml CHANGED
@@ -1,4 +1,4 @@
1
- trailingComma: es5
1
+ trailingComma: all
2
2
  tabWidth: 4
3
3
  singleQuote: true
4
4
  arrowParens: always
package/re-test.js ADDED
@@ -0,0 +1,10 @@
1
+ const s = "hello1, hello2, hello3";
2
+
3
+ const re = /hello(?<digit>\d)/g;
4
+
5
+ let m = s.replace(re, (match, ...args) => {
6
+ console.log(args);
7
+ return "world";
8
+ });
9
+
10
+ console.log({ s, m });
package/src/cltool.ts CHANGED
@@ -2,8 +2,8 @@ const fs = require("fs"); /* for handling reading of files */
2
2
  const path = require("path"); /* for handling file paths */
3
3
 
4
4
  import Colors = require("colors.ts"); /* for adding colours to strings */
5
- import { symlinkSync } from "fs";
6
5
  import Parser from "./parse";
6
+ import { WebSocketServer } from "ws";
7
7
 
8
8
  Colors.enable();
9
9
  const { ArgumentParser } = require("argparse"); /* for parsing clargs */
@@ -12,7 +12,7 @@ const choki = require("chokidar");
12
12
 
13
13
  export const argParser = new ArgumentParser({
14
14
  description: "Markdown bundler, with extra options",
15
- prog: process.argv[0].split(path.sep).pop(),
15
+ prog: "mdparse",
16
16
  });
17
17
 
18
18
  const configFileName = ".mdmconfig.json";
@@ -26,7 +26,7 @@ argParser.add_argument("-v", "--verbose", {
26
26
  action: "store_true",
27
27
  help: "enable verbose output",
28
28
  });
29
- argParser.add_argument("-db", "--debug", {
29
+ argParser.add_argument("-D", "--debug", {
30
30
  action: "store_true",
31
31
  help: "enable debugging information",
32
32
  });
@@ -47,40 +47,50 @@ argParser.add_argument("-w", "--watch", {
47
47
  action: "store_true",
48
48
  help: "recompile after a change in target target file or directory.",
49
49
  });
50
- argParser.add_argument("-uu", "--use-underscore", {
50
+ argParser.add_argument("-u", "--use-underscore", {
51
51
  action: "store_true",
52
52
  help: "set the parser to use '_' as seperator in ids for Table of Content. If the links in the table does not work, this is likely to be the issue.",
53
53
  });
54
- argParser.add_argument("--toc-level", {
54
+ argParser.add_argument("-t", "--toc-level", {
55
55
  help: "the section level of the table of contents, by default is 3",
56
56
  default: 3,
57
57
  type: "int",
58
58
  });
59
- argParser.add_argument("--html", {
59
+ argParser.add_argument("-H", "--html", {
60
60
  action: "store_true",
61
61
  help: "compile HTML from the parsed markdown",
62
62
  });
63
- argParser.add_argument("--allow-undef", "-au", {
63
+ argParser.add_argument("--allow-undefined", "-A", {
64
64
  action: "store_true",
65
- help: "allow undefined variables. Mostly useful for typing inline html tags, and other non-strictly markdown related uses",
65
+ help: "allow the use of the \"<thing>\" syntax, without raising an error when 'thing' is not a variable. Mostly useful when writing inline html tags, and other non-strictly markdown related uses",
66
66
  });
67
67
  //#endregion
68
68
 
69
69
  function main() {
70
- // var server: refreshServer | undefined;
71
- let clargs;
70
+ let clargs, fileargs;
71
+ let server: WebSocketServer | undefined;
72
+
73
+ /* Read config file or parse args from cmd-line */
72
74
  if (fs.existsSync(configFileName)) {
73
- let data = JSON.parse(fs.readFileSync(configFileName)).opts;
75
+ let data: { [key: string]: string | boolean | number } = JSON.parse(fs.readFileSync(configFileName)).opts;
74
76
 
75
- let args = [];
77
+ let args: (string | number)[] = [];
76
78
  Object.entries(data).forEach(([key, value]) => {
77
- if (key != "src") args.push("--" + key);
78
- if (typeof value != "boolean") args.push(value);
79
+ if (key != "src" && value !== false) {
80
+ args.push("--" + key);
81
+ }
82
+ if (typeof value != "boolean") {
83
+ args.push(value);
84
+ }
79
85
  });
80
- args.push(data.src);
81
86
 
82
- argParser.parse_args(args);
83
- } else clargs = argParser.parse_args();
87
+ /* We skip [0] and [1], as it is the binary and source file, even when compiled*/
88
+ for (let i = 2; i < process.argv.length; i++) args.push(process.argv[i]);
89
+
90
+ clargs = argParser.parse_args(args);
91
+ } else {
92
+ clargs = argParser.parse_args();
93
+ }
84
94
 
85
95
  /* helper method for calling parser */
86
96
  const compile = (source, output, cb?) => {
@@ -109,7 +119,10 @@ function main() {
109
119
 
110
120
  try {
111
121
  compile(clargs.src, clargs.output, () => {
112
- // if (server.refresh) server.refresh();
122
+ /* after compile, send refresh command to clients */
123
+ server.clients.forEach((client) => {
124
+ if (client.OPEN) client.send("refresh");
125
+ });
113
126
  });
114
127
  } catch (e) {
115
128
  console.log(e.message);
@@ -123,16 +136,16 @@ function main() {
123
136
  clargs.src = path.join(clargs.src, clargs.entry);
124
137
  }
125
138
 
126
- const srcDirName = path.dirname(clargs.src);
127
-
128
139
  if (clargs.debug) console.dir(clargs);
129
140
 
141
+ /* compile once */
130
142
  if (!clargs.watch) compile(clargs.src, clargs.output);
131
143
 
144
+ /* watch the folder and recompile on change */
132
145
  if (clargs.watch) {
133
- /* watch the folder of entry */
134
- // server = wsServer();
146
+ const srcDirName = path.dirname(clargs.src);
135
147
  console.log(`Watching ${srcDirName} for changes...`.yellow);
148
+ server = new WebSocketServer({ port: 7788 });
136
149
 
137
150
  const _watcher = choki.watch(srcDirName).on("all", watcher);
138
151
  try {
package/src/commands.ts CHANGED
@@ -1,35 +1,48 @@
1
1
  import * as path from "path";
2
2
  import Parser from "./parse";
3
+ import * as fs from "fs";
4
+ import templates, { new_template } from "./templates";
5
+ import requireRuntime from "require-runtime";
6
+
7
+ export class MDMError extends Error {
8
+ match: RegExpMatchArray;
9
+ constructor(message: string, match: RegExpMatchArray) {
10
+ super(message);
11
+ this.name = "MDMError";
12
+ this.match = match;
13
+ }
14
+ }
3
15
 
4
- const commands = {
16
+ export const commands: {
17
+ preparse: Command[];
18
+ parse: Command[];
19
+ postparse: Command[];
20
+ } = {
5
21
  preparse: [],
6
22
  parse: [],
7
23
  postparse: [],
8
24
  };
9
25
 
10
- const CommandType = {
11
- PREPARSE: 0,
12
- PARSE: 1,
13
- POSTPARSE: 2,
14
- };
26
+ export enum CommandType {
27
+ PREPARSE,
28
+ PARSE,
29
+ POSTPARSE,
30
+ }
15
31
 
16
- enum TargetType {
32
+ export enum TargetType {
17
33
  HTML,
18
34
  MARKDOWN,
19
35
  }
20
36
 
21
37
  export class Command {
22
- type: number;
23
- validator: (token: string, parser: Parser) => boolean | RegExpMatchArray;
24
- acter: (token: string, parser: Parser) => string | void;
38
+ validator: RegExp;
39
+ acter: (match: RegExpMatchArray, parser: Parser) => string | void;
40
+ type: CommandType;
25
41
 
26
42
  constructor(
27
- type,
28
- validator: (
29
- token: string,
30
- parser: Parser,
31
- ) => boolean | RegExpMatchArray,
32
- acter: (token: string, parser: Parser) => string | void,
43
+ validator: RegExp,
44
+ acter: (match: RegExpMatchArray, parser: Parser) => string | void,
45
+ type: CommandType,
33
46
  ) {
34
47
  this.type = type;
35
48
  this.validator = validator;
@@ -49,132 +62,191 @@ export class Command {
49
62
  }
50
63
  }
51
64
 
52
- valid(token, parser) {
53
- return this.validator(token, parser);
54
- }
55
-
56
- act(token, parser) {
57
- return this.acter(token, parser);
65
+ act(match, parser) {
66
+ return this.acter(match, parser);
58
67
  }
59
68
  }
60
69
 
61
70
  /* variable shorthand */
62
71
  new Command(
72
+ /(\s|^)<(.+)>/,
73
+ (match, parser) => `${match[1]}#mdvar<${match[2]}>`,
63
74
  CommandType.PREPARSE,
64
- (t, p) => t.match(/(?:\s|^)<\w+>/),
65
- (t, p) => `#mdvar` + t,
66
75
  );
67
76
 
68
77
  /* mddef */
69
78
  new Command(
70
- CommandType.PARSE,
71
- (t, p) => t.match(/^#mddef<(\w+)=(\w+)>/),
72
- (t, p) => {
73
- const m = t.match(/^#mddef<(\w+)=(\w+)>/);
74
- p.opts.defs[m[1]] = m[2];
79
+ /#mddef< *(.+?) *= *(.+?) *>/ /* first .+ is lazy so as to not match following spaces */,
80
+ (match, parser) => {
81
+ parser.opts.defs[match[1]] = match[2].replace("_", " ");
75
82
  },
83
+ CommandType.PARSE,
76
84
  );
77
85
 
78
86
  /* mdvar */
79
87
  new Command(
80
- CommandType.PARSE,
81
- (t, p) => t.match(/^#mdvar<(\w+)>/) || t.match(/^<(\w+)>/),
82
- (t, p) => {
83
- const match = t.match(/#mdvar<(\w+)>/);
84
- let value = p.opts.defs[match[1]];
85
- if (!value && !p.opts.allow_undef)
88
+ /#mdvar<(.+?)>/,
89
+ (match, parser) => {
90
+ let value = parser.opts.defs[match[1]];
91
+ if (!value && !parser.opts.allow_undefined)
86
92
  throw new Error(`Undefined variable: ${match[1]}`);
87
- value = value || `<${match[1]}>`;
88
- return t.replace(match[0], value.replace("_", " "));
93
+ return (value = value || `<${match[1]}>`);
89
94
  },
95
+ CommandType.PARSE,
90
96
  );
91
97
 
92
98
  /** mdinclude */
93
99
  new Command(
94
- CommandType.PARSE,
95
- (t, p) => t.match(/^#mdinclude<([\w.\/-]+)(?:[,\s]+([\w]+))?>/),
96
- (t, p) => {
100
+ /#mdinclude<([\w.\/-]+)(?:[,\s]+([\w]+))?>/,
101
+ (match, parser) => {
97
102
  /* increase the current recursive depth */
98
- p.opts.depth++;
103
+ parser.opts.depth++;
99
104
 
100
- if (p.opts.depth > p.opts.max_depth) {
105
+ if (parser.opts.depth > parser.opts.max_depth) {
101
106
  throw new Error("max depth exceeded!");
102
107
  }
103
108
 
104
109
  /* get the matching group */
105
- const match = t.match(/^#mdinclude<([\w.\/-]+)(?:[,\s]+([\w]+))?>/);
106
-
107
110
  const [_, name, condition] = match;
108
111
 
109
112
  /* implement conditional imports */
110
- if (condition && !p.opts.args.includes(condition)) return;
113
+ if (condition && !parser.opts.args.includes(condition)) return;
111
114
 
112
- const recursiveParser = new Parser(path.join(p.wd, name), p.opts, {
113
- parent: p,
114
- });
115
+ const recursiveParser = new Parser(
116
+ path.join(parser.wd, name),
117
+ parser.opts,
118
+ {
119
+ parent: parser,
120
+ },
121
+ );
115
122
 
116
123
  /* keep the options the same */
117
- recursiveParser.opts = p.opts;
118
- recursiveParser.parent = p;
124
+ recursiveParser.opts = parser.opts;
125
+ recursiveParser.parent = parser;
119
126
 
120
127
  const fileType = path.extname(recursiveParser.file);
121
128
 
122
129
  const blob =
123
130
  fileType === ".md"
124
- ? recursiveParser.get(p.opts.targetType)
131
+ ? recursiveParser.get(parser.opts.targetType)
125
132
  : recursiveParser.raw;
126
133
 
127
- p.opts.depth--;
134
+ parser.opts.depth--;
128
135
  return blob;
129
136
  },
137
+ CommandType.PARSE,
130
138
  );
131
139
 
140
+ /* mdlabel */
132
141
  new Command(
133
- CommandType.PREPARSE,
134
- (t, p) => t.match(/#mdlabel<(\d+),([\w\W]+)>/),
135
- (t, p) => {
136
- if (p.opts.targetType !== TargetType.HTML) return;
142
+ /#mdlabel<(\d+),\s?(.+)>/,
143
+ (match, parser) => {
144
+ if (parser.opts.targetType !== TargetType.HTML) return "";
137
145
 
138
- const match = t.match(/#mdlabel<([\d]+),([\w\W]+)>/);
139
146
  const level = Number.parseInt(match[1]);
140
147
  const title = match[2];
141
- const link = p.titleId(title);
142
- p.opts.secs.push({ level, title });
148
+ const link = parser.titleId(title);
149
+ parser.opts.secs.push({ level, title });
143
150
  return `<span id="${link}"></span>`;
144
151
  },
152
+ CommandType.PREPARSE,
145
153
  );
146
154
 
147
155
  /* mdref */
148
156
  new Command(
149
- CommandType.PARSE,
150
- (t, p) => t.match(/#mdref<([\w\W]+)>/),
157
+ /#mdref<(.+)>/,
151
158
 
152
- (t, p) => {
153
- const match = t.match(/#mdref<([\w\W]+)>/);
154
-
155
- for (let i = 0; i < p.opts.secs.length; i++) {
156
- let { title } = p.opts.secs[i];
159
+ (match, parser) => {
160
+ for (let i = 0; i < parser.opts.secs.length; i++) {
161
+ let { title } = parser.opts.secs[i];
157
162
  if (title === match[1]) break;
158
163
 
159
- if (i === p.opts.secs.length - 1)
164
+ if (i === parser.opts.secs.length - 1)
160
165
  throw new Error(
161
166
  `Reference to [${match[1]}] could not be resolved!`,
162
167
  );
163
168
  }
164
169
 
165
170
  match[1] = match[1].replace("_", " ");
166
- const link = p.titleId(match[1]);
167
- if (p.opts.targetType === TargetType.HTML)
171
+ const link = parser.titleId(match[1]);
172
+ if (parser.opts.targetType === TargetType.HTML)
168
173
  return `<a href="#${link}">${match[1]}</a>`;
169
- else if (p.opts.targetType === TargetType.MARKDOWN)
174
+ else if (parser.opts.targetType === TargetType.MARKDOWN)
170
175
  return `[${match[1]}](#${link})`;
171
176
  },
177
+ CommandType.PARSE,
178
+ );
179
+
180
+ /* mdtemplate */
181
+ new Command(
182
+ /#mdtemplate<([\w\W]+)>/,
183
+ (match, parser) => {
184
+ const template = match[1];
185
+ const replacement = templates[template];
186
+
187
+ if (replacement !== undefined) {
188
+ return replacement;
189
+ } else {
190
+ throw new MDMError(`Template \"${template}\" not found!`, match);
191
+ }
192
+ },
193
+ CommandType.PARSE,
172
194
  );
173
195
 
174
196
  new Command(
197
+ /#mdmaketoc(?:<>)?/,
198
+ (match, parser) => parser.gen_toc(),
175
199
  CommandType.POSTPARSE,
176
- (t, p) => t.match(/#mdmaketoc/),
177
- (t, p) => p.gen_toc(),
178
200
  );
179
201
 
180
- module.exports = commands;
202
+ export function load_extensions(parser: Parser) {
203
+ /* global extention */
204
+ const global_extensions_path = path.join(process.cwd(), "extensions.js");
205
+ if (fs.existsSync(global_extensions_path)) {
206
+ const extensions = requireRuntime(global_extensions_path);
207
+ extensions.main(new_template, new_command);
208
+
209
+ if (parser.opts.verbose)
210
+ console.log(
211
+ `Loaded global extensions from ${global_extensions_path}`
212
+ .yellow,
213
+ );
214
+ } else if (parser.opts.debug) {
215
+ console.log(
216
+ `No global extensions found at ${global_extensions_path}`.red,
217
+ );
218
+ }
219
+
220
+ /* project extention */
221
+ const project_extensions_path = path.join(parser.wd_full, "extensions.js");
222
+ if (fs.existsSync(project_extensions_path)) {
223
+ const extensions = requireRuntime(project_extensions_path);
224
+ extensions.main(new_template, new_command);
225
+
226
+ if (parser.opts.verbose)
227
+ console.log(
228
+ `Loaded project extensions from ${project_extensions_path}`
229
+ .yellow,
230
+ );
231
+ } else if (parser.opts.debug) {
232
+ console.log(
233
+ `No project extensions found at ${project_extensions_path}!`.red,
234
+ );
235
+ }
236
+ }
237
+
238
+ /**
239
+ *
240
+ * @param regex The regex to match the command
241
+ * @param acter The function called when a match is found. Takes two arguments, `match` and `parser`. `match` is the result of the regex match, and `parser` is the parser instance. The function should return the replacement string.
242
+ * @param type When the command should be run. Can be `CommandType.PREPARSE`, `CommandType.PARSE`, or `CommandType.POSTPARSE`. Defaults to `CommandType.PARSE`.
243
+ */
244
+ export function new_command(
245
+ regex: RegExp,
246
+ acter: (match: RegExpMatchArray, parser: Parser) => string,
247
+ type?: CommandType,
248
+ ) {
249
+ new Command(regex, acter, type || CommandType.PARSE);
250
+ }
251
+
252
+ export default { commands, load_extensions };