wrap-ansi 3.0.0 → 5.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/index.js +77 -78
- package/package.json +11 -12
- package/readme.md +19 -0
package/index.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
'use strict';
|
2
2
|
const stringWidth = require('string-width');
|
3
3
|
const stripAnsi = require('strip-ansi');
|
4
|
+
const ansiStyles = require('ansi-styles');
|
4
5
|
|
5
6
|
const ESCAPES = new Set([
|
6
7
|
'\u001B',
|
@@ -9,63 +10,33 @@ const ESCAPES = new Set([
|
|
9
10
|
|
10
11
|
const END_CODE = 39;
|
11
12
|
|
12
|
-
const ESCAPE_CODES = new Map([
|
13
|
-
[0, 0],
|
14
|
-
[1, 22],
|
15
|
-
[2, 22],
|
16
|
-
[3, 23],
|
17
|
-
[4, 24],
|
18
|
-
[7, 27],
|
19
|
-
[8, 28],
|
20
|
-
[9, 29],
|
21
|
-
[30, 39],
|
22
|
-
[31, 39],
|
23
|
-
[32, 39],
|
24
|
-
[33, 39],
|
25
|
-
[34, 39],
|
26
|
-
[35, 39],
|
27
|
-
[36, 39],
|
28
|
-
[37, 39],
|
29
|
-
[90, 39],
|
30
|
-
[40, 49],
|
31
|
-
[41, 49],
|
32
|
-
[42, 49],
|
33
|
-
[43, 49],
|
34
|
-
[44, 49],
|
35
|
-
[45, 49],
|
36
|
-
[46, 49],
|
37
|
-
[47, 49]
|
38
|
-
]);
|
39
|
-
|
40
13
|
const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`;
|
41
14
|
|
42
15
|
// Calculate the length of words split on ' ', ignoring
|
43
16
|
// the extra characters added by ansi escape codes
|
44
|
-
const wordLengths =
|
17
|
+
const wordLengths = string => string.split(' ').map(character => stringWidth(character));
|
45
18
|
|
46
19
|
// Wrap a long word across multiple rows
|
47
20
|
// Ansi escape codes do not count towards length
|
48
|
-
const wrapWord = (rows, word,
|
49
|
-
const
|
21
|
+
const wrapWord = (rows, word, columns) => {
|
22
|
+
const characters = [...word];
|
50
23
|
|
51
24
|
let insideEscape = false;
|
52
25
|
let visible = stringWidth(stripAnsi(rows[rows.length - 1]));
|
53
26
|
|
54
|
-
for (const
|
55
|
-
const
|
56
|
-
const char = item[1];
|
57
|
-
const charLength = stringWidth(char);
|
27
|
+
for (const [index, character] of characters.entries()) {
|
28
|
+
const characterLength = stringWidth(character);
|
58
29
|
|
59
|
-
if (visible +
|
60
|
-
rows[rows.length - 1] +=
|
30
|
+
if (visible + characterLength <= columns) {
|
31
|
+
rows[rows.length - 1] += character;
|
61
32
|
} else {
|
62
|
-
rows.push(
|
33
|
+
rows.push(character);
|
63
34
|
visible = 0;
|
64
35
|
}
|
65
36
|
|
66
|
-
if (ESCAPES.has(
|
37
|
+
if (ESCAPES.has(character)) {
|
67
38
|
insideEscape = true;
|
68
|
-
} else if (insideEscape &&
|
39
|
+
} else if (insideEscape && character === 'm') {
|
69
40
|
insideEscape = false;
|
70
41
|
continue;
|
71
42
|
}
|
@@ -74,9 +45,9 @@ const wrapWord = (rows, word, cols) => {
|
|
74
45
|
continue;
|
75
46
|
}
|
76
47
|
|
77
|
-
visible +=
|
48
|
+
visible += characterLength;
|
78
49
|
|
79
|
-
if (visible ===
|
50
|
+
if (visible === columns && index < characters.length - 1) {
|
80
51
|
rows.push('');
|
81
52
|
visible = 0;
|
82
53
|
}
|
@@ -89,88 +60,116 @@ const wrapWord = (rows, word, cols) => {
|
|
89
60
|
}
|
90
61
|
};
|
91
62
|
|
63
|
+
// Trims spaces from a string ignoring invisible sequences
|
64
|
+
const stringVisibleTrimSpacesRight = str => {
|
65
|
+
const words = str.split(' ');
|
66
|
+
let last = words.length;
|
67
|
+
|
68
|
+
while (last > 0) {
|
69
|
+
if (stringWidth(words[last - 1]) > 0) {
|
70
|
+
break;
|
71
|
+
}
|
72
|
+
|
73
|
+
last--;
|
74
|
+
}
|
75
|
+
|
76
|
+
if (last === words.length) {
|
77
|
+
return str;
|
78
|
+
}
|
79
|
+
|
80
|
+
return words.slice(0, last).join(' ') + words.slice(last).join('');
|
81
|
+
};
|
82
|
+
|
92
83
|
// The wrap-ansi module can be invoked
|
93
84
|
// in either 'hard' or 'soft' wrap mode
|
94
85
|
//
|
95
86
|
// 'hard' will never allow a string to take up more
|
96
|
-
// than
|
87
|
+
// than columns characters
|
97
88
|
//
|
98
89
|
// 'soft' allows long words to expand past the column length
|
99
|
-
const exec = (
|
100
|
-
|
90
|
+
const exec = (string, columns, options = {}) => {
|
91
|
+
if (options.trim !== false && string.trim() === '') {
|
92
|
+
return '';
|
93
|
+
}
|
101
94
|
|
102
95
|
let pre = '';
|
103
96
|
let ret = '';
|
104
97
|
let escapeCode;
|
105
98
|
|
106
|
-
const lengths = wordLengths(
|
107
|
-
|
108
|
-
const rows = [''];
|
99
|
+
const lengths = wordLengths(string);
|
100
|
+
let rows = [''];
|
109
101
|
|
110
|
-
for (const
|
111
|
-
|
112
|
-
|
102
|
+
for (const [index, word] of string.split(' ').entries()) {
|
103
|
+
if (options.trim !== false) {
|
104
|
+
rows[rows.length - 1] = rows[rows.length - 1].trimLeft();
|
105
|
+
}
|
113
106
|
|
114
|
-
rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim();
|
115
107
|
let rowLength = stringWidth(rows[rows.length - 1]);
|
116
108
|
|
117
|
-
if (
|
118
|
-
if (rowLength
|
109
|
+
if (index !== 0) {
|
110
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
119
111
|
// If we start with a new word but the current row length equals the length of the columns, add a new row
|
120
112
|
rows.push('');
|
121
113
|
rowLength = 0;
|
122
114
|
}
|
123
115
|
|
124
|
-
|
125
|
-
|
116
|
+
if (rowLength > 0 || options.trim === false) {
|
117
|
+
rows[rows.length - 1] += ' ';
|
118
|
+
rowLength++;
|
119
|
+
}
|
126
120
|
}
|
127
121
|
|
128
122
|
// In 'hard' wrap mode, the length of a line is
|
129
|
-
// never allowed to extend past '
|
130
|
-
if (lengths[
|
131
|
-
|
123
|
+
// never allowed to extend past 'columns'
|
124
|
+
if (options.hard && lengths[index] > columns) {
|
125
|
+
const remainingColumns = (columns - rowLength);
|
126
|
+
const breaksStartingThisLine = 1 + Math.floor((lengths[index] - remainingColumns - 1) / columns);
|
127
|
+
const breaksStartingNextLine = Math.floor((lengths[index] - 1) / columns);
|
128
|
+
if (breaksStartingNextLine < breaksStartingThisLine) {
|
132
129
|
rows.push('');
|
133
130
|
}
|
134
|
-
|
131
|
+
|
132
|
+
wrapWord(rows, word, columns);
|
135
133
|
continue;
|
136
134
|
}
|
137
135
|
|
138
|
-
if (rowLength + lengths[
|
139
|
-
if (options.wordWrap === false && rowLength <
|
140
|
-
wrapWord(rows, word,
|
136
|
+
if (rowLength + lengths[index] > columns && rowLength > 0 && lengths[index] > 0) {
|
137
|
+
if (options.wordWrap === false && rowLength < columns) {
|
138
|
+
wrapWord(rows, word, columns);
|
141
139
|
continue;
|
142
140
|
}
|
143
141
|
|
144
142
|
rows.push('');
|
145
143
|
}
|
146
144
|
|
147
|
-
if (rowLength + lengths[
|
148
|
-
wrapWord(rows, word,
|
145
|
+
if (rowLength + lengths[index] > columns && options.wordWrap === false) {
|
146
|
+
wrapWord(rows, word, columns);
|
149
147
|
continue;
|
150
148
|
}
|
151
149
|
|
152
150
|
rows[rows.length - 1] += word;
|
153
151
|
}
|
154
152
|
|
155
|
-
|
153
|
+
if (options.trim !== false) {
|
154
|
+
rows = rows.map(stringVisibleTrimSpacesRight);
|
155
|
+
}
|
156
156
|
|
157
|
-
|
158
|
-
const i = item[0];
|
159
|
-
const char = item[1];
|
157
|
+
pre = rows.join('\n');
|
160
158
|
|
161
|
-
|
159
|
+
for (const [index, character] of [...pre].entries()) {
|
160
|
+
ret += character;
|
162
161
|
|
163
|
-
if (ESCAPES.has(
|
164
|
-
const code = parseFloat(/\d[^m]*/.exec(pre.slice(
|
162
|
+
if (ESCAPES.has(character)) {
|
163
|
+
const code = parseFloat(/\d[^m]*/.exec(pre.slice(index, index + 4)));
|
165
164
|
escapeCode = code === END_CODE ? null : code;
|
166
165
|
}
|
167
166
|
|
168
|
-
const code =
|
167
|
+
const code = ansiStyles.codes.get(Number(escapeCode));
|
169
168
|
|
170
169
|
if (escapeCode && code) {
|
171
|
-
if (pre[
|
170
|
+
if (pre[index + 1] === '\n') {
|
172
171
|
ret += wrapAnsi(code);
|
173
|
-
} else if (
|
172
|
+
} else if (character === '\n') {
|
174
173
|
ret += wrapAnsi(escapeCode);
|
175
174
|
}
|
176
175
|
}
|
@@ -180,10 +179,10 @@ const exec = (str, cols, opts) => {
|
|
180
179
|
};
|
181
180
|
|
182
181
|
// For each newline, invoke the method separately
|
183
|
-
module.exports = (
|
184
|
-
return String(
|
182
|
+
module.exports = (string, columns, options) => {
|
183
|
+
return String(string)
|
185
184
|
.normalize()
|
186
185
|
.split('\n')
|
187
|
-
.map(line => exec(line,
|
186
|
+
.map(line => exec(line, columns, options))
|
188
187
|
.join('\n');
|
189
188
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "wrap-ansi",
|
3
|
-
"version": "
|
3
|
+
"version": "5.1.0",
|
4
4
|
"description": "Wordwrap a string with ANSI escape codes",
|
5
5
|
"license": "MIT",
|
6
6
|
"repository": "chalk/wrap-ansi",
|
@@ -10,11 +10,10 @@
|
|
10
10
|
"url": "sindresorhus.com"
|
11
11
|
},
|
12
12
|
"engines": {
|
13
|
-
"node": ">=
|
13
|
+
"node": ">=6"
|
14
14
|
},
|
15
15
|
"scripts": {
|
16
|
-
"test": "xo && nyc ava"
|
17
|
-
"coveralls": "nyc report --reporter=text-lcov | coveralls"
|
16
|
+
"test": "xo && nyc ava"
|
18
17
|
},
|
19
18
|
"files": [
|
20
19
|
"index.js"
|
@@ -47,16 +46,16 @@
|
|
47
46
|
"text"
|
48
47
|
],
|
49
48
|
"dependencies": {
|
50
|
-
"
|
51
|
-
"
|
49
|
+
"ansi-styles": "^3.2.0",
|
50
|
+
"string-width": "^3.0.0",
|
51
|
+
"strip-ansi": "^5.0.0"
|
52
52
|
},
|
53
53
|
"devDependencies": {
|
54
|
-
"ava": "^
|
55
|
-
"chalk": "^2.
|
56
|
-
"coveralls": "^
|
54
|
+
"ava": "^1.2.1",
|
55
|
+
"chalk": "^2.4.2",
|
56
|
+
"coveralls": "^3.0.3",
|
57
57
|
"has-ansi": "^3.0.0",
|
58
|
-
"nyc": "^
|
59
|
-
"
|
60
|
-
"xo": "^0.18.2"
|
58
|
+
"nyc": "^13.3.0",
|
59
|
+
"xo": "^0.24.0"
|
61
60
|
}
|
62
61
|
}
|
package/readme.md
CHANGED
@@ -24,6 +24,20 @@ console.log(wrapAnsi(input, 20));
|
|
24
24
|
|
25
25
|
<img width="331" src="screenshot.png">
|
26
26
|
|
27
|
+
---
|
28
|
+
|
29
|
+
<div align="center">
|
30
|
+
<b>
|
31
|
+
<a href="https://tidelift.com/subscription/pkg/npm-wrap_ansi?utm_source=npm-wrap-ansi&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
32
|
+
</b>
|
33
|
+
<br>
|
34
|
+
<sub>
|
35
|
+
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
36
|
+
</sub>
|
37
|
+
</div>
|
38
|
+
|
39
|
+
---
|
40
|
+
|
27
41
|
|
28
42
|
## API
|
29
43
|
|
@@ -84,6 +98,11 @@ Whitespace on all lines is removed by default. Set this option to `false` if you
|
|
84
98
|
- [Benjamin Coe](https://github.com/bcoe)
|
85
99
|
|
86
100
|
|
101
|
+
## Security
|
102
|
+
|
103
|
+
To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
|
104
|
+
|
105
|
+
|
87
106
|
## License
|
88
107
|
|
89
108
|
MIT
|