@peaceroad/markdown-it-renderer-fence 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 k_taka
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # p7d-markdown-it-renderer-fence
2
+
3
+ In code blocks, the `<samp>` tag is used with the language keywords `samp`, `shell`, and `console`.
4
+
5
+ To add specific styles to code blocks and display line numbers in code blocks, enclose each line in a span element and set CSS.
6
+
7
+ ## Use
8
+
9
+ It is assumed that you will use highlight.js and markdown-it-attrs together. It will probably work without them though.
10
+
11
+ ```js
12
+ import mdit from 'markdown-it'
13
+ import mditAttrs from 'markdown-it-attrs'
14
+ import highlightjs from 'highlihgtjs'
15
+ import mditRendererFence from '@peaceroad/markdown-it-renderer-fence'
16
+
17
+ const md = mdit({
18
+ langPrefix: 'language-',
19
+ highlight: (str, lang) => {
20
+ if (lang && highlightjs.getLanguage(lang)) {
21
+ try {
22
+ return highlightjs.highlight(str, { language: lang }).value
23
+ } catch (__) {}
24
+ }
25
+ return ''
26
+ }).use(mditAttrs).use(mditRendererFence)
27
+
28
+
29
+ const htmlCont = md.render('...')
30
+ ```
31
+
32
+ It is also intended to be used in conjunction with @peaceroad/markdown-it-figure-with-p-caption.
33
+
34
+ ## Code block to samp block
35
+
36
+ ~~~
37
+ [Markdown]
38
+ ```samp
39
+ $ pwd
40
+ /home/User
41
+ ```
42
+ [HTML]
43
+ <pre><samp>$ pwd
44
+ /home/User
45
+ </samp></pre>
46
+
47
+
48
+ [Markdown]
49
+ ```shell
50
+ $ pwd
51
+ /home/User
52
+ ```
53
+ [HTML]
54
+ <pre><samp class="language-shell"><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">pwd</span></span>
55
+ /home/User
56
+ </samp></pre>
57
+
58
+
59
+ [Markdown]
60
+ ```console
61
+ $ pwd
62
+ /home/User
63
+ ```
64
+ [HTML]
65
+ <pre><samp class="language-console"><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">pwd</span></span>
66
+ /home/User
67
+ </samp></pre>
68
+ ~~~
69
+
70
+
71
+ ## Add span elements to display line number, and style attribute.
72
+
73
+ Add `start` or `data-pre-start` attribute by adding attributes used markdown-it-attrs.
74
+
75
+ ~~~md
76
+ ```js {.style start="1"}
77
+ import mdit from 'markdonw-it'
78
+ const md = mdit()
79
+ md.render('Nyaan')
80
+ ```
81
+ ~~~
82
+
83
+ ~~~html
84
+ <pre><code class="language-js style" data-pre-start="1" style="counter-set:pre-line-number 1;"><span class="pre-line"><span class="hljs-keyword">import</span> mdit <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;markdonw-it&#x27;</span></span>
85
+ <span class="pre-line"><span class="hljs-keyword">const</span> md = <span class="hljs-title function_">mdit</span>()</span>
86
+ <span class="pre-line">md.<span class="hljs-title function_">render</span>(<span class="hljs-string">&#x27;Nyaan&#x27;</span>)</span>
87
+ </code></pre>
88
+ ~~~
89
+
90
+ CSS example: <https://codepen.io/peaceroad/pen/qBGpYGK>
package/index.js ADDED
@@ -0,0 +1,119 @@
1
+ const fenceStartTag = (token, tagName, opt) => {
2
+ let idAttr = [], classAttr = [], dataAttrs = [], styleAttr = [], otherAttrs = []
3
+ let hasClass = false
4
+ if (token.attrs) {
5
+ //console.log('start: ' +token.attrs)
6
+ for (let attr of token.attrs) {
7
+ if (attr[0] === 'id') {
8
+ idAttr.push(attr)
9
+ } else if (attr[0] === 'class') {
10
+ hasClass = true
11
+ classAttr.push([attr[0], opt.langPrefix + token.info + ' ' + attr[1]])
12
+ } else if (attr[0].startsWith('data-')) {
13
+ dataAttrs.push(attr)
14
+ } else if (attr[0] === 'style') {
15
+ styleAttr.push(attr)
16
+ } else {
17
+ otherAttrs.push(attr)
18
+ }
19
+ }
20
+ }
21
+ if (!hasClass) classAttr.push(['class', opt.langPrefix + token.info])
22
+ let orderedAttrs = [...idAttr, ...classAttr, ...dataAttrs, ...styleAttr, ...otherAttrs]
23
+ //console.log(orderedAttrs)
24
+ let tag = '<' + tagName
25
+ for (let attr of orderedAttrs) {
26
+ tag += ' ' + attr[0] + '="' + attr[1] + '"'
27
+ }
28
+ return tag + '>'
29
+ };
30
+
31
+ const splitFenceBlockToLines = (token, content) => {
32
+ const br = content.match(/\r?\n/)
33
+ const lines = content.split(/r?\n/)
34
+ let hasCodeLineStart = false
35
+ let styleIndex = -1
36
+ let dataIndex = -1
37
+ let setNumber = -1
38
+ if (token.attrs) {
39
+ token.attrs.forEach((attr, i) => {
40
+ if (attr[i][0] === 'style') styleIndex = i
41
+ hasCodeLineStart = (/^(?:(?:data-)?pre-)?start$/.test(attr[0]))
42
+ if (hasCodeLineStart) dataIndex = i
43
+ })
44
+ }
45
+ if (!hasCodeLineStart && setNumber === -1) return content
46
+ token.attrs[dataIndex][0] = 'data-pre-start'
47
+ setNumber = token.attrs[dataIndex][1]
48
+
49
+ if (styleIndex === -1) {
50
+ token.attrs.push(['style', 'counter-set:pre-line-number ' + setNumber + ';'])
51
+ } else {
52
+ token.attrs[styleIndex][1] = token.attrs[styleIndex][1].replace(/;?$/, '; counter-set:pre-line-number ' + setNumber + ';')
53
+ }
54
+ lines.map((line, n) => {
55
+ const lastElementTag = line.match(/<(\w+)( +[^>]*?)>[^>]*?(<\/\1>)?[^>]*?$/)
56
+ if (lastElementTag && !lastElementTag[3]) {
57
+ line += '</span>'
58
+ if (n < lines.length - 2) {
59
+ lines[n + 1] = `<${lastElementTag[1]}${lastElementTag[2]}>` + lines[n + 1]
60
+ }
61
+ }
62
+ if (n < lines.length - 1) {
63
+ lines[n] = '<span class="pre-line">' + line + '</span>'
64
+ }
65
+ })
66
+ return lines.join(br)
67
+ }
68
+
69
+ const getFenceHtml = (tokens, idx, env, slf, md, options) => {
70
+ const opt = {
71
+ setHighlight: true,
72
+ setLineNumber: true,
73
+ langPrefix: 'language-',
74
+ highlight: null,
75
+ }
76
+ if (options) Object.assign(opt, options)
77
+
78
+ const token = tokens[idx]
79
+ //console.log(token)
80
+ let content = token.content
81
+ if (md.options.highlight) {
82
+ if (token.info !== 'samp' && opt.setHighlight) {
83
+ content = md.options.highlight(token.content, token.info)
84
+ } else {
85
+ content = md.utils.escapeHtml(token.content)
86
+ }
87
+ } else {
88
+ content = md.utils.escapeHtml(token.content)
89
+ }
90
+ if (opt.setLineNumber) {
91
+ content = splitFenceBlockToLines(token, content)
92
+ }
93
+
94
+ let fenceHtml = '<pre>'
95
+ if (token.info === 'samp') {
96
+ fenceHtml += '<samp>'
97
+ } else if (token.info === 'shell' || token.info === 'console') {
98
+ fenceHtml += fenceStartTag(token, 'samp', opt);
99
+ } else {
100
+ fenceHtml += fenceStartTag(token, 'code', opt);
101
+ }
102
+ fenceHtml += content
103
+ if (token.info === 'samp') {
104
+ fenceHtml += '</samp>'
105
+ } else if (token.info === 'shell' || token.info === 'console') {
106
+ fenceHtml += '</samp>'
107
+ } else {
108
+ fenceHtml += '</code>'
109
+ }
110
+ return fenceHtml + '</pre>\n'
111
+ }
112
+
113
+ const mditRendererFence = (md, options) => {
114
+ md.renderer.rules['fence'] = (tokens, idx, env, slf) => {
115
+ return getFenceHtml(tokens, idx, env, slf, md, options)
116
+ }
117
+ }
118
+
119
+ export default mditRendererFence
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@peaceroad/markdown-it-renderer-fence",
3
+ "version": "0.1.0",
4
+ "description": "In code blocks, the `<samp>` tag is used with the language keywords `samp`, `shell`, and `console`, and provides an option to display line numbers.",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "node test/test.js"
9
+ },
10
+ "author": "peaceroad <peaceroad@gmail.com>",
11
+ "repository": "https://github.com/peaceroad/p7d-markdown-it-renderer-fence",
12
+ "license": "MIT",
13
+ "devDependencies": {
14
+ "@peaceroad/markdown-it-figure-with-p-caption": "^0.6.1",
15
+ "highlight.js": "^11.9.0",
16
+ "markdown-it": "^14.1.0",
17
+ "markdown-it-attrs": "^4.1.6"
18
+ }
19
+ }
@@ -0,0 +1,107 @@
1
+ [Markdown]
2
+ ```js
3
+ import mdit from 'markdonw-it'
4
+ ```
5
+ [HTML]
6
+ <pre><code class="language-js"><span class="hljs-keyword">import</span> mdit <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;markdonw-it&#x27;</span>
7
+ </code></pre>
8
+
9
+
10
+ [Markdown]
11
+ ```html
12
+ <p>I draw <span class="style">cats</span>.</p>
13
+ ```
14
+ [HTML]
15
+ <pre><code class="language-html"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>I draw <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;style&quot;</span>&gt;</span>cats<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
16
+ </code></pre>
17
+
18
+
19
+ [Markdown]
20
+ ```js
21
+ import mdit from 'markdonw-it'
22
+ const md = mdit()
23
+ md.render('Nyaan')
24
+ ```
25
+ [HTML]
26
+ <pre><code class="language-js"><span class="hljs-keyword">import</span> mdit <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;markdonw-it&#x27;</span>
27
+ <span class="hljs-keyword">const</span> md = <span class="hljs-title function_">mdit</span>()
28
+ md.<span class="hljs-title function_">render</span>(<span class="hljs-string">&#x27;Nyaan&#x27;</span>)
29
+ </code></pre>
30
+
31
+
32
+ [Markdown]
33
+ ```js {.style}
34
+ import mdit from 'markdonw-it'
35
+ const md = mdit()
36
+ md.render('Nyaan')
37
+ ```
38
+ [HTML]
39
+ <pre><code class="language-js style"><span class="hljs-keyword">import</span> mdit <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;markdonw-it&#x27;</span>
40
+ <span class="hljs-keyword">const</span> md = <span class="hljs-title function_">mdit</span>()
41
+ md.<span class="hljs-title function_">render</span>(<span class="hljs-string">&#x27;Nyaan&#x27;</span>)
42
+ </code></pre>
43
+
44
+
45
+ [Markdown]
46
+ ```html {start="2"}
47
+ <p>I draw <span class="style">cats</span>.</p>
48
+ ```
49
+ [HTML]
50
+ <pre><code class="language-html" data-pre-start="2" style="counter-set:pre-line-number 2;"><span class="pre-line"><span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>I draw <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;style&quot;</span>&gt;</span>cats<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
51
+ </code></pre>
52
+
53
+
54
+ [Markdown]
55
+ ```js {start="1"}
56
+ import mdit from 'markdonw-it'
57
+ ```
58
+ [HTML]
59
+ <pre><code class="language-js" data-pre-start="1" style="counter-set:pre-line-number 1;"><span class="pre-line"><span class="hljs-keyword">import</span> mdit <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;markdonw-it&#x27;</span></span>
60
+ </code></pre>
61
+
62
+
63
+ [Markdown]
64
+ ```js {.style start="1"}
65
+ import mdit from 'markdonw-it'
66
+ const md = mdit()
67
+ md.render('Nyaan')
68
+ ```
69
+ [HTML]
70
+ <pre><code class="language-js style" data-pre-start="1" style="counter-set:pre-line-number 1;"><span class="pre-line"><span class="hljs-keyword">import</span> mdit <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;markdonw-it&#x27;</span></span>
71
+ <span class="pre-line"><span class="hljs-keyword">const</span> md = <span class="hljs-title function_">mdit</span>()</span>
72
+ <span class="pre-line">md.<span class="hljs-title function_">render</span>(<span class="hljs-string">&#x27;Nyaan&#x27;</span>)</span>
73
+ </code></pre>
74
+
75
+
76
+ [Markdown]
77
+ ```shell
78
+ $ pwd
79
+ /home/User
80
+ ```
81
+ [HTML]
82
+ <pre><samp class="language-shell"><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">pwd</span></span>
83
+ /home/User
84
+ </samp></pre>
85
+
86
+
87
+ [Markdown]
88
+ ```console
89
+ $ pwd
90
+ /home/User
91
+ ```
92
+ [HTML]
93
+ <pre><samp class="language-console"><span class="hljs-meta prompt_">$ </span><span class="language-bash"><span class="hljs-built_in">pwd</span></span>
94
+ /home/User
95
+ </samp></pre>
96
+
97
+
98
+ [Markdown]
99
+ ```samp
100
+ $ pwd
101
+ /home/User
102
+ ```
103
+ [HTML]
104
+ <pre><samp>$ pwd
105
+ /home/User
106
+ </samp></pre>
107
+
@@ -0,0 +1,43 @@
1
+ [Markdown]
2
+ ```js
3
+ import mdit from 'markdonw-it'
4
+ mdit().render('A cat.')
5
+ ```
6
+ [HTML]
7
+ <pre><code class="language-js">import mdit from 'markdonw-it'
8
+ mdit().render('A cat.')
9
+ </code></pre>
10
+
11
+
12
+ [Markdown]
13
+ ```samp
14
+ $ pwd
15
+ /home/User
16
+ ```
17
+ [HTML]
18
+ <pre><samp>$ pwd
19
+ /home/User
20
+ </samp></pre>
21
+
22
+
23
+ [Markdown]
24
+ ```shell
25
+ $ pwd
26
+ /home/User
27
+ ```
28
+ [HTML]
29
+ <pre><samp class="language-shell">$ pwd
30
+ /home/User
31
+ </samp></pre>
32
+
33
+
34
+ [Markdown]
35
+ ```console
36
+ $ pwd
37
+ /home/User
38
+ ```
39
+ [HTML]
40
+ <pre><samp class="language-console">$ pwd
41
+ /home/User
42
+ </samp></pre>
43
+
package/test/test.js ADDED
@@ -0,0 +1,118 @@
1
+ import assert from 'assert'
2
+ import fs from 'fs'
3
+ import path from 'path'
4
+ import mdit from 'markdown-it'
5
+
6
+ import mditFigureWithPCaption from '@peaceroad/markdown-it-figure-with-p-caption'
7
+ import mditRendererFence from '../index.js'
8
+ import attrs from 'markdown-it-attrs'
9
+ import highlightjs from 'highlight.js'
10
+
11
+
12
+ let opt = {}
13
+
14
+ const md = mdit({ html: true }).use(mditRendererFence).use(attrs)
15
+ const mdHighlightJs = mdit({
16
+ html: true,
17
+ langPrefix: 'language-',
18
+ typographer: false,
19
+ highlight: (str, lang) => {
20
+ if (lang && highlightjs.getLanguage(lang)) {
21
+ try {
22
+ return highlightjs.highlight(str, { language: lang }).value
23
+ } catch (__) {}
24
+ }
25
+ return ''
26
+ }
27
+ }).use(mditRendererFence, opt).use(attrs)
28
+
29
+
30
+ let __dirname = path.dirname(new URL(import.meta.url).pathname)
31
+ const isWindows = (process.platform === 'win32')
32
+ if (isWindows) {
33
+ __dirname = __dirname.replace(/^\/+/, '').replace(/\//g, '\\')
34
+ }
35
+
36
+ const testData = {
37
+ noOption: __dirname + path.sep + 'examples.txt',
38
+ highlightjs: __dirname + path.sep + 'examples-highlightjs.txt',
39
+ }
40
+
41
+ const getTestData = (pat) => {
42
+ let ms = [];
43
+ if(!fs.existsSync(pat)) {
44
+ console.log('No exist: ' + pat)
45
+ return ms
46
+ }
47
+ const exampleCont = fs.readFileSync(pat, 'utf-8').trim();
48
+
49
+ let ms0 = exampleCont.split(/\n*\[Markdown\]\n/);
50
+ let n = 1;
51
+ while(n < ms0.length) {
52
+ let mhs = ms0[n].split(/\n+\[HTML[^\]]*?\]\n/);
53
+ let i = 1;
54
+ while (i < 2) {
55
+ if (mhs[i] === undefined) {
56
+ mhs[i] = '';
57
+ } else {
58
+ mhs[i] = mhs[i].replace(/$/,'\n');
59
+ }
60
+ i++;
61
+ }
62
+ ms[n] = {
63
+ "markdown": mhs[0],
64
+ "html": mhs[1],
65
+ };
66
+ n++;
67
+ }
68
+ return ms
69
+ }
70
+
71
+ const runTest = (process, pat, pass, testId) => {
72
+ console.log('===========================================================')
73
+ console.log(pat)
74
+ let ms = getTestData(pat)
75
+ if (ms.length === 0) return
76
+ let n = 1;
77
+ let end = ms.length - 1
78
+ if(testId) {
79
+ if (testId[0]) n = testId[0]
80
+ if (testId[1]) {
81
+ if (ms.length >= testId[1]) {
82
+ end = testId[1]
83
+ }
84
+ }
85
+ }
86
+ //console.log(n, end)
87
+
88
+ while(n <= end) {
89
+ if (!ms[n]
90
+ // || n != 3
91
+ ) {
92
+ n++
93
+ continue
94
+ }
95
+
96
+ const m = ms[n].markdown;
97
+ const h = process.render(m)
98
+ console.log('Test: ' + n + ' >>>');
99
+ try {
100
+ assert.strictEqual(h, ms[n].html);
101
+ } catch(e) {
102
+ pass = false
103
+ //console.log('Test: ' + n + ' >>>');
104
+ //console.log(opt);
105
+ console.log(ms[n].markdown);
106
+ console.log('incorrect:');
107
+ console.log('H: ' + h +'C: ' + ms[n].html);
108
+ }
109
+ n++;
110
+ }
111
+ return pass
112
+ }
113
+
114
+ let pass = true
115
+ pass = runTest(md, testData.noOption, pass)
116
+ pass = runTest(mdHighlightJs, testData.highlightjs, pass)
117
+
118
+ if (pass) console.log('Passed all test.')