slice-ansi 5.0.0 → 7.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/index.js +136 -74
- package/package.json +9 -9
- package/readme.md +5 -17
package/index.js
CHANGED
@@ -1,105 +1,167 @@
|
|
1
|
-
import isFullwidthCodePoint from 'is-fullwidth-code-point';
|
2
1
|
import ansiStyles from 'ansi-styles';
|
2
|
+
import isFullwidthCodePoint from 'is-fullwidth-code-point';
|
3
3
|
|
4
|
-
|
4
|
+
// \x1b and \x9b
|
5
|
+
const ESCAPES = new Set([27, 155]);
|
5
6
|
|
6
|
-
const
|
7
|
-
|
8
|
-
'\u009B'
|
9
|
-
];
|
7
|
+
const CODE_POINT_0 = '0'.codePointAt(0);
|
8
|
+
const CODE_POINT_9 = '9'.codePointAt(0);
|
10
9
|
|
11
|
-
const
|
10
|
+
const endCodesSet = new Set();
|
11
|
+
const endCodesMap = new Map();
|
12
|
+
for (const [start, end] of ansiStyles.codes) {
|
13
|
+
endCodesSet.add(ansiStyles.color.ansi(end));
|
14
|
+
endCodesMap.set(ansiStyles.color.ansi(start), ansiStyles.color.ansi(end));
|
15
|
+
}
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
function getEndCode(code) {
|
18
|
+
if (endCodesSet.has(code)) {
|
19
|
+
return code;
|
20
|
+
}
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
ansiCode = ansiCode.split(';')[0][0] + '0';
|
21
|
-
}
|
22
|
+
if (endCodesMap.has(code)) {
|
23
|
+
return endCodesMap.get(code);
|
24
|
+
}
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
26
|
+
code = code.slice(2);
|
27
|
+
if (code.includes(';')) {
|
28
|
+
code = code[0] + '0';
|
29
|
+
}
|
30
|
+
|
31
|
+
const returnValue = ansiStyles.codes.get(Number.parseInt(code, 10));
|
32
|
+
if (returnValue) {
|
33
|
+
return ansiStyles.color.ansi(returnValue);
|
34
|
+
}
|
35
|
+
|
36
|
+
return ansiStyles.reset.open;
|
37
|
+
}
|
38
|
+
|
39
|
+
function findNumberIndex(string) {
|
40
|
+
for (let index = 0; index < string.length; index++) {
|
41
|
+
const codePoint = string.codePointAt(index);
|
42
|
+
if (codePoint >= CODE_POINT_0 && codePoint <= CODE_POINT_9) {
|
43
|
+
return index;
|
36
44
|
}
|
37
45
|
}
|
38
46
|
|
39
|
-
|
40
|
-
|
47
|
+
return -1;
|
48
|
+
}
|
41
49
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
50
|
+
function parseAnsiCode(string, offset) {
|
51
|
+
string = string.slice(offset, offset + 19);
|
52
|
+
const startIndex = findNumberIndex(string);
|
53
|
+
if (startIndex !== -1) {
|
54
|
+
let endIndex = string.indexOf('m', startIndex);
|
55
|
+
if (endIndex === -1) {
|
56
|
+
endIndex = string.length;
|
47
57
|
}
|
58
|
+
|
59
|
+
return string.slice(0, endIndex + 1);
|
48
60
|
}
|
61
|
+
}
|
49
62
|
|
50
|
-
|
51
|
-
|
63
|
+
function tokenize(string, endCharacter = Number.POSITIVE_INFINITY) {
|
64
|
+
const returnValue = [];
|
65
|
+
|
66
|
+
let index = 0;
|
67
|
+
let visibleCount = 0;
|
68
|
+
while (index < string.length) {
|
69
|
+
const codePoint = string.codePointAt(index);
|
70
|
+
|
71
|
+
if (ESCAPES.has(codePoint)) {
|
72
|
+
const code = parseAnsiCode(string, index);
|
73
|
+
if (code) {
|
74
|
+
returnValue.push({
|
75
|
+
type: 'ansi',
|
76
|
+
code,
|
77
|
+
endCode: getEndCode(code),
|
78
|
+
});
|
79
|
+
index += code.length;
|
80
|
+
continue;
|
81
|
+
}
|
82
|
+
}
|
52
83
|
|
53
|
-
|
54
|
-
|
55
|
-
const ansiCodes = [];
|
84
|
+
const isFullWidth = isFullwidthCodePoint(codePoint);
|
85
|
+
const character = String.fromCodePoint(codePoint);
|
56
86
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
87
|
+
returnValue.push({
|
88
|
+
type: 'character',
|
89
|
+
value: character,
|
90
|
+
isFullWidth,
|
91
|
+
});
|
62
92
|
|
63
|
-
|
64
|
-
|
93
|
+
index += character.length;
|
94
|
+
visibleCount += isFullWidth ? 2 : character.length;
|
65
95
|
|
66
|
-
if (
|
67
|
-
|
68
|
-
|
96
|
+
if (visibleCount >= endCharacter) {
|
97
|
+
break;
|
98
|
+
}
|
99
|
+
}
|
69
100
|
|
70
|
-
|
71
|
-
|
101
|
+
return returnValue;
|
102
|
+
}
|
72
103
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
104
|
+
function reduceAnsiCodes(codes) {
|
105
|
+
let returnValue = [];
|
106
|
+
|
107
|
+
for (const code of codes) {
|
108
|
+
if (code.code === ansiStyles.reset.open) {
|
109
|
+
// Reset code, disable all codes
|
110
|
+
returnValue = [];
|
111
|
+
} else if (endCodesSet.has(code.code)) {
|
112
|
+
// This is an end code, disable all matching start codes
|
113
|
+
returnValue = returnValue.filter(returnValueCode => returnValueCode.endCode !== code.code);
|
114
|
+
} else {
|
115
|
+
// This is a start code. Disable all styles this "overrides", then enable it
|
116
|
+
returnValue = returnValue.filter(returnValueCode => returnValueCode.endCode !== code.endCode);
|
117
|
+
returnValue.push(code);
|
80
118
|
}
|
119
|
+
}
|
120
|
+
|
121
|
+
return returnValue;
|
122
|
+
}
|
81
123
|
|
82
|
-
|
83
|
-
|
124
|
+
function undoAnsiCodes(codes) {
|
125
|
+
const reduced = reduceAnsiCodes(codes);
|
126
|
+
const endCodes = reduced.map(({endCode}) => endCode);
|
127
|
+
return endCodes.reverse().join('');
|
128
|
+
}
|
129
|
+
|
130
|
+
export default function sliceAnsi(string, start, end) {
|
131
|
+
const tokens = tokenize(string, end);
|
132
|
+
let activeCodes = [];
|
133
|
+
let position = 0;
|
134
|
+
let returnValue = '';
|
135
|
+
let include = false;
|
136
|
+
|
137
|
+
for (const token of tokens) {
|
138
|
+
if (end !== undefined && position >= end) {
|
139
|
+
break;
|
84
140
|
}
|
85
141
|
|
86
|
-
if (
|
87
|
-
|
142
|
+
if (token.type === 'ansi') {
|
143
|
+
activeCodes.push(token);
|
144
|
+
if (include) {
|
145
|
+
returnValue += token.code;
|
146
|
+
}
|
147
|
+
} else {
|
148
|
+
// Character
|
149
|
+
if (!include && position >= start) {
|
150
|
+
include = true;
|
151
|
+
// Simplify active codes
|
152
|
+
activeCodes = reduceAnsiCodes(activeCodes);
|
153
|
+
returnValue = activeCodes.map(({code}) => code).join('');
|
154
|
+
}
|
88
155
|
|
89
|
-
if (
|
90
|
-
|
156
|
+
if (include) {
|
157
|
+
returnValue += token.value;
|
91
158
|
}
|
92
|
-
}
|
93
159
|
|
94
|
-
|
95
|
-
output += character;
|
96
|
-
} else if (visible === begin && !isInsideEscape && ansiCode !== undefined) {
|
97
|
-
output = checkAnsi(ansiCodes);
|
98
|
-
} else if (visible >= stringEnd) {
|
99
|
-
output += checkAnsi(ansiCodes, true, ansiCode);
|
100
|
-
break;
|
160
|
+
position += token.isFullWidth ? 2 : token.value.length;
|
101
161
|
}
|
102
162
|
}
|
103
163
|
|
104
|
-
|
164
|
+
// Disable active codes at the end
|
165
|
+
returnValue += undoAnsiCodes(activeCodes);
|
166
|
+
return returnValue;
|
105
167
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "slice-ansi",
|
3
|
-
"version": "
|
3
|
+
"version": "7.0.0",
|
4
4
|
"description": "Slice a string with ANSI escape codes",
|
5
5
|
"license": "MIT",
|
6
6
|
"repository": "chalk/slice-ansi",
|
@@ -8,7 +8,7 @@
|
|
8
8
|
"type": "module",
|
9
9
|
"exports": "./index.js",
|
10
10
|
"engines": {
|
11
|
-
"node": ">=
|
11
|
+
"node": ">=14.16"
|
12
12
|
},
|
13
13
|
"scripts": {
|
14
14
|
"test": "xo && ava"
|
@@ -40,14 +40,14 @@
|
|
40
40
|
"text"
|
41
41
|
],
|
42
42
|
"dependencies": {
|
43
|
-
"ansi-styles": "^6.
|
44
|
-
"is-fullwidth-code-point": "^
|
43
|
+
"ansi-styles": "^6.2.1",
|
44
|
+
"is-fullwidth-code-point": "^5.0.0"
|
45
45
|
},
|
46
46
|
"devDependencies": {
|
47
|
-
"ava": "^3.
|
48
|
-
"chalk": "^
|
49
|
-
"random-item": "^4.0.
|
50
|
-
"strip-ansi": "^7.
|
51
|
-
"xo": "^0.
|
47
|
+
"ava": "^5.3.1",
|
48
|
+
"chalk": "^5.3.0",
|
49
|
+
"random-item": "^4.0.1",
|
50
|
+
"strip-ansi": "^7.1.0",
|
51
|
+
"xo": "^0.56.0"
|
52
52
|
}
|
53
53
|
}
|
package/readme.md
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
|
5
5
|
## Install
|
6
6
|
|
7
|
-
```
|
8
|
-
|
7
|
+
```sh
|
8
|
+
npm install slice-ansi
|
9
9
|
```
|
10
10
|
|
11
11
|
## Usage
|
@@ -22,7 +22,7 @@ console.log(sliceAnsi(string, 20, 30));
|
|
22
22
|
|
23
23
|
## API
|
24
24
|
|
25
|
-
### sliceAnsi(string,
|
25
|
+
### sliceAnsi(string, startSlice, endSlice?)
|
26
26
|
|
27
27
|
#### string
|
28
28
|
|
@@ -30,11 +30,11 @@ Type: `string`
|
|
30
30
|
|
31
31
|
String with ANSI escape codes. Like one styled by [`chalk`](https://github.com/chalk/chalk).
|
32
32
|
|
33
|
-
####
|
33
|
+
#### startSlice
|
34
34
|
|
35
35
|
Type: `number`
|
36
36
|
|
37
|
-
Zero-based index at which to
|
37
|
+
Zero-based index at which to start the slice.
|
38
38
|
|
39
39
|
#### endSlice
|
40
40
|
|
@@ -52,15 +52,3 @@ Zero-based index at which to end the slice.
|
|
52
52
|
|
53
53
|
- [Sindre Sorhus](https://github.com/sindresorhus)
|
54
54
|
- [Josh Junon](https://github.com/qix-)
|
55
|
-
|
56
|
-
---
|
57
|
-
|
58
|
-
<div align="center">
|
59
|
-
<b>
|
60
|
-
<a href="https://tidelift.com/subscription/pkg/npm-slice_ansi?utm_source=npm-slice-ansi&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
61
|
-
</b>
|
62
|
-
<br>
|
63
|
-
<sub>
|
64
|
-
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
65
|
-
</sub>
|
66
|
-
</div>
|