turnish 1.0.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 +22 -0
- package/README.md +270 -0
- package/dist/index.cjs +68 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.iife.js +68 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.mjs +818 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +68 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/types/collapse-whitespace.d.ts +39 -0
- package/dist/types/default-rules.d.ts +4 -0
- package/dist/types/html-parser.d.ts +4 -0
- package/dist/types/index.d.ts +113 -0
- package/dist/types/node.d.ts +22 -0
- package/dist/types/root-node.d.ts +5 -0
- package/dist/types/rules.d.ts +30 -0
- package/dist/types/utilities.d.ts +16 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025- Manabu Nakazawa
|
|
4
|
+
Copyright (c) 2017-2025 Dom Christie
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Turnish
|
|
2
|
+
|
|
3
|
+
[](https://github.com/mshibanami/turnish/actions/workflows/test.yml)
|
|
4
|
+
|
|
5
|
+
Turnish is a HTML to Markdown converter written in JavaScript.
|
|
6
|
+
|
|
7
|
+
This is a fork of [Turndown](https://github.com/mixmark-io/turndown), originally created by Dom Christie.
|
|
8
|
+
|
|
9
|
+
## Turnish vs Turndown
|
|
10
|
+
|
|
11
|
+
**Library user perspective:**
|
|
12
|
+
|
|
13
|
+
* Fixed various issues, such as:
|
|
14
|
+
* escaping unwanted characters that can break the Markdown rendering.
|
|
15
|
+
* removing new lines in link texts.
|
|
16
|
+
* Added an option to configure how non-standard or unsupported HTML fragments are handled during conversion. For example, whether to convert them to Markdown where possible, preserve them as raw HTML, or retain them (adding a `markdown="1"` attribute when the HTML contains Markdown) so Markdown processors can parse any embedded Markdown.
|
|
17
|
+
* Changed the default behavior to better comply with de facto standards.
|
|
18
|
+
* Remains compatible with Turndown plugins.
|
|
19
|
+
* Remains licensed under the MIT License.
|
|
20
|
+
|
|
21
|
+
**Library/plugin developer perspective:**
|
|
22
|
+
|
|
23
|
+
* Updated to TypeScript
|
|
24
|
+
* Modernized build system using Vite
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
npm:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
npm install turnish
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
pnpm:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
pnpm install turnish
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Browser:
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<script src="https://cdn.jsdelivr.net/npm/turnish@latest/dist/index.iife.js"></script>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
For Node.js:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
var Turnish = require('turnish')
|
|
52
|
+
|
|
53
|
+
var turnish = new Turnish()
|
|
54
|
+
var markdown = turnish.render('<h1>Hello world!</h1>')
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
ES module import (Node with ESM, bundlers, or browsers supporting modules):
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
import Turnish from 'turnish'
|
|
61
|
+
|
|
62
|
+
const turnish = new Turnish()
|
|
63
|
+
const markdown = turnish.render('<h1>Hello world!</h1>')
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Turnish also accepts DOM nodes as input (either element nodes, document nodes, or document fragment nodes):
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
var markdown = turnish.render(document.getElementById('content'))
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Options
|
|
73
|
+
|
|
74
|
+
Options can be passed in to the constructor on instantiation. For example:
|
|
75
|
+
|
|
76
|
+
```js
|
|
77
|
+
var turnish = new Turnish({ option: 'value' })
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| Option | Valid values | Default |
|
|
81
|
+
| :--------------------------- | :---------------------------------------------------------------------------- | :--------- |
|
|
82
|
+
| `headingStyle` | `setext` or `atx` | `atx` |
|
|
83
|
+
| `hr` | Any [Thematic break](http://spec.commonmark.org/0.27/#thematic-breaks) | `---` |
|
|
84
|
+
| `bulletListMarker` | `-`, `+`, or `*` | `-` |
|
|
85
|
+
| `codeBlockStyle` | `indented` or `fenced` | `fenced` |
|
|
86
|
+
| `fence` | ` ``` ` or `~~~` | ` ``` ` |
|
|
87
|
+
| `emDelimiter` | `_` or `*` | `*` |
|
|
88
|
+
| `strongDelimiter` | `**` or `__` | `**` |
|
|
89
|
+
| `linkStyle` | `inlined` or `referenced` | `inlined` |
|
|
90
|
+
| `linkReferenceStyle` | `full`, `collapsed`, or `shortcut` | `full` |
|
|
91
|
+
| `preformattedCode` | `false` or [`true`](https://github.com/lucthev/collapse-whitespace/issues/16) | `false` |
|
|
92
|
+
| `linkReferenceDeduplication` | `none` or `full` | `full` |
|
|
93
|
+
| `htmlRetentionMode` | `standard`, `preserveAll`, or `markdownIncludingHtml` | `standard` |
|
|
94
|
+
|
|
95
|
+
### Advanced Options
|
|
96
|
+
|
|
97
|
+
| Option | Valid values | Default |
|
|
98
|
+
| :------------------- | :------------------------ | :-------------------------- |
|
|
99
|
+
| `blankReplacement` | rule replacement function | See **Special Rules** below |
|
|
100
|
+
| `keepReplacement` | rule replacement function | See **Special Rules** below |
|
|
101
|
+
| `defaultReplacement` | rule replacement function | See **Special Rules** below |
|
|
102
|
+
|
|
103
|
+
## Methods
|
|
104
|
+
|
|
105
|
+
### `addRule(key, rule)`
|
|
106
|
+
|
|
107
|
+
The `key` parameter is a unique name for the rule for easy reference. Example:
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
turnish.addRule('strikethrough', {
|
|
111
|
+
filter: ['del', 's', 'strike'],
|
|
112
|
+
replacement: function (content) {
|
|
113
|
+
return '~' + content + '~'
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`addRule` returns the `Turnish` instance for chaining.
|
|
119
|
+
|
|
120
|
+
See **Extending with Rules** below.
|
|
121
|
+
|
|
122
|
+
### `keep(filter)`
|
|
123
|
+
|
|
124
|
+
Determines which elements are to be kept and rendered as HTML. By default, Turndown does not keep any elements. The filter parameter works like a rule filter (see section on filters belows). Example:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
turnish.keep(['del', 'ins'])
|
|
128
|
+
turnish.render('<p>Hello <del>world</del><ins>World</ins></p>') // 'Hello <del>world</del><ins>World</ins>'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This will render `<del>` and `<ins>` elements as HTML when converted.
|
|
132
|
+
|
|
133
|
+
`keep` can be called multiple times, with the newly added keep filters taking precedence over older ones. Keep filters will be overridden by the standard CommonMark rules and any added rules. To keep elements that are normally handled by those rules, add a rule with the desired behaviour.
|
|
134
|
+
|
|
135
|
+
`keep` returns the `Turnish` instance for chaining.
|
|
136
|
+
|
|
137
|
+
### `remove(filter)`
|
|
138
|
+
|
|
139
|
+
Determines which elements are to be removed altogether i.e. converted to an empty string. By default, Turnish does not remove any elements. The filter parameter works like a rule filter (see section on filters belows). Example:
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
turnish.remove('del')
|
|
143
|
+
turnish.render('<p>Hello <del>world</del><ins>World</ins></p>') // 'Hello World'
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This will remove `<del>` elements (and contents).
|
|
147
|
+
|
|
148
|
+
`remove` can be called multiple times, with the newly added remove filters taking precedence over older ones. Remove filters will be overridden by the keep filters, standard CommonMark rules, and any added rules. To remove elements that are normally handled by those rules, add a rule with the desired behaviour.
|
|
149
|
+
|
|
150
|
+
`remove` returns the `Turnish` instance for chaining.
|
|
151
|
+
|
|
152
|
+
### `use(plugin|array)`
|
|
153
|
+
|
|
154
|
+
Use a plugin, or an array of plugins. Example:
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
// Import plugins from turndown-plugin-gfm
|
|
158
|
+
var turndownPluginGfm = require('turndown-plugin-gfm')
|
|
159
|
+
var gfm = turndownPluginGfm.gfm
|
|
160
|
+
var tables = turndownPluginGfm.tables
|
|
161
|
+
var strikethrough = turndownPluginGfm.strikethrough
|
|
162
|
+
|
|
163
|
+
// Use the gfm plugin
|
|
164
|
+
turnish.use(gfm)
|
|
165
|
+
|
|
166
|
+
// Use the table and strikethrough plugins only
|
|
167
|
+
turnish.use([tables, strikethrough])
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`use` returns the `Turnish` instance for chaining.
|
|
171
|
+
|
|
172
|
+
See **Plugins** below.
|
|
173
|
+
|
|
174
|
+
## Extending with Rules
|
|
175
|
+
|
|
176
|
+
Turnish can be extended by adding **rules**. A rule is a plain JavaScript object with `filter` and `replacement` properties. For example, the rule for converting `<p>` elements is as follows:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
{
|
|
180
|
+
filter: 'p',
|
|
181
|
+
replacement: function (content) {
|
|
182
|
+
return '\n\n' + content + '\n\n'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The filter selects `<p>` elements, and the replacement function returns the `<p>` contents separated by two new lines.
|
|
188
|
+
|
|
189
|
+
### `filter` string|Array|Function
|
|
190
|
+
|
|
191
|
+
The filter property determines whether or not an element should be replaced with the rule's `replacement`. DOM nodes can be selected simply using a tag name or an array of tag names:
|
|
192
|
+
|
|
193
|
+
* `filter: 'p'` will select `<p>` elements
|
|
194
|
+
* `filter: ['em', 'i']` will select `<em>` or `<i>` elements
|
|
195
|
+
|
|
196
|
+
The tag names in the `filter` property are expected in lowercase, regardless of their form in the document.
|
|
197
|
+
|
|
198
|
+
Alternatively, the filter can be a function that returns a boolean depending on whether a given node should be replaced. The function is passed a DOM node as well as the `Turnish` options. For example, the following rule selects `<a>` elements (with an `href`) when the `linkStyle` option is `inlined`:
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
filter: function (node, options) {
|
|
202
|
+
return (
|
|
203
|
+
options.linkStyle === 'inlined' &&
|
|
204
|
+
node.nodeName === 'A' &&
|
|
205
|
+
node.getAttribute('href')
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### `replacement` Function
|
|
211
|
+
|
|
212
|
+
The replacement function determines how an element should be converted. It should return the Markdown string for a given node. The function is passed the node's content, the node itself, and the `Turnish` options.
|
|
213
|
+
|
|
214
|
+
The following rule shows how `<em>` elements are converted:
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
rules.emphasis = {
|
|
218
|
+
filter: ['em', 'i'],
|
|
219
|
+
|
|
220
|
+
replacement: function (content, node, options) {
|
|
221
|
+
return options.emDelimiter + content + options.emDelimiter
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Special Rules
|
|
227
|
+
|
|
228
|
+
**Blank rule** determines how to handle blank elements. It overrides every rule (even those added via `addRule`). A node is blank if it only contains whitespace, and it's not an `<a>`, `<td>`,`<th>` or a void element. Its behaviour can be customised using the `blankReplacement` option.
|
|
229
|
+
|
|
230
|
+
**Keep rules** determine how to handle the elements that should not be converted, i.e. rendered as HTML in the Markdown output. By default, no elements are kept. Block-level elements will be separated from surrounding content by blank lines. Its behaviour can be customised using the `keepReplacement` option.
|
|
231
|
+
|
|
232
|
+
**Remove rules** determine which elements to remove altogether. By default, no elements are removed.
|
|
233
|
+
|
|
234
|
+
**Default rule** handles nodes which are not recognised by any other rule. By default, it outputs the node's text content (separated by blank lines if it is a block-level element). Its behaviour can be customised with the `defaultReplacement` option.
|
|
235
|
+
|
|
236
|
+
### Rule Precedence
|
|
237
|
+
|
|
238
|
+
Turnish iterates over the set of rules, and picks the first one that matches the `filter`. The following list describes the order of precedence:
|
|
239
|
+
|
|
240
|
+
1. Blank rule
|
|
241
|
+
2. Added rules (optional)
|
|
242
|
+
3. Commonmark rules
|
|
243
|
+
4. Keep rules
|
|
244
|
+
5. Remove rules
|
|
245
|
+
6. Default rule
|
|
246
|
+
|
|
247
|
+
## Plugins
|
|
248
|
+
|
|
249
|
+
The plugin API provides a convenient way for developers to apply multiple extensions. A plugin is just a function that is called with the `Turnish` instance.
|
|
250
|
+
|
|
251
|
+
## Escaping Markdown Characters
|
|
252
|
+
|
|
253
|
+
Turnish uses backslashes (`\`) to escape Markdown characters in the HTML input. This ensures that these characters are not interpreted as Markdown when the output is compiled back to HTML. For example, the contents of `<h1>1. Hello world</h1>` needs to be escaped to `1\. Hello world`, otherwise it will be interpreted as a list item rather than a heading.
|
|
254
|
+
|
|
255
|
+
To avoid the complexity and the performance implications of parsing the content of every HTML element as Markdown, Turnish uses a group of regular expressions to escape potential Markdown syntax. As a result, the escaping rules can be quite aggressive.
|
|
256
|
+
|
|
257
|
+
### Overriding `Turnish.prototype.escape`
|
|
258
|
+
|
|
259
|
+
If you are confident in doing so, you may want to customise the escaping behaviour to suit your needs. This can be done by overriding `Turnish.prototype.escape`. `escape` takes the text of each HTML element and should return a version with the Markdown characters escaped.
|
|
260
|
+
|
|
261
|
+
Note: text in code elements is never passed to`escape`.
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
[MIT License](LICENSE)
|
|
266
|
+
|
|
267
|
+
Copyright (c) 2025- Manabu Nakazawa
|
|
268
|
+
Copyright (c) 2017-2025 Dom Christie
|
|
269
|
+
|
|
270
|
+
Turnish is originally based on [Turndown](https://github.com/mixmark-io/turndown) by Dom Christie, and is licensed under the MIT License.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";function B(t,e){const n=t;return n.isBlock=E(n),n.isCode=n.nodeName==="CODE"||n.parentNode?.isCode,n.isBlank=P(n),n.flankingWhitespace=H(n,e),n}function P(t){return!S(t)&&!U(t)&&/^\s*$/i.test(t.textContent||"")&&!$(t)&&!z(t)}function H(t,e){const n=t;if(n.isBlock||e.preformattedCode&&n.isCode)return{leading:"",trailing:""};const r=_(t.textContent||"");return r.leadingAscii&&A("left",t,e)&&(r.leading=r.leadingNonAscii),r.trailingAscii&&A("right",t,e)&&(r.trailing=r.trailingNonAscii),{leading:r.leading,trailing:r.trailing}}function _(t){const e=t.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);return e?{leading:e[1],leadingAscii:e[2],leadingNonAscii:e[3],trailing:e[4],trailingNonAscii:e[5],trailingAscii:e[6]}:{leading:"",leadingAscii:"",leadingNonAscii:"",trailing:"",trailingNonAscii:"",trailingAscii:""}}function A(t,e,n){let r,i,l;return t==="left"?(r=e.previousElementSibling,i=/ $/):(r=e.nextElementSibling,i=/^ /),r&&(r.nodeType===3?l=i.test(r.nodeValue||""):n.preformattedCode&&r.nodeName==="CODE"?l=!1:r.nodeType===1&&!E(r)&&(l=i.test(r.textContent||""))),l||!1}const m={Element:1,Text:3,CDATASection:4};function N(t,e){return Array(e+1).join(t)}function D(t){return t.replace(/^\n*/,"")}function w(t){let e=t.length;for(;e>0&&t[e-1]===`
|
|
2
|
+
`;)e--;return t.substring(0,e)}function x(t){return w(D(t))}const v=["ADDRESS","ARTICLE","ASIDE","AUDIO","BLOCKQUOTE","BODY","CANVAS","CENTER","DD","DIR","DIV","DL","DT","FIELDSET","FIGCAPTION","FIGURE","FOOTER","FORM","FRAMESET","H1","H2","H3","H4","H5","H6","HEADER","HGROUP","HR","HTML","ISINDEX","LI","MAIN","MENU","NAV","NOFRAMES","NOSCRIPT","OL","OUTPUT","P","PRE","SECTION","TABLE","TBODY","TD","TFOOT","TH","THEAD","TR","UL"];function E(t){return k(t,v)}const O=["AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR"];function S(t){return k(t,O)}function $(t){return M(t,O)}const L=["A","TABLE","THEAD","TBODY","TFOOT","TH","TD","IFRAME","SCRIPT","AUDIO","VIDEO"],F=["P","BR","H1","H2","H3","H4","H5","H6","BLOCKQUOTE","UL","OL","LI","PRE","CODE","HR","A","EM","I","STRONG","B","IMG","DIV","SPAN","TABLE","THEAD","TBODY","TR","TH","TD"];function U(t){return k(t,L)}function z(t){return M(t,L)}function k(t,e){return e.indexOf(t.nodeName)>=0}function M(t,e){return e.some(function(n){return t.nodeType!==m.Element?!1:t.getElementsByTagName(n).length})}function I(t){return t?t.replace(/(\n+\s*)+/g,`
|
|
3
|
+
`):""}function V(t){return I(t).replace(/[\t\r\n]+/g," ").replace(/ {2,}/g," ").replace(/([()])/g,"\\$1").trim()}function p(t){return I(t).replace(/[\t\r\n]+/g," ")}const f={};f.paragraph={filter:"p",replacement:function(t){return`
|
|
4
|
+
|
|
5
|
+
`+t+`
|
|
6
|
+
|
|
7
|
+
`}};f.lineBreak={filter:"br",replacement:function(t,e,n){return n.br+`
|
|
8
|
+
`}};f.heading={filter:["h1","h2","h3","h4","h5","h6"],replacement:function(t,e,n){const r=Number(e.nodeName.charAt(1));if(n.headingStyle==="setext"&&r<3){const i=N(r===1?"=":"-",t.length);return`
|
|
9
|
+
|
|
10
|
+
`+t+`
|
|
11
|
+
`+i+`
|
|
12
|
+
|
|
13
|
+
`}else return`
|
|
14
|
+
|
|
15
|
+
`+N("#",r)+" "+t+`
|
|
16
|
+
|
|
17
|
+
`}};f.blockquote={filter:"blockquote",replacement:function(t){return t=x(t).replace(/^/gm,"> "),`
|
|
18
|
+
|
|
19
|
+
`+t+`
|
|
20
|
+
|
|
21
|
+
`}};f.list={filter:["ul","ol"],replacement:function(t,e){const n=e.parentNode;return n.nodeName==="LI"&&n.lastElementChild===e?`
|
|
22
|
+
`+t:`
|
|
23
|
+
|
|
24
|
+
`+t+`
|
|
25
|
+
|
|
26
|
+
`}};f.listItem={filter:"li",replacement:function(t,e,n){let r=n.bulletListMarker+" ";const i=e.parentNode;if(i.nodeName==="OL"){const a=i.getAttribute("start"),o=Array.prototype.indexOf.call(i.children,e);r=(a?Number(a)+o:o+1)+". "}const l=/\n$/.test(t);return t=x(t)+(l?`
|
|
27
|
+
`:""),t=t.replace(/\n/gm,`
|
|
28
|
+
`+" ".repeat(r.length)),r+t+(e.nextSibling?`
|
|
29
|
+
`:"")}};f.indentedCodeBlock={filter:function(t,e){return!!(e&&e.codeBlockStyle==="indented"&&t.nodeName==="PRE"&&t.firstChild&&t.firstChild.nodeName==="CODE")},replacement:function(t,e){return!e||!e.firstChild?"":`
|
|
30
|
+
|
|
31
|
+
`+e.firstChild.textContent.replace(/\n/g,`
|
|
32
|
+
`)+`
|
|
33
|
+
|
|
34
|
+
`}};f.fencedCodeBlock={filter:function(t,e){return!!(e&&e.codeBlockStyle==="fenced"&&t.nodeName==="PRE"&&t.firstChild&&t.firstChild.nodeName==="CODE")},replacement:function(t,e,n){if(!e.firstChild)return"";const r=e.firstChild,l=((r.getAttribute("class")||"").match(/language-(\S+)/)||[null,""])[1],a=r.textContent||"",o=n.fence?.charAt(0)||"`";let s=3;const u=new RegExp("^"+o+"{3,}","gm");let c;for(;c=u.exec(a);)c[0].length>=s&&(s=c[0].length+1);const d=N(o,s);return`
|
|
35
|
+
|
|
36
|
+
`+d+l+`
|
|
37
|
+
`+a.replace(/\n$/,"")+`
|
|
38
|
+
`+d+`
|
|
39
|
+
|
|
40
|
+
`}};f.horizontalRule={filter:"hr",replacement:function(t,e,n){return`
|
|
41
|
+
|
|
42
|
+
`+n.hr+`
|
|
43
|
+
|
|
44
|
+
`}};f.inlineLink={filter:function(t,e){return!!(e?.linkStyle==="inlined"&&t.nodeName==="A"&&t.getAttribute("href"))},replacement:function(t,e){const n=V(t);let r=e.getAttribute("href")?.replace(/([()])/g,"\\$1"),i;const l=e.getAttribute("title");return l?i=' "'+p(l).replace(/"/g,'\\"')+'"':i="","["+n+"]("+r+i+")"}};const R={filter:function(t,e){return!!(e&&e.linkStyle==="referenced"&&t.nodeName==="A"&&t.getAttribute("href"))},replacement:function(t,e,n){const r=R,i=e.getAttribute("href");let l;const a=e.getAttribute("title");a?l=' "'+p(a)+'"':l="";const o=i+l;let s,u;switch(n.linkReferenceStyle){case"collapsed":s="["+t+"][]",u="["+t+"]: "+o;break;case"shortcut":s="["+t+"]",u="["+t+"]: "+o;break;default:{let c;const d=r.urlReferenceIdMap.get(o);n.linkReferenceDeduplication==="full"&&d?(c=d,u="["+c+"]: "+i+l):(c=r.references.length+1,r.urlReferenceIdMap.set(o,c),u="["+c+"]: "+i+l,r.references.push(u)),s="["+t+"]["+c+"]";break}}return n.linkReferenceStyle!=="full"&&(n.linkReferenceDeduplication==="full"?r.urlReferenceIdMap.has(o)||(r.urlReferenceIdMap.set(o,1),r.references.push(u)):r.references.push(u)),s},references:[],urlReferenceIdMap:new Map,append:()=>{const t=R;let e="";return t.references&&t.references.length&&(e=`
|
|
45
|
+
|
|
46
|
+
`+t.references.join(`
|
|
47
|
+
`)+`
|
|
48
|
+
|
|
49
|
+
`,t.references=[],t.urlReferenceIdMap=new Map),e}};f.referenceLink=R;f.emphasis={filter:["em","i"],replacement:(t,e,n)=>(t=t.trim(),t?n.emDelimiter+t+n.emDelimiter:"")};f.strong={filter:["strong","b"],replacement:(t,e,n)=>(t=t.trim(),t?n.strongDelimiter+t+n.strongDelimiter:"")};f.code={filter:t=>{const e=t.previousSibling||t.nextSibling,r=t.parentNode.nodeName==="PRE"&&!e;return t.nodeName==="CODE"&&!r},replacement:t=>{const e=t.replace(/\r?\n|\r/g," "),n=/^`|^ .*?[^ ].* $|`$/.test(e)?" ":"";let r="`";const i=e.match(/`+/gm)||[];for(;i.includes(r);)r=r+"`";return r+n+e+n+r}};f.image={filter:"img",replacement:function(t,e){const n=e.getAttribute("alt"),r=n?p(n):"",i=e.getAttribute("src")||"",l=e.getAttribute("title"),a=l?p(l):"",o=a?' "'+a+'"':"";return i?"":""}};class W{options;_keep;_remove;blankRule;keepReplacement;markdownIncludingHtmlReplacement;defaultRule;array;constructor(e){this.options=e,this._keep=[],this._remove=[],this.blankRule={replacement:e.blankReplacement},this.keepReplacement=e.keepReplacement,this.markdownIncludingHtmlReplacement=e.markdownIncludingHtmlReplacement,this.defaultRule={replacement:e.defaultReplacement},this.array=[];for(const n in e.rules)this.array.push(e.rules[n])}add(e,n){this.array.unshift(n)}keep(e){this._keep.unshift({filter:e,replacement:this.keepReplacement})}remove(e){this._remove.unshift({filter:e,replacement:function(){return""}})}forNode(e){if(e.isBlank)return this.blankRule;if(this.options.htmlRetentionMode==="preserveAll"&&this.isUnsupportedElement(e))return{replacement:this.keepReplacement};if(this.options.htmlRetentionMode==="markdownIncludingHtml"&&this.isUnsupportedElement(e))return{replacement:this.markdownIncludingHtmlReplacement};let n;return(n=h(this.array,e,this.options))||(n=h(this._keep,e,this.options))||(n=h(this._remove,e,this.options))?n:this.defaultRule}isUnsupportedElement(e){const n=e.nodeName;if(n==="PRE"&&e.firstChild&&e.firstChild.nodeName==="CODE"){const r=e.firstChild;if(r.attributes&&r.attributes.length>0){for(let i=0;i<r.attributes.length;i++)if(r.attributes[i].name.toLowerCase()!=="class")return!0}}if(e.attributes&&e.attributes.length>0)switch(n){case"IMG":for(let i=0;i<e.attributes.length;i++){const l=e.attributes[i].name.toLowerCase();if(l!=="src"&&l!=="alt"&&l!=="title")return!0}return!1;case"A":for(let i=0;i<e.attributes.length;i++){const l=e.attributes[i].name.toLowerCase();if(l!=="href"&&l!=="title")return!0}return!1;case"CODE":const r=e.parentNode;if(r&&r.nodeName==="PRE"){for(let i=0;i<e.attributes.length;i++)if(e.attributes[i].name.toLowerCase()!=="class")return!0;return!1}default:return!0}return F.indexOf(n)===-1}forEach(e){for(let n=0;n<this.array.length;n++)e(this.array[n],n)}}function h(t,e,n){for(let r=0;r<t.length;r++){const i=t[r];if(G(i,e,n))return i}}function G(t,e,n){const r=t.filter;if(typeof r=="string"){if(r===e.nodeName.toLowerCase())return!0}else if(Array.isArray(r)){if(r.indexOf(e.nodeName.toLowerCase())>-1)return!0}else if(typeof r=="function"){if(r(e,n))return!0}else throw new TypeError("`filter` needs to be a string, array, or function");return!1}function K(t){const e=t.element,n=t.isBlock,r=t.isVoid,i=t.isPre||function(u){return u.nodeName==="PRE"};if(!e.firstChild||i(e))return;let l=null,a=!1,o=null,s=y(o,e,i);for(;s!==e;){if(s.nodeType===m.Text||s.nodeType===m.CDATASection){const c=s;let d=c.data.replace(/[ \r\n\t]+/g," ");if((!l||/ $/.test(l.data))&&!a&&d[0]===" "&&(d=d.substr(1)),!d){s=g(s);continue}c.data=d,l=c}else if(s.nodeType===m.Element)n(s)||s.nodeName==="BR"?(l&&(l.data=l.data.replace(/ $/,"")),l=null,a=!1):r(s)||i(s)?(l=null,a=!0):l&&(a=!1);else{s=g(s);continue}const u=y(o,s,i);o=s,s=u}l&&(l.data=l.data.replace(/ $/,""),l.data||g(l))}function g(t){const e=t.nextSibling??t.parentNode;return t.parentNode&&t.parentNode.removeChild(t),e}function y(t,e,n){return t&&t.parentNode===e||n(e)?e.nextSibling??e.parentNode:e.firstChild??e.nextSibling??e.parentNode}const T=typeof window<"u"?window:typeof globalThis<"u"?globalThis:{};function j(){const t=typeof T.DOMParser<"u"?T.DOMParser:void 0;let e=!1;if(!t)return!1;try{new t().parseFromString("","text/html")&&(e=!0)}catch{}return e}class C{parseFromString(e,n){throw new Error("Not implemented")}}function Y(){if(typeof window<"u"&&typeof document<"u"&&(typeof process>"u"||process.browser),typeof window<"u"){class t extends C{parseFromString(n,r){const i=document.implementation.createHTMLDocument("");return i.open(),i.write(n),i.close(),i}}return new t}else{const t=require("@mixmark-io/domino");class e extends C{parseFromString(r,i){return t.createDocument(r)}}return new e}}const q=()=>j()?new T.DOMParser:Y();function Q(t,{preformattedCode:e}){let n;return typeof t=="string"?n=J().parseFromString('<x-turnish id="turnish-root">'+t+"</x-turnish>","text/html").getElementById("turnish-root"):n=t.cloneNode(!0),K({element:n,isBlock:E,isVoid:S,isPre:e?Z:void 0}),n}let X;function J(){return X??=q()}function Z(t){return t.nodeName==="PRE"||t.nodeName==="CODE"}const ee=[[/\\/g,"\\\\"],[/\*/g,"\\*"],[/_/g,"\\_"],[/^-/g,"\\-"],[/^\+ /g,"\\+ "],[/^(=+)/g,"\\$1"],[/^(#{1,6}) /g,"\\$1 "],[/`/g,"\\`"],[/^~~~/g,"\\~~~"],[/\[/g,"\\["],[/\]/g,"\\]"],[/<([^>]*)>/g,"\\<$1\\>"],[/^>/g,"\\>"],[/^(\d+)\. /g,"$1\\. "]],te={rules:f,headingStyle:"atx",hr:"---",bulletListMarker:"-",codeBlockStyle:"fenced",fence:"```",emDelimiter:"*",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",linkReferenceDeduplication:"full",br:" ",preformattedCode:!1,htmlRetentionMode:"standard",blankReplacement:(t,e)=>e.isBlock?`
|
|
50
|
+
|
|
51
|
+
`:"",keepReplacement:(t,e)=>e.isBlock?`
|
|
52
|
+
|
|
53
|
+
`+e.outerHTML+`
|
|
54
|
+
|
|
55
|
+
`:e.outerHTML,markdownIncludingHtmlReplacement:(t,e)=>{const n=e.nodeName.toLowerCase();let r="";if(e.attributes&&e.attributes.length>0){const s=[];for(let u=0;u<e.attributes.length;u++){const c=e.attributes[u];s.push(`${c.name}="${c.value}"`)}r=" "+s.join(" ")}r+=' markdown="1"';const i=`<${n}${r}>`,l=`</${n}>`,a=t.trim(),o=i+`
|
|
56
|
+
`+a+`
|
|
57
|
+
`+l;return e.isBlock?`
|
|
58
|
+
|
|
59
|
+
`+o+`
|
|
60
|
+
|
|
61
|
+
`:o},defaultReplacement:function(t,e){return e.isBlock?`
|
|
62
|
+
|
|
63
|
+
`+t+`
|
|
64
|
+
|
|
65
|
+
`:t}};class ne{options;rules;constructor(e){this.options=Object.assign({},te,e),this.rules=new W(this.options)}render(e){if(!re(e))throw new TypeError(e+" is not a string, or an element/document/fragment node.");if(e==="")return"";const n=this.process(Q(e,this.options));return this.postProcess(n)}use(e){if(Array.isArray(e))for(let n=0;n<e.length;n++)this.use(e[n]);else if(typeof e=="function")e(this);else throw new TypeError("plugin must be a Function or an Array of Functions");return this}addRule(e,n){return this.rules.add(e,n),this}keep(e){return this.rules.keep(e),this}remove(e){return this.rules.remove(e),this}escape(e){return ee.reduce(function(n,r){return n.replace(r[0],r[1])},e)}process(e){return Array.from(e.childNodes).reduce((n,r)=>{const i=B(r,this.options);let l="";if(i.nodeType===m.Text){const a=i.nodeValue??"";l=i.isCode?a:this.escape(a)}else i.nodeType===m.Element&&(l=this.replacementForNode(i));return b(n,l)},"")}postProcess(e){for(const n of this.rules.array)n.append&&(e=b(e,n.append(this.options)));return e.replace(/^[\t\r\n]+/,"").replace(/[\t\r\n\s]+$/,"")}replacementForNode(e){const n=this.rules.forNode(e);let r=this.process(e);const i=e.flankingWhitespace;return(i.leading||i.trailing)&&(r=r.trim()),i.leading+n.replacement(r,e,this.options)+i.trailing}}function b(t,e){const n=w(t),r=D(e),i=Math.max(t.length-n.length,e.length-r.length),l=`
|
|
66
|
+
|
|
67
|
+
`.substring(0,i);return n+l+r}function re(t){return t!=null&&(typeof t=="string"||t.nodeType&&(t.nodeType===1||t.nodeType===9||t.nodeType===11))}module.exports=ne;
|
|
68
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/node.ts","../src/utilities.ts","../src/default-rules.ts","../src/rules.ts","../src/collapse-whitespace.ts","../src/html-parser.ts","../src/root-node.ts","../src/index.ts"],"sourcesContent":["import { isBlock, isVoid, hasVoid, isMeaningfulWhenBlank, hasMeaningfulWhenBlank } from '@/utilities'\n\ninterface Options {\n preformattedCode?: boolean;\n}\n\ninterface FlankingWhitespace {\n leading: string;\n trailing: string;\n}\n\ninterface EdgeWhitespace extends FlankingWhitespace {\n leadingAscii: string;\n leadingNonAscii: string;\n trailingNonAscii: string;\n trailingAscii: string;\n}\n\nexport interface ExtendedNode extends Element {\n isBlock: boolean;\n isCode: boolean;\n isBlank: boolean;\n flankingWhitespace: FlankingWhitespace;\n}\n\nexport function ExtendedNode(node: Node, options: Options): ExtendedNode {\n const extended = node as ExtendedNode;\n extended.isBlock = isBlock(extended);\n extended.isCode = extended.nodeName === 'CODE' || (extended.parentNode as ExtendedNode)?.isCode;\n extended.isBlank = isBlank(extended);\n extended.flankingWhitespace = flankingWhitespace(extended, options);\n return extended;\n}\n\nfunction isBlank(node: ExtendedNode): boolean {\n return (\n !isVoid(node) &&\n !isMeaningfulWhenBlank(node) &&\n /^\\s*$/i.test(node.textContent || '') &&\n !hasVoid(node) &&\n !hasMeaningfulWhenBlank(node)\n )\n}\n\nfunction flankingWhitespace(node: ExtendedNode, options: Options): FlankingWhitespace {\n const extendedNode = node as ExtendedNode;\n\n if (extendedNode.isBlock || (options.preformattedCode && extendedNode.isCode)) {\n return { leading: '', trailing: '' };\n }\n\n const edges = edgeWhitespace(node.textContent || '');\n\n // abandon leading ASCII WS if left-flanked by ASCII WS\n if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) {\n edges.leading = edges.leadingNonAscii;\n }\n\n // abandon trailing ASCII WS if right-flanked by ASCII WS\n if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {\n edges.trailing = edges.trailingNonAscii;\n }\n\n return { leading: edges.leading, trailing: edges.trailing };\n}\n\nfunction edgeWhitespace(string: string): EdgeWhitespace {\n const m = string.match(/^(([ \\t\\r\\n]*)(\\s*))(?:(?=\\S)[\\s\\S]*\\S)?((\\s*?)([ \\t\\r\\n]*))$/);\n\n if (!m) {\n return {\n leading: '',\n leadingAscii: '',\n leadingNonAscii: '',\n trailing: '',\n trailingNonAscii: '',\n trailingAscii: ''\n };\n }\n\n return {\n leading: m[1], // whole string for whitespace-only strings\n leadingAscii: m[2],\n leadingNonAscii: m[3],\n trailing: m[4], // empty for whitespace-only strings\n trailingNonAscii: m[5],\n trailingAscii: m[6]\n };\n}\n\nfunction isFlankedByWhitespace(side: 'left' | 'right', node: Element, options: Options): boolean {\n let sibling: Element | null;\n let regExp: RegExp;\n let isFlanked: boolean | undefined;\n\n if (side === 'left') {\n sibling = node.previousElementSibling;\n regExp = / $/;\n } else {\n sibling = node.nextElementSibling;\n regExp = /^ /;\n }\n\n if (sibling) {\n if (sibling.nodeType === 3) {\n isFlanked = regExp.test(sibling.nodeValue || '');\n } else if (options.preformattedCode && sibling.nodeName === 'CODE') {\n isFlanked = false;\n } else if (sibling.nodeType === 1 && !isBlock(sibling)) {\n isFlanked = regExp.test(sibling.textContent || '');\n }\n }\n\n return isFlanked || false;\n}\n\nexport const NodeTypes = {\n Element: 1,\n Text: 3,\n CDATASection: 4,\n Comment: 8\n} as const;\n\nexport type NodeType = typeof NodeTypes[keyof typeof NodeTypes];\n","import { ExtendedNode, NodeTypes } from \"./node\";\n\nexport function repeat(character: string, count: number) {\n return Array(count + 1).join(character)\n}\n\nexport function trimLeadingNewlines(string: string) {\n return string.replace(/^\\n*/, '')\n}\n\nexport function trimTrailingNewlines(string: string) {\n // avoid match-at-end regexp bottleneck, see #370\n let indexEnd = string.length\n while (indexEnd > 0 && string[indexEnd - 1] === '\\n') indexEnd--\n return string.substring(0, indexEnd)\n}\n\nexport function trimNewlines(string: string) {\n return trimTrailingNewlines(trimLeadingNewlines(string))\n}\n\nexport const blockElements = [\n 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',\n 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',\n 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',\n 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',\n 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',\n 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'\n]\n\nexport function isBlock(node: Node) {\n return is(node, blockElements)\n}\n\nexport const voidElements = [\n 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',\n 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'\n]\n\nexport function isVoid(node: Node) {\n return is(node, voidElements)\n}\n\nexport function hasVoid(node: Node) {\n return has(node, voidElements)\n}\n\nconst meaningfulWhenBlankElements = [\n 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',\n 'AUDIO', 'VIDEO'\n]\n\nexport const standardMarkdownElements = [\n 'P', 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'BLOCKQUOTE',\n 'UL', 'OL', 'LI', 'PRE', 'CODE', 'HR', 'A', 'EM', 'I', 'STRONG',\n 'B', 'IMG', 'DIV', 'SPAN', 'TABLE', 'THEAD', 'TBODY', 'TR', 'TH', 'TD'\n]\n\nexport function isMeaningfulWhenBlank(node: Node) {\n return is(node, meaningfulWhenBlankElements)\n}\n\nexport function hasMeaningfulWhenBlank(node: Node) {\n return has(node, meaningfulWhenBlankElements)\n}\n\nfunction is(node: Node, tagNames: string[]) {\n return tagNames.indexOf(node.nodeName) >= 0\n}\n\nfunction has(node: Node, tagNames: string[]) {\n return (\n tagNames.some(function (tagName) {\n if (node.nodeType !== NodeTypes.Element) {\n return false;\n }\n return (node as Element).getElementsByTagName(tagName).length\n })\n )\n}\n\nexport function sanitizeWhitespace(string: string): string {\n return string ? string.replace(/(\\n+\\s*)+/g, '\\n') : '';\n}\n\nexport function sanitizedLinkContent(content: string): string {\n const sanitized = sanitizeWhitespace(content);\n return sanitized\n .replace(/[\\t\\r\\n]+/g, ' ')\n .replace(/ {2,}/g, ' ')\n .replace(/([()])/g, '\\\\$1')\n .trim();\n}\n\nexport function sanitizedLinkTitle(content: string): string {\n const sanitized = sanitizeWhitespace(content);\n return sanitized\n .replace(/[\\t\\r\\n]+/g, ' ');\n}\n\nexport type RequireOnly<T, K extends keyof T> =\n T & Required<Pick<T, K>>;\n","\nimport { Rule } from '@/rules';\nimport { TurnishOptions } from '@/index';\nimport { repeat, RequireOnly, sanitizedLinkContent, sanitizedLinkTitle, trimNewlines } from '@/utilities';\nimport { url } from 'inspector';\n\nexport const defaultRules: { [key: string]: Rule } = {}\n\ndefaultRules.paragraph = {\n filter: 'p',\n replacement: function (content: string): string {\n return '\\n\\n' + content + '\\n\\n';\n }\n};\n\ndefaultRules.lineBreak = {\n filter: 'br',\n replacement: function (_content: string, _node: Node, options: TurnishOptions): string {\n return options.br + '\\n';\n }\n};\n\ndefaultRules.heading = {\n filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n const hLevel = Number(node.nodeName.charAt(1));\n if (options.headingStyle === 'setext' && hLevel < 3) {\n const underline = repeat((hLevel === 1 ? '=' : '-'), content.length);\n return (\n '\\n\\n' + content + '\\n' + underline + '\\n\\n'\n );\n } else {\n return '\\n\\n' + repeat('#', hLevel) + ' ' + content + '\\n\\n';\n }\n }\n};\n\ndefaultRules.blockquote = {\n filter: 'blockquote',\n replacement: function (content: string): string {\n content = trimNewlines(content).replace(/^/gm, '> ');\n return '\\n\\n' + content + '\\n\\n';\n }\n};\n\ndefaultRules.list = {\n filter: ['ul', 'ol'],\n replacement: function (content: string, node: Node): string {\n const parent = node.parentNode as Element;\n if (parent.nodeName === 'LI' && parent.lastElementChild === node) {\n return '\\n' + content;\n } else {\n return '\\n\\n' + content + '\\n\\n';\n }\n }\n};\n\ndefaultRules.listItem = {\n filter: 'li',\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n let prefix = options.bulletListMarker + ' ';\n const parent = node.parentNode as Element;\n if (parent.nodeName === 'OL') {\n const start = parent.getAttribute('start');\n const index = Array.prototype.indexOf.call(parent.children, node);\n prefix = (start ? Number(start) + index : index + 1) + '. ';\n }\n const isParagraph = /\\n$/.test(content);\n content = trimNewlines(content) + (isParagraph ? '\\n' : '');\n content = content.replace(/\\n/gm, '\\n' + ' '.repeat(prefix.length)); // indent\n return (\n prefix + content + (node.nextSibling ? '\\n' : '')\n );\n }\n};\n\ndefaultRules.indentedCodeBlock = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.codeBlockStyle === 'indented' &&\n node.nodeName === 'PRE' &&\n node.firstChild &&\n (node.firstChild as Element).nodeName === 'CODE'\n );\n },\n replacement: function (_content: string, node: Node): string {\n if (!node || !node.firstChild) return '';\n return (\n '\\n\\n ' +\n (node.firstChild as Element).textContent!.replace(/\\n/g, '\\n ') +\n '\\n\\n'\n );\n }\n};\n\ndefaultRules.fencedCodeBlock = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.codeBlockStyle === 'fenced' &&\n node.nodeName === 'PRE' &&\n node.firstChild &&\n (node.firstChild as Element).nodeName === 'CODE'\n );\n },\n replacement: function (_content: string, node: Node, options: TurnishOptions): string {\n if (!node.firstChild) {\n return '';\n }\n const codeElem = node.firstChild as Element;\n const className = codeElem.getAttribute('class') || '';\n const language = (className.match(/language-(\\S+)/) || [null, ''])[1];\n const code = codeElem.textContent || '';\n const fenceChar = options.fence?.charAt(0) || '`';\n let fenceSize = 3;\n const fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');\n let match;\n while ((match = fenceInCodeRegex.exec(code))) {\n if (match[0].length >= fenceSize) {\n fenceSize = match[0].length + 1;\n }\n }\n const fence = repeat(fenceChar, fenceSize);\n return (\n '\\n\\n' + fence + language + '\\n' +\n code.replace(/\\n$/, '') +\n '\\n' + fence + '\\n\\n'\n );\n }\n};\n\ndefaultRules.horizontalRule = {\n filter: 'hr',\n replacement: function (_content: string, _node: Node, options: TurnishOptions): string {\n return '\\n\\n' + options.hr + '\\n\\n';\n }\n};\n\ndefaultRules.inlineLink = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options?.linkStyle === 'inlined' &&\n node.nodeName === 'A' &&\n (node as Element).getAttribute('href')\n );\n },\n replacement: function (content: string, node: Node): string {\n const sanitizedContent = sanitizedLinkContent(content);\n let href = (node as Element)\n .getAttribute('href')\n ?.replace(/([()])/g, '\\\\$1');\n let title: string;\n const titleAttr = (node as Element).getAttribute('title');\n if (titleAttr) {\n const sanitizedTitle = sanitizedLinkTitle(titleAttr);\n title = ' \"' + sanitizedTitle.replace(/\"/g, '\\\\\"') + '\"';\n } else {\n title = '';\n }\n return '[' + sanitizedContent + '](' + href + title + ')';\n }\n};\n\nconst referenceLinkRule: RequireOnly<Rule, \"urlReferenceIdMap\" | \"references\"> = {\n filter: function (node: Node, options: TurnishOptions): boolean {\n return !!(\n options &&\n options.linkStyle === 'referenced' &&\n node.nodeName === 'A' &&\n (node as Element).getAttribute('href')\n );\n },\n replacement: function (content: string, node: Node, options: TurnishOptions): string {\n const self = referenceLinkRule;\n\n const href = (node as Element).getAttribute('href');\n let title: string;\n const titleAttr = (node as Element).getAttribute('title');\n if (titleAttr) {\n const sanitizedTitle = sanitizedLinkTitle(titleAttr);\n title = ' \"' + sanitizedTitle + '\"';\n } else {\n title = '';\n }\n const referenceKey = href + title;\n\n let replacement: string;\n let reference: string;\n switch (options.linkReferenceStyle) {\n case 'collapsed':\n replacement = '[' + content + '][]';\n reference = '[' + content + ']: ' + referenceKey;\n break;\n case 'shortcut':\n replacement = '[' + content + ']';\n reference = '[' + content + ']: ' + referenceKey;\n break;\n default: {\n let id: number;\n const existingKey = self.urlReferenceIdMap.get(referenceKey);\n if (options.linkReferenceDeduplication === 'full' && existingKey) {\n id = existingKey;\n reference = '[' + id + ']: ' + href + title;\n } else {\n id = self.references.length + 1;\n self.urlReferenceIdMap.set(referenceKey, id);\n reference = '[' + id + ']: ' + href + title;\n self.references.push(reference);\n }\n replacement = '[' + content + '][' + id + ']';\n break;\n }\n }\n\n if (options.linkReferenceStyle !== 'full') {\n // Check if we should deduplicate\n if (options.linkReferenceDeduplication === 'full') {\n if (!self.urlReferenceIdMap.has(referenceKey)) {\n self.urlReferenceIdMap.set(referenceKey, 1);\n self.references.push(reference);\n }\n } else {\n self.references.push(reference);\n }\n }\n return replacement;\n },\n references: [],\n urlReferenceIdMap: new Map<string, number>(),\n append: (): string => {\n const self = referenceLinkRule;\n let references = '';\n if (self.references && self.references.length) {\n references = '\\n\\n' + self.references.join('\\n') + '\\n\\n';\n self.references = [];\n self.urlReferenceIdMap = new Map();\n }\n return references;\n }\n};\n\ndefaultRules.referenceLink = referenceLinkRule;\n\ndefaultRules.emphasis = {\n filter: ['em', 'i'],\n replacement: (content: string, _node: Node, options: TurnishOptions): string => {\n content = content.trim();\n if (!content) { return ''; }\n return options.emDelimiter + content + options.emDelimiter;\n }\n};\n\ndefaultRules.strong = {\n filter: ['strong', 'b'],\n replacement: (content: string, _node: Node, options: TurnishOptions): string => {\n content = content.trim();\n if (!content) { return ''; }\n return options.strongDelimiter + content + options.strongDelimiter;\n }\n};\n\ndefaultRules.code = {\n filter: (node: Node): boolean => {\n const hasSiblings = node.previousSibling || node.nextSibling;\n const parent = node.parentNode as Element;\n const isCodeBlock = parent.nodeName === 'PRE' && !hasSiblings;\n return node.nodeName === 'CODE' && !isCodeBlock;\n },\n replacement: (content: string): string => {\n const trimmed = content.replace(/\\r?\\n|\\r/g, ' ');\n const extraSpace = /^`|^ .*?[^ ].* $|`$/.test(trimmed) ? ' ' : '';\n let delimiter = '`';\n const matches: string[] = trimmed.match(/`+/gm) || [];\n while (matches.includes(delimiter)) delimiter = delimiter + '`';\n return delimiter + extraSpace + trimmed + extraSpace + delimiter;\n }\n};\n\ndefaultRules.image = {\n filter: 'img',\n replacement: function (_content: string, node: Node): string {\n const altAttr = (node as Element).getAttribute('alt');\n const alt = altAttr ? sanitizedLinkTitle(altAttr) : '';\n const src = (node as Element).getAttribute('src') || '';\n const titleAttr = (node as Element).getAttribute('title');\n const title = titleAttr ? sanitizedLinkTitle(titleAttr) : '';\n const titlePart = title ? ' \"' + title + '\"' : '';\n return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '';\n }\n};\n","/**\n * Manages a collection of rules used to convert HTML to Markdown\n */\nimport { ExtendedNode } from \"./node\";\nimport { TurnishOptions } from \"@/index\";\nimport { standardMarkdownElements } from \"./utilities\";\n\nexport type RuleFilterFunction = (node: ExtendedNode, options: TurnishOptions) => boolean;\nexport type RuleFilter = string | string[] | RuleFilterFunction;\n\ntype RuleReplacementFunction = (...args: any[]) => string;\n\nexport interface Rule {\n filter?: RuleFilter;\n replacement: RuleReplacementFunction | ((content: string, node: any, options: TurnishOptions, previousNode?: any) => string);\n references?: string[];\n /// Map of URL+title combinations to their reference IDs, used for link reference deduplication.\n /// When linkReferenceDeduplication is 'full', this tracks which URLs have already been assigned a reference number to avoid creating duplicate references.\n urlReferenceIdMap?: Map<string, number>;\n append?: (options: TurnishOptions) => string;\n}\n\nexport class Rules {\n options: TurnishOptions;\n private _keep: Rule[];\n private _remove: Rule[];\n blankRule: Rule;\n keepReplacement: RuleReplacementFunction;\n markdownIncludingHtmlReplacement: RuleReplacementFunction;\n defaultRule: Rule;\n array: Rule[];\n\n constructor(options: TurnishOptions) {\n this.options = options;\n this._keep = [];\n this._remove = [];\n\n this.blankRule = {\n replacement: options.blankReplacement\n };\n\n this.keepReplacement = options.keepReplacement;\n this.markdownIncludingHtmlReplacement = options.markdownIncludingHtmlReplacement;\n\n this.defaultRule = {\n replacement: options.defaultReplacement\n };\n\n this.array = [];\n for (const key in options.rules) {\n this.array.push(options.rules[key]);\n }\n }\n\n add(key: string, rule: Rule): void {\n this.array.unshift(rule);\n }\n\n keep(filter: RuleFilter): void {\n this._keep.unshift({\n filter: filter,\n replacement: this.keepReplacement\n });\n }\n\n remove(filter: RuleFilter): void {\n this._remove.unshift({\n filter: filter,\n replacement: function () {\n return '';\n }\n });\n }\n\n forNode(node: ExtendedNode): Rule {\n if (node.isBlank) {\n return this.blankRule;\n }\n if (this.options.htmlRetentionMode === 'preserveAll' && this.isUnsupportedElement(node)) {\n return {\n replacement: this.keepReplacement\n };\n }\n if (this.options.htmlRetentionMode === 'markdownIncludingHtml' && this.isUnsupportedElement(node)) {\n return {\n replacement: this.markdownIncludingHtmlReplacement\n };\n }\n\n let rule: Rule | undefined;\n if ((rule = findRule(this.array, node, this.options))) {\n return rule;\n }\n if ((rule = findRule(this._keep, node, this.options))) {\n return rule;\n }\n if ((rule = findRule(this._remove, node, this.options))) {\n return rule;\n }\n return this.defaultRule;\n }\n\n /// Check if an element is unsupported for Markdown conversion.\n private isUnsupportedElement(node: ExtendedNode): boolean {\n const nodeName = node.nodeName;\n\n if (nodeName === 'PRE' && node.firstChild && (node.firstChild as Element).nodeName === 'CODE') {\n const codeElem = node.firstChild as Element;\n if (codeElem.attributes && codeElem.attributes.length > 0) {\n for (let i = 0; i < codeElem.attributes.length; i++) {\n const attrName = codeElem.attributes[i].name.toLowerCase();\n if (attrName !== 'class') {\n return true;\n }\n }\n }\n }\n\n if (node.attributes && node.attributes.length > 0) {\n switch (nodeName) {\n case 'IMG':\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'src' && attrName !== 'alt' && attrName !== 'title') {\n return true;\n }\n }\n return false;\n case 'A':\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'href' && attrName !== 'title') {\n return true;\n }\n }\n return false;\n case 'CODE':\n const parent = node.parentNode as Element;\n if (parent && parent.nodeName === 'PRE') {\n for (let i = 0; i < node.attributes.length; i++) {\n const attrName = node.attributes[i].name.toLowerCase();\n if (attrName !== 'class') {\n return true;\n }\n }\n return false;\n }\n default:\n return true;\n }\n }\n // Elements that are not standard HTML elements are unsupported\n if (standardMarkdownElements.indexOf(nodeName) === -1) {\n return true;\n }\n return false;\n }\n\n forEach(fn: (rule: Rule, index: number) => void): void {\n for (let i = 0; i < this.array.length; i++) {\n fn(this.array[i], i);\n }\n }\n}\n\nfunction findRule(rules: Rule[], node: ExtendedNode, options: TurnishOptions): Rule | undefined {\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n if (filterValue(rule, node, options)) return rule;\n }\n return undefined;\n}\n\nfunction filterValue(rule: Rule, node: ExtendedNode, options: TurnishOptions): boolean {\n const filter = rule.filter;\n if (typeof filter === 'string') {\n if (filter === node.nodeName.toLowerCase()) {\n return true;\n }\n } else if (Array.isArray(filter)) {\n if (filter.indexOf(node.nodeName.toLowerCase()) > -1) {\n return true;\n }\n } else if (typeof filter === 'function') {\n if (filter(node, options)) {\n return true;\n }\n } else {\n throw new TypeError('`filter` needs to be a string, array, or function');\n }\n return false;\n}\n","/**\n * The collapseWhitespace function is adapted from collapse-whitespace\n * by Luc Thevenard.\n *\n * The MIT License (MIT)\n *\n * Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nimport { NodeTypes } from \"./node\";\n\n/**\n * collapseWhitespace(options) removes extraneous whitespace from an the given element.\n *\n * @param {Object} options\n */\ninterface CollapseWhitespaceOptions {\n element: Node;\n isBlock: (node: Node) => boolean;\n isVoid: (node: Node) => boolean;\n isPre?: (node: Node) => boolean;\n}\n\nfunction collapseWhitespace(options: CollapseWhitespaceOptions): void {\n const element = options.element\n const isBlock = options.isBlock\n const isVoid = options.isVoid\n const isPre = options.isPre || function (node: Node): boolean {\n return node.nodeName === 'PRE';\n };\n\n if (!element.firstChild || isPre(element)) return\n\n let prevText: Text | null = null;\n let keepLeadingWs = false\n\n let prev: Node | null = null;\n let node: Node = next(prev, element, isPre);\n\n while (node !== element) {\n if (node.nodeType === NodeTypes.Text || node.nodeType === NodeTypes.CDATASection) {\n const textNode = node as Text;\n let text = textNode.data.replace(/[ \\r\\n\\t]+/g, ' ');\n\n if ((!prevText || / $/.test(prevText.data)) &&\n !keepLeadingWs && text[0] === ' ') {\n text = text.substr(1);\n }\n\n // `text` might be empty at this point.\n if (!text) {\n node = remove(node);\n continue;\n }\n\n textNode.data = text;\n\n prevText = textNode;\n } else if (node.nodeType === NodeTypes.Element) {\n if (isBlock(node) || node.nodeName === 'BR') {\n if (prevText) {\n prevText.data = prevText.data.replace(/ $/, '');\n }\n\n prevText = null;\n keepLeadingWs = false;\n } else if (isVoid(node) || isPre(node)) {\n // Avoid trimming space around non-block, non-BR void elements and inline PRE.\n prevText = null;\n keepLeadingWs = true;\n } else if (prevText) {\n // Drop protection if set previously.\n keepLeadingWs = false;\n }\n } else {\n node = remove(node);\n continue;\n }\n\n const nextNode = next(prev, node, isPre);\n prev = node;\n node = nextNode;\n }\n\n if (prevText) {\n prevText.data = prevText.data.replace(/ $/, '');\n if (!prevText.data) {\n remove(prevText);\n }\n }\n}\n\n/**\n * remove(node) removes the given node from the DOM and returns the\n * next node in the sequence.\n *\n * @param {Node} node\n * @return {Node} node\n */\nfunction remove(node: Node): Node {\n const nextNode: Node | null = node.nextSibling ?? node.parentNode;\n if (node.parentNode) {\n node.parentNode.removeChild(node);\n }\n return nextNode as Node;\n}\n\n/**\n * next(prev, current, isPre) returns the next node in the sequence, given the\n * current and previous nodes.\n *\n * @param {Node} prev\n * @param {Node} current\n * @param {Function} isPre\n * @return {Node}\n */\nfunction next(prev: Node | null, current: Node, isPre: (node: Node) => boolean): Node {\n if ((prev && prev.parentNode === current) || isPre(current)) {\n const nextNode: Node | null = current.nextSibling ?? current.parentNode;\n return nextNode as Node;\n }\n const nextNode: Node | null = current.firstChild ?? current.nextSibling ?? current.parentNode;\n return nextNode as Node;\n}\n\nexport default collapseWhitespace\n","/*\n * Set up window for Node.js\n */\n\nconst root: typeof globalThis = typeof window !== 'undefined' ? window : (typeof globalThis !== 'undefined' ? globalThis : {} as any)\n\n/*\n * Parsing HTML strings\n */\n\nfunction canParseHTMLNatively() {\n const Parser = typeof root.DOMParser !== 'undefined' ? root.DOMParser : undefined;\n let canParse = false;\n if (!Parser) return false;\n // Adapted from https://gist.github.com/1129031\n // Firefox/Opera/IE throw errors on unsupported types\n try {\n // WebKit returns null on unsupported types\n if (new Parser().parseFromString('', 'text/html')) {\n canParse = true;\n }\n } catch (e) { }\n return canParse;\n}\n\nexport class HTMLParser {\n // This will be assigned per environment below\n parseFromString(_input: string, _type?: string): Document {\n throw new Error('Not implemented')\n }\n}\n\nfunction createParser(): HTMLParser {\n const isBrowser =\n typeof window !== 'undefined' &&\n typeof document !== 'undefined' &&\n (typeof process === 'undefined' || (process as any).browser === true)\n\n if (typeof window !== 'undefined') {\n // Browser environment: use DOM API\n class HTMLParserBrowser extends HTMLParser {\n parseFromString(input: string, _type?: string): Document {\n const doc = document.implementation.createHTMLDocument('')\n doc.open()\n doc.write(input)\n doc.close()\n return doc\n }\n }\n return new HTMLParserBrowser()\n } else {\n const domino = require('@mixmark-io/domino') as {\n createDocument: (html: string) => Document\n }\n class HTMLParserNode extends HTMLParser {\n parseFromString(input: string, _type?: string): Document {\n return domino.createDocument(input);\n }\n }\n return new HTMLParserNode()\n }\n}\n\nexport const createHTMLParser = (): HTMLParser =>\n canParseHTMLNatively()\n ? new root.DOMParser()\n : createParser()\n","import collapseWhitespace from '@/collapse-whitespace'\nimport { createHTMLParser, HTMLParser } from '@/html-parser'\nimport { isBlock, isVoid } from '@/utilities'\n\ninterface RootNodeOptions {\n preformattedCode?: boolean\n}\n\nexport default function RootNode(\n input: string | Node,\n { preformattedCode }: RootNodeOptions\n): Element {\n let root: Element\n if (typeof input === 'string') {\n const doc = htmlParser().parseFromString(\n // DOM parsers arrange elements in the <head> and <body>.\n // Wrapping in a custom element ensures elements are reliably arranged in\n // a single element.\n '<x-turnish id=\"turnish-root\">' + input + '</x-turnish>',\n 'text/html'\n )\n root = doc.getElementById('turnish-root') as Element\n } else {\n root = input.cloneNode(true) as Element\n }\n collapseWhitespace({\n element: root,\n isBlock: isBlock,\n isVoid: isVoid,\n isPre: preformattedCode ? isPreOrCode : undefined\n })\n\n return root\n}\n\nlet _htmlParser: HTMLParser | undefined\nfunction htmlParser(): HTMLParser {\n return (_htmlParser ??= createHTMLParser())\n}\n\nfunction isPreOrCode(node: Node): boolean {\n return node.nodeName === 'PRE' || node.nodeName === 'CODE';\n}\n","import { defaultRules } from '@/default-rules'\nimport { Rules, Rule, RuleFilter } from '@/rules'\nimport { trimLeadingNewlines, trimTrailingNewlines } from '@/utilities'\nimport RootNode from '@/root-node'\nimport { ExtendedNode, NodeTypes } from '@/node';\nconst reduce = Array.prototype.reduce\n\ntype EscapeRule = [RegExp, string];\n\nconst escapes: EscapeRule[] = [\n [/\\\\/g, '\\\\\\\\'],\n [/\\*/g, '\\\\*'],\n [/_/g, '\\\\_'],\n [/^-/g, '\\\\-'],\n [/^\\+ /g, '\\\\+ '],\n [/^(=+)/g, '\\\\$1'],\n [/^(#{1,6}) /g, '\\\\$1 '],\n [/`/g, '\\\\`'],\n [/^~~~/g, '\\\\~~~'],\n [/\\[/g, '\\\\['],\n [/\\]/g, '\\\\]'],\n [/<([^>]*)>/g, '\\\\<$1\\\\>'],\n [/^>/g, '\\\\>'],\n [/^(\\d+)\\. /g, '$1\\\\. ']\n];\n\ntype Plugin = (service: Turnish) => void;\n\nexport interface TurnishOptions {\n rules?: { [key: string]: Rule };\n headingStyle?: 'setext' | 'atx';\n hr?: string;\n bulletListMarker?: '*' | '-' | '+';\n codeBlockStyle?: 'indented' | 'fenced';\n fence?: string;\n emDelimiter?: '_' | '*';\n strongDelimiter?: '**' | '__';\n linkStyle?: 'inlined' | 'referenced';\n linkReferenceStyle?: 'full' | 'collapsed' | 'shortcut';\n linkReferenceDeduplication?: 'none' | 'full';\n br?: string;\n preformattedCode?: boolean;\n htmlRetentionMode?: 'standard' | 'preserveAll' | 'markdownIncludingHtml';\n blankReplacement: (content: string, node: ExtendedNode) => string;\n keepReplacement: (content: string, node: ExtendedNode) => string;\n markdownIncludingHtmlReplacement: (content: string, node: ExtendedNode) => string;\n defaultReplacement: (content: string, node: ExtendedNode) => string;\n [key: string]: any;\n}\n\n\nconst defaultOptions: TurnishOptions = {\n rules: defaultRules,\n headingStyle: 'atx',\n hr: '---',\n bulletListMarker: '-',\n codeBlockStyle: 'fenced',\n fence: '```',\n emDelimiter: '*',\n strongDelimiter: '**',\n linkStyle: 'inlined',\n linkReferenceStyle: 'full',\n linkReferenceDeduplication: 'full',\n br: ' ',\n preformattedCode: false,\n htmlRetentionMode: 'standard',\n blankReplacement: (content: string, node: ExtendedNode): string => {\n return node.isBlock ? '\\n\\n' : '';\n },\n keepReplacement: (content: string, node: ExtendedNode): string => {\n return node.isBlock ? '\\n\\n' + node.outerHTML + '\\n\\n' : node.outerHTML;\n },\n markdownIncludingHtmlReplacement: (content: string, node: ExtendedNode): string => {\n const tagName = node.nodeName.toLowerCase();\n\n let attributes = '';\n if (node.attributes && node.attributes.length > 0) {\n const attrs: string[] = [];\n for (let i = 0; i < node.attributes.length; i++) {\n const attr = node.attributes[i];\n attrs.push(`${attr.name}=\"${attr.value}\"`);\n }\n attributes = ' ' + attrs.join(' ');\n }\n\n attributes += ' markdown=\"1\"';\n\n const openTag = `<${tagName}${attributes}>`;\n const closeTag = `</${tagName}>`;\n\n const trimmedContent = content.trim();\n const html = openTag + '\\n' + trimmedContent + '\\n' + closeTag;\n\n return node.isBlock ? '\\n\\n' + html + '\\n\\n' : html;\n },\n defaultReplacement: function (content: string, node: ExtendedNode): string {\n return node.isBlock ? '\\n\\n' + content + '\\n\\n' : content;\n }\n};\n\nexport default class Turnish {\n options: TurnishOptions;\n rules: Rules;\n\n constructor(options?: Partial<TurnishOptions>) {\n this.options = Object.assign({}, defaultOptions, options);\n this.rules = new Rules(this.options);\n }\n\n /**\n * The entry point for converting a string or DOM node to Markdown\n * @public\n * @param {InputType} input The string or DOM node to convert\n * @returns A Markdown representation of the input\n * @type string\n */\n render(input: InputType): string {\n if (!canConvert(input)) {\n throw new TypeError(\n input + ' is not a string, or an element/document/fragment node.'\n );\n }\n if (input === '') {\n return '';\n }\n const output = this.process(RootNode(input, this.options));\n return this.postProcess(output);\n }\n\n /**\n * Add one or more plugins\n * @public\n * @param {Plugin|Plugin[]} plugin The plugin or array of plugins to add\n * @returns The Turnish instance for chaining\n * @type Object\n */\n use(plugin: Plugin | Plugin[]): Turnish {\n if (Array.isArray(plugin)) {\n for (let i = 0; i < plugin.length; i++) this.use(plugin[i]);\n } else if (typeof plugin === 'function') {\n plugin(this);\n } else {\n throw new TypeError('plugin must be a Function or an Array of Functions');\n }\n return this;\n }\n\n /**\n * Adds a rule\n * @public\n * @param {string} key The unique key of the rule\n * @param {Object} rule The rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n addRule(key: string, rule: Rule): Turnish {\n this.rules.add(key, rule);\n return this;\n }\n\n /**\n * Keep a node (as HTML) that matches the filter\n * @public\n * @param {RuleFilter} filter The unique key of the rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n keep(filter: RuleFilter): Turnish {\n this.rules.keep(filter);\n return this;\n }\n\n /**\n * Remove a node that matches the filter\n * @public\n * @param {string|Array|Function} filter The unique key of the rule\n * @returns The Turnish instance for chaining\n * @type Object\n */\n remove(filter: RuleFilter): Turnish {\n this.rules.remove(filter);\n return this;\n }\n\n /**\n * Escapes Markdown syntax\n * @public\n * @param {string} string The string to escape\n * @returns A string with Markdown syntax escaped\n * @type string\n */\n escape(string: string): string {\n return escapes.reduce(function (accumulator: string, escape: EscapeRule) {\n return accumulator.replace(escape[0], escape[1]);\n }, string);\n }\n\n\n /**\n * Reduces a DOM node down to its Markdown string equivalent\n * @private\n * @param {HTMLElement} parentNode The node to convert\n * @returns A Markdown representation of the node\n * @type string\n */\n process(this: Turnish, parentNode: Node): string {\n return Array.from(parentNode.childNodes).reduce((output, node) => {\n const extended = ExtendedNode(node, this.options);\n let replacement = '';\n if (extended.nodeType === NodeTypes.Text) {\n const value = extended.nodeValue ?? ''; // ensure a string\n replacement = extended.isCode ? value : this.escape(value);\n } else if (extended.nodeType === NodeTypes.Element) {\n replacement = this.replacementForNode(extended);\n }\n return join(output, replacement);\n }, '');\n }\n\n /**\n * Appends strings as each rule requires and trims the output\n * @private\n * @param {string} output The conversion output\n * @returns A trimmed version of the ouput\n * @type string\n */\n postProcess(output: string): string {\n for (const rule of this.rules.array) {\n if (rule.append) {\n output = join(output, rule.append(this.options))\n }\n }\n return output\n .replace(/^[\\t\\r\\n]+/, '')\n .replace(/[\\t\\r\\n\\s]+$/, '')\n }\n\n\n /**\n * Converts an element node to its Markdown equivalent\n * @private\n * @param {ExtendedNode} node The node to convert\n * @returns A Markdown representation of the node\n * @type string\n */\n replacementForNode(node: ExtendedNode) {\n const rule = this.rules.forNode(node)\n let content = this.process(node)\n const whitespace = node.flankingWhitespace\n if (whitespace.leading || whitespace.trailing) {\n content = content.trim()\n }\n return (\n whitespace.leading +\n rule.replacement(content, node, this.options) +\n whitespace.trailing\n )\n }\n}\n\n/**\n * Joins replacement to the current output with appropriate number of new lines\n * @private\n * @param {string} output The current conversion output\n * @param {string} replacement The string to append to the output\n * @returns Joined output\n * @type string\n */\nfunction join(output: string, replacement: string): string {\n const s1 = trimTrailingNewlines(output)\n const s2 = trimLeadingNewlines(replacement)\n const nls = Math.max(output.length - s1.length, replacement.length - s2.length)\n const separator = '\\n\\n'.substring(0, nls)\n\n return s1 + separator + s2\n}\n\n/**\n * Determines whether an input can be converted\n * @private\n * @param {string|HTMLElement} input Describe this parameter\n * @returns Describe what it returns\n * @type string|Object|Array|Boolean|Number\n */\ntype InputType = string | HTMLElement | Document | DocumentFragment;\nfunction canConvert(input: any): input is InputType {\n return (\n input != null && (\n typeof input === 'string' ||\n (input.nodeType && (\n input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11\n ))\n )\n );\n}\n"],"names":["ExtendedNode","node","options","extended","isBlock","isBlank","flankingWhitespace","isVoid","isMeaningfulWhenBlank","hasVoid","hasMeaningfulWhenBlank","extendedNode","edges","edgeWhitespace","isFlankedByWhitespace","string","m","side","sibling","regExp","isFlanked","NodeTypes","repeat","character","count","trimLeadingNewlines","trimTrailingNewlines","indexEnd","trimNewlines","blockElements","is","voidElements","has","meaningfulWhenBlankElements","standardMarkdownElements","tagNames","tagName","sanitizeWhitespace","sanitizedLinkContent","content","sanitizedLinkTitle","defaultRules","_content","_node","hLevel","underline","parent","prefix","start","index","isParagraph","codeElem","language","code","fenceChar","fenceSize","fenceInCodeRegex","match","fence","sanitizedContent","href","title","titleAttr","referenceLinkRule","self","referenceKey","replacement","reference","id","existingKey","references","hasSiblings","isCodeBlock","trimmed","extraSpace","delimiter","matches","altAttr","alt","src","titlePart","Rules","key","rule","filter","findRule","nodeName","attrName","fn","i","rules","filterValue","collapseWhitespace","element","isPre","prevText","keepLeadingWs","prev","next","textNode","text","remove","nextNode","current","root","canParseHTMLNatively","Parser","canParse","HTMLParser","_input","_type","createParser","HTMLParserBrowser","input","doc","domino","HTMLParserNode","createHTMLParser","RootNode","preformattedCode","htmlParser","isPreOrCode","_htmlParser","escapes","defaultOptions","attributes","attrs","attr","openTag","closeTag","trimmedContent","html","Turnish","canConvert","output","plugin","accumulator","escape","parentNode","value","join","whitespace","s1","s2","nls","separator"],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
var Turnish=(function(){"use strict";function B(t,e){const n=t;return n.isBlock=g(n),n.isCode=n.nodeName==="CODE"||n.parentNode?.isCode,n.isBlank=P(n),n.flankingWhitespace=H(n,e),n}function P(t){return!w(t)&&!U(t)&&/^\s*$/i.test(t.textContent||"")&&!$(t)&&!z(t)}function H(t,e){const n=t;if(n.isBlock||e.preformattedCode&&n.isCode)return{leading:"",trailing:""};const r=_(t.textContent||"");return r.leadingAscii&&A("left",t,e)&&(r.leading=r.leadingNonAscii),r.trailingAscii&&A("right",t,e)&&(r.trailing=r.trailingNonAscii),{leading:r.leading,trailing:r.trailing}}function _(t){const e=t.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);return e?{leading:e[1],leadingAscii:e[2],leadingNonAscii:e[3],trailing:e[4],trailingNonAscii:e[5],trailingAscii:e[6]}:{leading:"",leadingAscii:"",leadingNonAscii:"",trailing:"",trailingNonAscii:"",trailingAscii:""}}function A(t,e,n){let r,i,l;return t==="left"?(r=e.previousElementSibling,i=/ $/):(r=e.nextElementSibling,i=/^ /),r&&(r.nodeType===3?l=i.test(r.nodeValue||""):n.preformattedCode&&r.nodeName==="CODE"?l=!1:r.nodeType===1&&!g(r)&&(l=i.test(r.textContent||""))),l||!1}const m={Element:1,Text:3,CDATASection:4};function p(t,e){return Array(e+1).join(t)}function y(t){return t.replace(/^\n*/,"")}function C(t){let e=t.length;for(;e>0&&t[e-1]===`
|
|
2
|
+
`;)e--;return t.substring(0,e)}function b(t){return C(y(t))}const v=["ADDRESS","ARTICLE","ASIDE","AUDIO","BLOCKQUOTE","BODY","CANVAS","CENTER","DD","DIR","DIV","DL","DT","FIELDSET","FIGCAPTION","FIGURE","FOOTER","FORM","FRAMESET","H1","H2","H3","H4","H5","H6","HEADER","HGROUP","HR","HTML","ISINDEX","LI","MAIN","MENU","NAV","NOFRAMES","NOSCRIPT","OL","OUTPUT","P","PRE","SECTION","TABLE","TBODY","TD","TFOOT","TH","THEAD","TR","UL"];function g(t){return N(t,v)}const D=["AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR"];function w(t){return N(t,D)}function $(t){return O(t,D)}const x=["A","TABLE","THEAD","TBODY","TFOOT","TH","TD","IFRAME","SCRIPT","AUDIO","VIDEO"],F=["P","BR","H1","H2","H3","H4","H5","H6","BLOCKQUOTE","UL","OL","LI","PRE","CODE","HR","A","EM","I","STRONG","B","IMG","DIV","SPAN","TABLE","THEAD","TBODY","TR","TH","TD"];function U(t){return N(t,x)}function z(t){return O(t,x)}function N(t,e){return e.indexOf(t.nodeName)>=0}function O(t,e){return e.some(function(n){return t.nodeType!==m.Element?!1:t.getElementsByTagName(n).length})}function S(t){return t?t.replace(/(\n+\s*)+/g,`
|
|
3
|
+
`):""}function V(t){return S(t).replace(/[\t\r\n]+/g," ").replace(/ {2,}/g," ").replace(/([()])/g,"\\$1").trim()}function h(t){return S(t).replace(/[\t\r\n]+/g," ")}const f={};f.paragraph={filter:"p",replacement:function(t){return`
|
|
4
|
+
|
|
5
|
+
`+t+`
|
|
6
|
+
|
|
7
|
+
`}},f.lineBreak={filter:"br",replacement:function(t,e,n){return n.br+`
|
|
8
|
+
`}},f.heading={filter:["h1","h2","h3","h4","h5","h6"],replacement:function(t,e,n){const r=Number(e.nodeName.charAt(1));if(n.headingStyle==="setext"&&r<3){const i=p(r===1?"=":"-",t.length);return`
|
|
9
|
+
|
|
10
|
+
`+t+`
|
|
11
|
+
`+i+`
|
|
12
|
+
|
|
13
|
+
`}else return`
|
|
14
|
+
|
|
15
|
+
`+p("#",r)+" "+t+`
|
|
16
|
+
|
|
17
|
+
`}},f.blockquote={filter:"blockquote",replacement:function(t){return t=b(t).replace(/^/gm,"> "),`
|
|
18
|
+
|
|
19
|
+
`+t+`
|
|
20
|
+
|
|
21
|
+
`}},f.list={filter:["ul","ol"],replacement:function(t,e){const n=e.parentNode;return n.nodeName==="LI"&&n.lastElementChild===e?`
|
|
22
|
+
`+t:`
|
|
23
|
+
|
|
24
|
+
`+t+`
|
|
25
|
+
|
|
26
|
+
`}},f.listItem={filter:"li",replacement:function(t,e,n){let r=n.bulletListMarker+" ";const i=e.parentNode;if(i.nodeName==="OL"){const a=i.getAttribute("start"),o=Array.prototype.indexOf.call(i.children,e);r=(a?Number(a)+o:o+1)+". "}const l=/\n$/.test(t);return t=b(t)+(l?`
|
|
27
|
+
`:""),t=t.replace(/\n/gm,`
|
|
28
|
+
`+" ".repeat(r.length)),r+t+(e.nextSibling?`
|
|
29
|
+
`:"")}},f.indentedCodeBlock={filter:function(t,e){return!!(e&&e.codeBlockStyle==="indented"&&t.nodeName==="PRE"&&t.firstChild&&t.firstChild.nodeName==="CODE")},replacement:function(t,e){return!e||!e.firstChild?"":`
|
|
30
|
+
|
|
31
|
+
`+e.firstChild.textContent.replace(/\n/g,`
|
|
32
|
+
`)+`
|
|
33
|
+
|
|
34
|
+
`}},f.fencedCodeBlock={filter:function(t,e){return!!(e&&e.codeBlockStyle==="fenced"&&t.nodeName==="PRE"&&t.firstChild&&t.firstChild.nodeName==="CODE")},replacement:function(t,e,n){if(!e.firstChild)return"";const r=e.firstChild,l=((r.getAttribute("class")||"").match(/language-(\S+)/)||[null,""])[1],a=r.textContent||"",o=n.fence?.charAt(0)||"`";let s=3;const u=new RegExp("^"+o+"{3,}","gm");let c;for(;c=u.exec(a);)c[0].length>=s&&(s=c[0].length+1);const d=p(o,s);return`
|
|
35
|
+
|
|
36
|
+
`+d+l+`
|
|
37
|
+
`+a.replace(/\n$/,"")+`
|
|
38
|
+
`+d+`
|
|
39
|
+
|
|
40
|
+
`}},f.horizontalRule={filter:"hr",replacement:function(t,e,n){return`
|
|
41
|
+
|
|
42
|
+
`+n.hr+`
|
|
43
|
+
|
|
44
|
+
`}},f.inlineLink={filter:function(t,e){return!!(e?.linkStyle==="inlined"&&t.nodeName==="A"&&t.getAttribute("href"))},replacement:function(t,e){const n=V(t);let r=e.getAttribute("href")?.replace(/([()])/g,"\\$1"),i;const l=e.getAttribute("title");return l?i=' "'+h(l).replace(/"/g,'\\"')+'"':i="","["+n+"]("+r+i+")"}};const T={filter:function(t,e){return!!(e&&e.linkStyle==="referenced"&&t.nodeName==="A"&&t.getAttribute("href"))},replacement:function(t,e,n){const r=T,i=e.getAttribute("href");let l;const a=e.getAttribute("title");a?l=' "'+h(a)+'"':l="";const o=i+l;let s,u;switch(n.linkReferenceStyle){case"collapsed":s="["+t+"][]",u="["+t+"]: "+o;break;case"shortcut":s="["+t+"]",u="["+t+"]: "+o;break;default:{let c;const d=r.urlReferenceIdMap.get(o);n.linkReferenceDeduplication==="full"&&d?(c=d,u="["+c+"]: "+i+l):(c=r.references.length+1,r.urlReferenceIdMap.set(o,c),u="["+c+"]: "+i+l,r.references.push(u)),s="["+t+"]["+c+"]";break}}return n.linkReferenceStyle!=="full"&&(n.linkReferenceDeduplication==="full"?r.urlReferenceIdMap.has(o)||(r.urlReferenceIdMap.set(o,1),r.references.push(u)):r.references.push(u)),s},references:[],urlReferenceIdMap:new Map,append:()=>{const t=T;let e="";return t.references&&t.references.length&&(e=`
|
|
45
|
+
|
|
46
|
+
`+t.references.join(`
|
|
47
|
+
`)+`
|
|
48
|
+
|
|
49
|
+
`,t.references=[],t.urlReferenceIdMap=new Map),e}};f.referenceLink=T,f.emphasis={filter:["em","i"],replacement:(t,e,n)=>(t=t.trim(),t?n.emDelimiter+t+n.emDelimiter:"")},f.strong={filter:["strong","b"],replacement:(t,e,n)=>(t=t.trim(),t?n.strongDelimiter+t+n.strongDelimiter:"")},f.code={filter:t=>{const e=t.previousSibling||t.nextSibling,r=t.parentNode.nodeName==="PRE"&&!e;return t.nodeName==="CODE"&&!r},replacement:t=>{const e=t.replace(/\r?\n|\r/g," "),n=/^`|^ .*?[^ ].* $|`$/.test(e)?" ":"";let r="`";const i=e.match(/`+/gm)||[];for(;i.includes(r);)r=r+"`";return r+n+e+n+r}},f.image={filter:"img",replacement:function(t,e){const n=e.getAttribute("alt"),r=n?h(n):"",i=e.getAttribute("src")||"",l=e.getAttribute("title"),a=l?h(l):"",o=a?' "'+a+'"':"";return i?"":""}};class W{options;_keep;_remove;blankRule;keepReplacement;markdownIncludingHtmlReplacement;defaultRule;array;constructor(e){this.options=e,this._keep=[],this._remove=[],this.blankRule={replacement:e.blankReplacement},this.keepReplacement=e.keepReplacement,this.markdownIncludingHtmlReplacement=e.markdownIncludingHtmlReplacement,this.defaultRule={replacement:e.defaultReplacement},this.array=[];for(const n in e.rules)this.array.push(e.rules[n])}add(e,n){this.array.unshift(n)}keep(e){this._keep.unshift({filter:e,replacement:this.keepReplacement})}remove(e){this._remove.unshift({filter:e,replacement:function(){return""}})}forNode(e){if(e.isBlank)return this.blankRule;if(this.options.htmlRetentionMode==="preserveAll"&&this.isUnsupportedElement(e))return{replacement:this.keepReplacement};if(this.options.htmlRetentionMode==="markdownIncludingHtml"&&this.isUnsupportedElement(e))return{replacement:this.markdownIncludingHtmlReplacement};let n;return(n=R(this.array,e,this.options))||(n=R(this._keep,e,this.options))||(n=R(this._remove,e,this.options))?n:this.defaultRule}isUnsupportedElement(e){const n=e.nodeName;if(n==="PRE"&&e.firstChild&&e.firstChild.nodeName==="CODE"){const r=e.firstChild;if(r.attributes&&r.attributes.length>0){for(let i=0;i<r.attributes.length;i++)if(r.attributes[i].name.toLowerCase()!=="class")return!0}}if(e.attributes&&e.attributes.length>0)switch(n){case"IMG":for(let i=0;i<e.attributes.length;i++){const l=e.attributes[i].name.toLowerCase();if(l!=="src"&&l!=="alt"&&l!=="title")return!0}return!1;case"A":for(let i=0;i<e.attributes.length;i++){const l=e.attributes[i].name.toLowerCase();if(l!=="href"&&l!=="title")return!0}return!1;case"CODE":const r=e.parentNode;if(r&&r.nodeName==="PRE"){for(let i=0;i<e.attributes.length;i++)if(e.attributes[i].name.toLowerCase()!=="class")return!0;return!1}default:return!0}return F.indexOf(n)===-1}forEach(e){for(let n=0;n<this.array.length;n++)e(this.array[n],n)}}function R(t,e,n){for(let r=0;r<t.length;r++){const i=t[r];if(G(i,e,n))return i}}function G(t,e,n){const r=t.filter;if(typeof r=="string"){if(r===e.nodeName.toLowerCase())return!0}else if(Array.isArray(r)){if(r.indexOf(e.nodeName.toLowerCase())>-1)return!0}else if(typeof r=="function"){if(r(e,n))return!0}else throw new TypeError("`filter` needs to be a string, array, or function");return!1}function K(t){const e=t.element,n=t.isBlock,r=t.isVoid,i=t.isPre||function(u){return u.nodeName==="PRE"};if(!e.firstChild||i(e))return;let l=null,a=!1,o=null,s=L(o,e,i);for(;s!==e;){if(s.nodeType===m.Text||s.nodeType===m.CDATASection){const c=s;let d=c.data.replace(/[ \r\n\t]+/g," ");if((!l||/ $/.test(l.data))&&!a&&d[0]===" "&&(d=d.substr(1)),!d){s=E(s);continue}c.data=d,l=c}else if(s.nodeType===m.Element)n(s)||s.nodeName==="BR"?(l&&(l.data=l.data.replace(/ $/,"")),l=null,a=!1):r(s)||i(s)?(l=null,a=!0):l&&(a=!1);else{s=E(s);continue}const u=L(o,s,i);o=s,s=u}l&&(l.data=l.data.replace(/ $/,""),l.data||E(l))}function E(t){const e=t.nextSibling??t.parentNode;return t.parentNode&&t.parentNode.removeChild(t),e}function L(t,e,n){return t&&t.parentNode===e||n(e)?e.nextSibling??e.parentNode:e.firstChild??e.nextSibling??e.parentNode}const k=typeof window<"u"?window:typeof globalThis<"u"?globalThis:{};function j(){const t=typeof k.DOMParser<"u"?k.DOMParser:void 0;let e=!1;if(!t)return!1;try{new t().parseFromString("","text/html")&&(e=!0)}catch{}return e}class M{parseFromString(e,n){throw new Error("Not implemented")}}function Y(){if(typeof window<"u"&&typeof document<"u"&&(typeof process>"u"||process.browser),typeof window<"u"){class t extends M{parseFromString(n,r){const i=document.implementation.createHTMLDocument("");return i.open(),i.write(n),i.close(),i}}return new t}else{const t=require("@mixmark-io/domino");class e extends M{parseFromString(r,i){return t.createDocument(r)}}return new e}}const q=()=>j()?new k.DOMParser:Y();function Q(t,{preformattedCode:e}){let n;return typeof t=="string"?n=J().parseFromString('<x-turnish id="turnish-root">'+t+"</x-turnish>","text/html").getElementById("turnish-root"):n=t.cloneNode(!0),K({element:n,isBlock:g,isVoid:w,isPre:e?Z:void 0}),n}let X;function J(){return X??=q()}function Z(t){return t.nodeName==="PRE"||t.nodeName==="CODE"}const ee=[[/\\/g,"\\\\"],[/\*/g,"\\*"],[/_/g,"\\_"],[/^-/g,"\\-"],[/^\+ /g,"\\+ "],[/^(=+)/g,"\\$1"],[/^(#{1,6}) /g,"\\$1 "],[/`/g,"\\`"],[/^~~~/g,"\\~~~"],[/\[/g,"\\["],[/\]/g,"\\]"],[/<([^>]*)>/g,"\\<$1\\>"],[/^>/g,"\\>"],[/^(\d+)\. /g,"$1\\. "]],te={rules:f,headingStyle:"atx",hr:"---",bulletListMarker:"-",codeBlockStyle:"fenced",fence:"```",emDelimiter:"*",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",linkReferenceDeduplication:"full",br:" ",preformattedCode:!1,htmlRetentionMode:"standard",blankReplacement:(t,e)=>e.isBlock?`
|
|
50
|
+
|
|
51
|
+
`:"",keepReplacement:(t,e)=>e.isBlock?`
|
|
52
|
+
|
|
53
|
+
`+e.outerHTML+`
|
|
54
|
+
|
|
55
|
+
`:e.outerHTML,markdownIncludingHtmlReplacement:(t,e)=>{const n=e.nodeName.toLowerCase();let r="";if(e.attributes&&e.attributes.length>0){const s=[];for(let u=0;u<e.attributes.length;u++){const c=e.attributes[u];s.push(`${c.name}="${c.value}"`)}r=" "+s.join(" ")}r+=' markdown="1"';const i=`<${n}${r}>`,l=`</${n}>`,a=t.trim(),o=i+`
|
|
56
|
+
`+a+`
|
|
57
|
+
`+l;return e.isBlock?`
|
|
58
|
+
|
|
59
|
+
`+o+`
|
|
60
|
+
|
|
61
|
+
`:o},defaultReplacement:function(t,e){return e.isBlock?`
|
|
62
|
+
|
|
63
|
+
`+t+`
|
|
64
|
+
|
|
65
|
+
`:t}};class ne{options;rules;constructor(e){this.options=Object.assign({},te,e),this.rules=new W(this.options)}render(e){if(!re(e))throw new TypeError(e+" is not a string, or an element/document/fragment node.");if(e==="")return"";const n=this.process(Q(e,this.options));return this.postProcess(n)}use(e){if(Array.isArray(e))for(let n=0;n<e.length;n++)this.use(e[n]);else if(typeof e=="function")e(this);else throw new TypeError("plugin must be a Function or an Array of Functions");return this}addRule(e,n){return this.rules.add(e,n),this}keep(e){return this.rules.keep(e),this}remove(e){return this.rules.remove(e),this}escape(e){return ee.reduce(function(n,r){return n.replace(r[0],r[1])},e)}process(e){return Array.from(e.childNodes).reduce((n,r)=>{const i=B(r,this.options);let l="";if(i.nodeType===m.Text){const a=i.nodeValue??"";l=i.isCode?a:this.escape(a)}else i.nodeType===m.Element&&(l=this.replacementForNode(i));return I(n,l)},"")}postProcess(e){for(const n of this.rules.array)n.append&&(e=I(e,n.append(this.options)));return e.replace(/^[\t\r\n]+/,"").replace(/[\t\r\n\s]+$/,"")}replacementForNode(e){const n=this.rules.forNode(e);let r=this.process(e);const i=e.flankingWhitespace;return(i.leading||i.trailing)&&(r=r.trim()),i.leading+n.replacement(r,e,this.options)+i.trailing}}function I(t,e){const n=C(t),r=y(e),i=Math.max(t.length-n.length,e.length-r.length),l=`
|
|
66
|
+
|
|
67
|
+
`.substring(0,i);return n+l+r}function re(t){return t!=null&&(typeof t=="string"||t.nodeType&&(t.nodeType===1||t.nodeType===9||t.nodeType===11))}return ne})();
|
|
68
|
+
//# sourceMappingURL=index.iife.js.map
|