@rokelamen/md2html 0.1.4 → 0.2.0

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/README.md CHANGED
@@ -1,18 +1,50 @@
1
1
  # md2html
2
2
 
3
- A simple markdown-html conventer written in Typescript.
3
+ A simple markdown-html converter written in Typescript.
4
+
5
+ The style relies on browser pure style, inspired by [`txti`](https://txti.es/).
4
6
 
5
7
  ## Goal
6
8
 
7
9
  > I create this project for learning TS and node dev, not for the purpose of building another better markdown parse engine.
8
10
 
9
- Markdown syntax was first promoted with the release of `markdown.pl` by John Gruber. This leads to Markdown has no explicit definition, which means how markdown is parsed to HTML highly depends on the implementation of the tool. *And I choosed a simplest way(line-by-line parsing)*
11
+ Markdown syntax was first promoted with the release of `markdown.pl` by John Gruber. This leads to Markdown has no explicit definition, which means how markdown is parsed to HTML highly depends on the implementation of the tool. *And I choose a simplest way(line-by-line parsing)*
10
12
 
11
13
  To stay as close as possible to the 'Standard Markdown', [CommonMark](https://commonmark.org/) is a great reference.
12
14
 
15
+ ## Requirement
16
+
17
+ [Node](https://nodejs.org/) environment(>= v12.0.0) is necessary.
18
+
19
+ ## Installation
20
+
21
+ Using npm:
22
+
23
+ ```sh
24
+ npm i -g @rokelamen/md2html
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```sh
30
+ md2html [options] [input]
31
+ ```
32
+
33
+ 1. Parse from/to stdio
34
+
35
+ ```sh
36
+ md2html "# Markdown content" > index.html
37
+ ```
38
+
39
+ 2. Parse from/to file
40
+
41
+ ```sh
42
+ md2html -f input.md -o index.html
43
+ ```
44
+
13
45
  ## Development Log
14
46
 
15
47
  Why I choose to use [`rollup`](https://rollupjs.org/)?
16
48
 
17
- A: Every time I `import` a module, I have to add extension to the module file and it is probably a `.js` ranther than `.ts`. It's wired that I must `import` a future JS file. So I decided to use a build tool(`rollup` of course) to pack all files together, which eliminates all `import` statements.
49
+ A: Every time I `import` a module, I have to add extension to the module file and it is probably a `.js` rather than `.ts`. It's wired that I must `import` a future JS file. So I decided to use a build tool(`rollup` of course) to pack all files together, which eliminates all `import` statements.
18
50
 
package/bin/cli.cjs CHANGED
@@ -4338,6 +4338,7 @@ const {
4338
4338
 
4339
4339
  /* For markdown line pattern pair */
4340
4340
  const headingReg = /^\s*(#{1,6})(?:\s+|$)(.*)$/;
4341
+ const delimiterReg = /^\s*((?:\*+\s*){3,}|(?:-+\s*){3,}|(?:_+\s*){3,})$/;
4341
4342
  const quoteReg = /^>\s*(.*)$/;
4342
4343
  const ulistReg = /^\s*([-+*])(?:\s+|$)(.*)$/;
4343
4344
  const olistReg = /^\s*(\d+)(.|\))(?:\s+|$)(.*)$/;
@@ -4359,7 +4360,65 @@ const italicReg = /([*_])([^*_]+)\1/g;
4359
4360
  * This function is intended to remove all such representations.
4360
4361
  */
4361
4362
  function escapeHtml(content) {
4362
- return content;
4363
+ return content
4364
+ .replace(/&/g, '&')
4365
+ .replace(/</g, '&lt;')
4366
+ .replace(/>/g, '&gt;')
4367
+ .replace(/"/g, '&quot;')
4368
+ .replace(/'/g, '&#39;');
4369
+ }
4370
+ const DEFAULT_STYLE = `
4371
+ body {
4372
+ margin: 0 auto;
4373
+ max-width: 650px;
4374
+ line-height: 1.6;
4375
+ font-size: 18px;
4376
+ color: #444;
4377
+ padding: 50px;
4378
+ }
4379
+ h1, h2, h3 {
4380
+ line-height: 1.2;
4381
+ }
4382
+ pre {
4383
+ background-color: #f8f8f8;
4384
+ padding: 18px;
4385
+ border-radius: 5px;
4386
+ }
4387
+ code {
4388
+ padding: 3px 5px;
4389
+ border-radius: 5px;
4390
+ background-color: #f4f4f4;
4391
+ font-size: 85%;
4392
+ }
4393
+ pre code {
4394
+ background-color: transparent;
4395
+ }
4396
+ blockquote {
4397
+ margin: 0;
4398
+ border-left: 5px solid #dfe2e5;
4399
+ padding: 0 18px;
4400
+ }
4401
+ blockquote > * {
4402
+ margin: 0;
4403
+ padding: 0;
4404
+ color: #888;
4405
+ }
4406
+ `;
4407
+ function wrapHtmlTemplate(content) {
4408
+ return `<!DOCTYPE html>
4409
+ <html>
4410
+ <head>
4411
+ <meta charset="UTF-8">
4412
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4413
+ <title>Markdown preview</title>
4414
+ <style>
4415
+ ${DEFAULT_STYLE.trim()}
4416
+ </style>
4417
+ </head>
4418
+ <body>
4419
+ ${content.trim()}
4420
+ </body>
4421
+ </html>`;
4363
4422
  }
4364
4423
 
4365
4424
  /* traverse markdown content elements and wrap text with tags at proper positions. */
@@ -4368,35 +4427,38 @@ function renderToHtml(mdElements) {
4368
4427
  for (const element of mdElements) {
4369
4428
  const type = element.type;
4370
4429
  switch (type) {
4371
- case "text":
4430
+ case 'text':
4372
4431
  result += `<p>${inlineParse(element.content)}</p>\n`;
4373
4432
  break;
4374
- case "heading":
4433
+ case 'heading':
4375
4434
  result += `<h${element.level}>${inlineParse(element.content)}</h${element.level}>\n`;
4376
4435
  break;
4377
- case "quote":
4378
- result += `<quote>${inlineParse(element.content)}</quote>\n`;
4436
+ case 'delimiter':
4437
+ result += `<hr>\n`;
4438
+ break;
4439
+ case 'quote':
4440
+ result += `<blockquote><p>${inlineParse(element.content)}</p></blockquote>\n`;
4379
4441
  break;
4380
4442
  case 'ulist':
4381
4443
  result += '<ul>\n' +
4382
4444
  element.items
4383
- .map(item => ` <li>${inlineParse(item)}</li>`)
4445
+ .map(item => `<li>${inlineParse(item)}</li>`)
4384
4446
  .join('\n') +
4385
4447
  '\n</ul>\n';
4386
4448
  break;
4387
4449
  case 'olist':
4388
4450
  result += `<ol start="${element.start}">\n` +
4389
4451
  element.items
4390
- .map(item => ` <li>${inlineParse(item)}</li>`)
4452
+ .map(item => `<li>${inlineParse(item)}</li>`)
4391
4453
  .join('\n') +
4392
4454
  '\n</ol>\n';
4393
4455
  break;
4394
- case "code":
4395
- result += '<code>\n' +
4456
+ case 'code':
4457
+ result += '<pre>\n' +
4396
4458
  element.items
4397
- .map(item => ` <p>${escapeHtml(item)}</p>`)
4459
+ .map(item => `<code>${escapeHtml(item)}</code>`)
4398
4460
  .join('\n') +
4399
- '\n</code>\n';
4461
+ '\n</pre>\n';
4400
4462
  break;
4401
4463
  }
4402
4464
  }
@@ -4414,7 +4476,7 @@ function inlineParse(content) {
4414
4476
  };
4415
4477
  // 1. code
4416
4478
  content = content
4417
- .replace(inlineCodeReg, (_, __, code) => stash(`<code>${code}</code>`));
4479
+ .replace(inlineCodeReg, (_, __, code) => stash(code));
4418
4480
  // 2. link and emphasis
4419
4481
  content = content
4420
4482
  .replace(imgReg, '<img src="$2" alt="$1">')
@@ -4423,7 +4485,7 @@ function inlineParse(content) {
4423
4485
  .replace(boldReg, '<strong>$2</strong>')
4424
4486
  .replace(italicReg, '<em>$2</em>');
4425
4487
  // 3. restore codes
4426
- content = content.replace(/\u0000(\d+)\u0000/g, (_, i) => escapeHtml(placeholders[i]));
4488
+ content = content.replace(/\u0000(\d+)\u0000/g, (_, i) => `<code>${escapeHtml(placeholders[i])}</code>`);
4427
4489
  return content;
4428
4490
  }
4429
4491
 
@@ -4452,7 +4514,7 @@ function inlineParse(content) {
4452
4514
  * is one paragraph as well.
4453
4515
  */
4454
4516
  /* The main parse logic */
4455
- function parse(markdown) {
4517
+ function parse(markdown, hasStyle) {
4456
4518
  /* Split markdown content to many lines */
4457
4519
  const crlfReg = /\r?\n/;
4458
4520
  const lines = markdown.split(crlfReg);
@@ -4460,7 +4522,7 @@ function parse(markdown) {
4460
4522
  const mdElements = parseToElements(lines);
4461
4523
  // console.log(mdElements);
4462
4524
  const html = renderToHtml(mdElements);
4463
- return html;
4525
+ return hasStyle ? wrapHtmlTemplate(html) : html;
4464
4526
  }
4465
4527
  /**
4466
4528
  * Traverse lines to turn to markdown elements with different well-designed structures
@@ -4491,6 +4553,12 @@ function parseToElements(lines) {
4491
4553
  flush();
4492
4554
  continue;
4493
4555
  }
4556
+ // Delimiter
4557
+ if (delimiterReg.test(line)) {
4558
+ flush();
4559
+ mdElements.push({ type: 'delimiter' });
4560
+ continue;
4561
+ }
4494
4562
  // Headings
4495
4563
  const headingM = line.match(headingReg);
4496
4564
  if (headingM) {
@@ -4586,8 +4654,8 @@ function parseToElements(lines) {
4586
4654
  }
4587
4655
 
4588
4656
  var name = "@rokelamen/md2html";
4589
- var version = "0.1.4";
4590
- var description = "A simple tool to convert markdown content to html";
4657
+ var version = "0.2.0";
4658
+ var description = "A simple tool to convert Markdown content to HTML";
4591
4659
 
4592
4660
  /* Command-line tool logic */
4593
4661
  function command() {
@@ -4600,6 +4668,7 @@ function command() {
4600
4668
  program
4601
4669
  .option('-f, --file <path>', 'source file path')
4602
4670
  .option('-o, --output <path>', 'output file path')
4671
+ .option('-s, --style', 'output full html struct with style')
4603
4672
  .argument('[input]', 'input content');
4604
4673
  /* Parse the cli options */
4605
4674
  program.parse(process.argv);
@@ -4625,7 +4694,7 @@ function command() {
4625
4694
  }
4626
4695
  })()
4627
4696
  : input;
4628
- const html = parse(content);
4697
+ const html = parse(content, options.style);
4629
4698
  if (typeof options.output === 'string') {
4630
4699
  fs__namespace.writeFileSync(options.output, html, 'utf-8');
4631
4700
  return;
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /* For markdown line pattern pair */
2
2
  const headingReg = /^\s*(#{1,6})(?:\s+|$)(.*)$/;
3
+ const delimiterReg = /^\s*((?:\*+\s*){3,}|(?:-+\s*){3,}|(?:_+\s*){3,})$/;
3
4
  const quoteReg = /^>\s*(.*)$/;
4
5
  const ulistReg = /^\s*([-+*])(?:\s+|$)(.*)$/;
5
6
  const olistReg = /^\s*(\d+)(.|\))(?:\s+|$)(.*)$/;
@@ -21,7 +22,65 @@ const italicReg = /([*_])([^*_]+)\1/g;
21
22
  * This function is intended to remove all such representations.
22
23
  */
23
24
  function escapeHtml(content) {
24
- return content;
25
+ return content
26
+ .replace(/&/g, '&amp;')
27
+ .replace(/</g, '&lt;')
28
+ .replace(/>/g, '&gt;')
29
+ .replace(/"/g, '&quot;')
30
+ .replace(/'/g, '&#39;');
31
+ }
32
+ const DEFAULT_STYLE = `
33
+ body {
34
+ margin: 0 auto;
35
+ max-width: 650px;
36
+ line-height: 1.6;
37
+ font-size: 18px;
38
+ color: #444;
39
+ padding: 50px;
40
+ }
41
+ h1, h2, h3 {
42
+ line-height: 1.2;
43
+ }
44
+ pre {
45
+ background-color: #f8f8f8;
46
+ padding: 18px;
47
+ border-radius: 5px;
48
+ }
49
+ code {
50
+ padding: 3px 5px;
51
+ border-radius: 5px;
52
+ background-color: #f4f4f4;
53
+ font-size: 85%;
54
+ }
55
+ pre code {
56
+ background-color: transparent;
57
+ }
58
+ blockquote {
59
+ margin: 0;
60
+ border-left: 5px solid #dfe2e5;
61
+ padding: 0 18px;
62
+ }
63
+ blockquote > * {
64
+ margin: 0;
65
+ padding: 0;
66
+ color: #888;
67
+ }
68
+ `;
69
+ function wrapHtmlTemplate(content) {
70
+ return `<!DOCTYPE html>
71
+ <html>
72
+ <head>
73
+ <meta charset="UTF-8">
74
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
75
+ <title>Markdown preview</title>
76
+ <style>
77
+ ${DEFAULT_STYLE.trim()}
78
+ </style>
79
+ </head>
80
+ <body>
81
+ ${content.trim()}
82
+ </body>
83
+ </html>`;
25
84
  }
26
85
 
27
86
  /* traverse markdown content elements and wrap text with tags at proper positions. */
@@ -30,35 +89,38 @@ function renderToHtml(mdElements) {
30
89
  for (const element of mdElements) {
31
90
  const type = element.type;
32
91
  switch (type) {
33
- case "text":
92
+ case 'text':
34
93
  result += `<p>${inlineParse(element.content)}</p>\n`;
35
94
  break;
36
- case "heading":
95
+ case 'heading':
37
96
  result += `<h${element.level}>${inlineParse(element.content)}</h${element.level}>\n`;
38
97
  break;
39
- case "quote":
40
- result += `<quote>${inlineParse(element.content)}</quote>\n`;
98
+ case 'delimiter':
99
+ result += `<hr>\n`;
100
+ break;
101
+ case 'quote':
102
+ result += `<blockquote><p>${inlineParse(element.content)}</p></blockquote>\n`;
41
103
  break;
42
104
  case 'ulist':
43
105
  result += '<ul>\n' +
44
106
  element.items
45
- .map(item => ` <li>${inlineParse(item)}</li>`)
107
+ .map(item => `<li>${inlineParse(item)}</li>`)
46
108
  .join('\n') +
47
109
  '\n</ul>\n';
48
110
  break;
49
111
  case 'olist':
50
112
  result += `<ol start="${element.start}">\n` +
51
113
  element.items
52
- .map(item => ` <li>${inlineParse(item)}</li>`)
114
+ .map(item => `<li>${inlineParse(item)}</li>`)
53
115
  .join('\n') +
54
116
  '\n</ol>\n';
55
117
  break;
56
- case "code":
57
- result += '<code>\n' +
118
+ case 'code':
119
+ result += '<pre>\n' +
58
120
  element.items
59
- .map(item => ` <p>${escapeHtml(item)}</p>`)
121
+ .map(item => `<code>${escapeHtml(item)}</code>`)
60
122
  .join('\n') +
61
- '\n</code>\n';
123
+ '\n</pre>\n';
62
124
  break;
63
125
  }
64
126
  }
@@ -76,7 +138,7 @@ function inlineParse(content) {
76
138
  };
77
139
  // 1. code
78
140
  content = content
79
- .replace(inlineCodeReg, (_, __, code) => stash(`<code>${code}</code>`));
141
+ .replace(inlineCodeReg, (_, __, code) => stash(code));
80
142
  // 2. link and emphasis
81
143
  content = content
82
144
  .replace(imgReg, '<img src="$2" alt="$1">')
@@ -85,7 +147,7 @@ function inlineParse(content) {
85
147
  .replace(boldReg, '<strong>$2</strong>')
86
148
  .replace(italicReg, '<em>$2</em>');
87
149
  // 3. restore codes
88
- content = content.replace(/\u0000(\d+)\u0000/g, (_, i) => escapeHtml(placeholders[i]));
150
+ content = content.replace(/\u0000(\d+)\u0000/g, (_, i) => `<code>${escapeHtml(placeholders[i])}</code>`);
89
151
  return content;
90
152
  }
91
153
 
@@ -114,7 +176,7 @@ function inlineParse(content) {
114
176
  * is one paragraph as well.
115
177
  */
116
178
  /* The main parse logic */
117
- function parse(markdown) {
179
+ function parse(markdown, hasStyle) {
118
180
  /* Split markdown content to many lines */
119
181
  const crlfReg = /\r?\n/;
120
182
  const lines = markdown.split(crlfReg);
@@ -122,7 +184,7 @@ function parse(markdown) {
122
184
  const mdElements = parseToElements(lines);
123
185
  // console.log(mdElements);
124
186
  const html = renderToHtml(mdElements);
125
- return html;
187
+ return hasStyle ? wrapHtmlTemplate(html) : html;
126
188
  }
127
189
  /**
128
190
  * Traverse lines to turn to markdown elements with different well-designed structures
@@ -153,6 +215,12 @@ function parseToElements(lines) {
153
215
  flush();
154
216
  continue;
155
217
  }
218
+ // Delimiter
219
+ if (delimiterReg.test(line)) {
220
+ flush();
221
+ mdElements.push({ type: 'delimiter' });
222
+ continue;
223
+ }
156
224
  // Headings
157
225
  const headingM = line.match(headingReg);
158
226
  if (headingM) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@rokelamen/md2html",
3
3
  "type": "module",
4
- "version": "0.1.4",
5
- "description": "A simple tool to convert markdown content to html",
4
+ "version": "0.2.0",
5
+ "description": "A simple tool to convert Markdown content to HTML",
6
6
  "author": "rokelamen <rogerskelamen@gmail.com>",
7
7
  "license": "MIT",
8
8
  "main": "./dist/index.js",