@webpro/remark-wrap-prose 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/index.js +31 -8
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ level. Tables, code, and other non-prose blocks are left untouched. Wide CJK
|
|
|
8
8
|
characters and emoji count as two columns. Words wider than the limit are never
|
|
9
9
|
broken mid-word.
|
|
10
10
|
|
|
11
|
+
Inline code stays intact and retains its whitespace, even when a code span exceeds the limit.
|
|
12
|
+
|
|
11
13
|
## Install
|
|
12
14
|
|
|
13
15
|
```sh
|
package/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fastStringTruncatedWidth from 'fast-string-truncated-width';
|
|
2
|
+
import { fromMarkdown } from 'mdast-util-from-markdown';
|
|
2
3
|
import { editorConfigWidth } from './editorconfig.js';
|
|
3
4
|
|
|
4
5
|
const DEFAULT_WIDTH = 80;
|
|
@@ -24,24 +25,42 @@ function displayWidth(value) {
|
|
|
24
25
|
// ASCII soft-wrap whitespace (space, tab, newline, form feed, vertical tab).
|
|
25
26
|
// Unicode spaces (no-break U+00A0, narrow no-break U+202F, …) are intentional
|
|
26
27
|
// content and are left untouched, so they survive reflow.
|
|
27
|
-
const SOFT_WHITESPACE = /[ \t\n\r\f\v]
|
|
28
|
+
const SOFT_WHITESPACE = /[ \t\n\r\f\v]+/g;
|
|
29
|
+
|
|
30
|
+
function* proseWords(text, parseOptions) {
|
|
31
|
+
const codeSpans = [];
|
|
32
|
+
function visit(node) {
|
|
33
|
+
if (node.type === 'inlineCode') codeSpans.push(node.position);
|
|
34
|
+
else if (node.children) node.children.forEach(visit);
|
|
35
|
+
}
|
|
36
|
+
if (text.includes('`')) visit(fromMarkdown(text, parseOptions));
|
|
37
|
+
|
|
38
|
+
let span = 0;
|
|
39
|
+
let start = 0;
|
|
40
|
+
for (const match of text.matchAll(SOFT_WHITESPACE)) {
|
|
41
|
+
while (span < codeSpans.length && codeSpans[span].end.offset <= match.index) span++;
|
|
42
|
+
if (span < codeSpans.length && codeSpans[span].start.offset <= match.index) continue;
|
|
43
|
+
yield text.slice(start, match.index);
|
|
44
|
+
start = match.index + match[0].length;
|
|
45
|
+
}
|
|
46
|
+
yield text.slice(start);
|
|
47
|
+
}
|
|
28
48
|
|
|
29
49
|
/**
|
|
30
|
-
* Greedily wrap words to a maximum display width, collapsing only ASCII
|
|
31
|
-
* soft-wrap whitespace. Words wider than the limit are kept intact (never
|
|
32
|
-
* broken mid-word).
|
|
50
|
+
* Greedily wrap words to a maximum display width, collapsing only ASCII soft-wrap whitespace outside inline code. Words and code spans wider than the limit are kept intact.
|
|
33
51
|
*
|
|
34
52
|
* @param {string} text
|
|
35
53
|
* @param {number} width
|
|
54
|
+
* @param {import('mdast-util-from-markdown').Options} parseOptions
|
|
36
55
|
* @returns {string}
|
|
37
56
|
*/
|
|
38
|
-
function fill(text, width) {
|
|
57
|
+
function fill(text, width, parseOptions) {
|
|
39
58
|
/** @type {Array<string>} */
|
|
40
59
|
const lines = [];
|
|
41
60
|
let line = '';
|
|
42
61
|
let lineWidth = 0;
|
|
43
62
|
|
|
44
|
-
for (const word of text
|
|
63
|
+
for (const word of proseWords(text, parseOptions)) {
|
|
45
64
|
if (!word) continue;
|
|
46
65
|
const wordWidth = displayWidth(word);
|
|
47
66
|
if (line === '') {
|
|
@@ -93,15 +112,19 @@ export default function remarkWrapProse(options = {}) {
|
|
|
93
112
|
exit();
|
|
94
113
|
|
|
95
114
|
const available = Math.max(1, width - (info.lineShift || 0));
|
|
115
|
+
const parseOptions = {
|
|
116
|
+
extensions: data.micromarkExtensions,
|
|
117
|
+
mdastExtensions: data.fromMarkdownExtensions
|
|
118
|
+
};
|
|
96
119
|
|
|
97
120
|
const first = node.children[0];
|
|
98
121
|
if (first?.type === 'gfmAlert') {
|
|
99
122
|
const marker = value.slice(0, first.value.length);
|
|
100
|
-
const body = fill(value.slice(first.value.length), available);
|
|
123
|
+
const body = fill(value.slice(first.value.length), available, parseOptions);
|
|
101
124
|
return body ? marker + '\n' + body : marker;
|
|
102
125
|
}
|
|
103
126
|
|
|
104
|
-
return fill(value, available);
|
|
127
|
+
return fill(value, available, parseOptions);
|
|
105
128
|
}
|
|
106
129
|
}
|
|
107
130
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpro/remark-wrap-prose",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Remark plugin to wrap prose to a maximum line width",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"unified",
|
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"fast-string-truncated-width": "^3.0.3"
|
|
41
|
+
"fast-string-truncated-width": "^3.0.3",
|
|
42
|
+
"mdast-util-from-markdown": "^2.1.0"
|
|
42
43
|
},
|
|
43
44
|
"devDependencies": {
|
|
44
|
-
"@types/node": "^
|
|
45
|
+
"@types/node": "^26.6.6",
|
|
45
46
|
"remark": "^15.0.1",
|
|
46
47
|
"remark-directive": "^4.0.0"
|
|
47
48
|
},
|