Socket
Socket
Sign inDemoInstall

slice-ansi

Package Overview
Dependencies
2
Maintainers
2
Versions
13
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 5.0.0 to 6.0.0

210

index.js

@@ -0,105 +1,167 @@

import ansiStyles from 'ansi-styles';
import isFullwidthCodePoint from 'is-fullwidth-code-point';
import ansiStyles from 'ansi-styles';
const astralRegex = /^[\uD800-\uDBFF][\uDC00-\uDFFF]$/;
// \x1b and \x9b
const ESCAPES = new Set([27, 155]);
const ESCAPES = [
'\u001B',
'\u009B'
];
const CODE_POINT_0 = '0'.codePointAt(0);
const CODE_POINT_9 = '9'.codePointAt(0);
const wrapAnsi = code => `${ESCAPES[0]}[${code}m`;
const endCodesSet = new Set();
const endCodesMap = new Map();
for (const [start, end] of ansiStyles.codes) {
endCodesSet.add(ansiStyles.color.ansi(end));
endCodesMap.set(ansiStyles.color.ansi(start), ansiStyles.color.ansi(end));
}
const checkAnsi = (ansiCodes, isEscapes, endAnsiCode) => {
let output = [];
ansiCodes = [...ansiCodes];
function getEndCode(code) {
if (endCodesSet.has(code)) {
return code;
}
for (let ansiCode of ansiCodes) {
const ansiCodeOrigin = ansiCode;
if (ansiCode.includes(';')) {
ansiCode = ansiCode.split(';')[0][0] + '0';
}
if (endCodesMap.has(code)) {
return endCodesMap.get(code);
}
const item = ansiStyles.codes.get(Number.parseInt(ansiCode, 10));
if (item) {
const indexEscape = ansiCodes.indexOf(item.toString());
if (indexEscape === -1) {
output.push(wrapAnsi(isEscapes ? item : ansiCodeOrigin));
} else {
ansiCodes.splice(indexEscape, 1);
}
} else if (isEscapes) {
output.push(wrapAnsi(0));
break;
} else {
output.push(wrapAnsi(ansiCodeOrigin));
}
code = code.slice(2);
if (code.includes(';')) {
code = code[0] + '0';
}
if (isEscapes) {
output = output.filter((element, index) => output.indexOf(element) === index);
const returnValue = ansiStyles.codes.get(Number.parseInt(code, 10));
if (returnValue) {
return ansiStyles.color.ansi(returnValue);
}
if (endAnsiCode !== undefined) {
const fistEscapeCode = wrapAnsi(ansiStyles.codes.get(Number.parseInt(endAnsiCode, 10)));
// TODO: Remove the use of `.reduce` here.
// eslint-disable-next-line unicorn/no-array-reduce
output = output.reduce((current, next) => next === fistEscapeCode ? [next, ...current] : [...current, next], []);
return ansiStyles.reset.open;
}
function findNumberIndex(string) {
for (let index = 0; index < string.length; index++) {
const codePoint = string.codePointAt(index);
if (codePoint >= CODE_POINT_0 && codePoint <= CODE_POINT_9) {
return index;
}
}
return output.join('');
};
return -1;
}
export default function sliceAnsi(string, begin, end) {
const characters = [...string];
const ansiCodes = [];
function parseAnsiCode(string, offset) {
string = string.slice(offset, offset + 19);
const startIndex = findNumberIndex(string);
if (startIndex !== -1) {
let endIndex = string.indexOf('m', startIndex);
if (endIndex === -1) {
endIndex = string.length;
}
let stringEnd = typeof end === 'number' ? end : characters.length;
let isInsideEscape = false;
let ansiCode;
let visible = 0;
let output = '';
return string.slice(0, endIndex + 1);
}
}
for (const [index, character] of characters.entries()) {
let leftEscape = false;
function tokenize(string, endCharacter = Number.POSITIVE_INFINITY) {
const returnValue = [];
if (ESCAPES.includes(character)) {
const code = /\d[^m]*/.exec(string.slice(index, index + 18));
ansiCode = code && code.length > 0 ? code[0] : undefined;
let index = 0;
let visibleCount = 0;
while (index < string.length) {
const codePoint = string.codePointAt(index);
if (visible < stringEnd) {
isInsideEscape = true;
if (ansiCode !== undefined) {
ansiCodes.push(ansiCode);
}
if (ESCAPES.has(codePoint)) {
const code = parseAnsiCode(string, index);
if (code) {
returnValue.push({
type: 'ansi',
code,
endCode: getEndCode(code),
});
index += code.length;
continue;
}
} else if (isInsideEscape && character === 'm') {
isInsideEscape = false;
leftEscape = true;
}
if (!isInsideEscape && !leftEscape) {
visible++;
const isFullWidth = isFullwidthCodePoint(codePoint);
const character = String.fromCodePoint(codePoint);
returnValue.push({
type: 'character',
value: character,
isFullWidth,
});
index += character.length;
visibleCount += isFullWidth ? 2 : character.length;
if (visibleCount >= endCharacter) {
break;
}
}
if (!astralRegex.test(character) && isFullwidthCodePoint(character.codePointAt())) {
visible++;
return returnValue;
}
if (typeof end !== 'number') {
stringEnd++;
}
function reduceAnsiCodes(codes) {
let returnValue = [];
for (const code of codes) {
if (code.code === ansiStyles.reset.open) {
// Reset code, disable all codes
returnValue = [];
} else if (endCodesSet.has(code.code)) {
// This is an end code, disable all matching start codes
returnValue = returnValue.filter(returnValueCode => returnValueCode.endCode !== code.code);
} else {
// This is a start code. Disable all styles this "overrides", then enable it
returnValue = returnValue.filter(returnValueCode => returnValueCode.endCode !== code.endCode);
returnValue.push(code);
}
}
if (visible > begin && visible <= stringEnd) {
output += character;
} else if (visible === begin && !isInsideEscape && ansiCode !== undefined) {
output = checkAnsi(ansiCodes);
} else if (visible >= stringEnd) {
output += checkAnsi(ansiCodes, true, ansiCode);
return returnValue;
}
function undoAnsiCodes(codes) {
const reduced = reduceAnsiCodes(codes);
const endCodes = reduced.map(({endCode}) => endCode);
return endCodes.reverse().join('');
}
export default function sliceAnsi(string, start, end) {
const tokens = tokenize(string, end);
let activeCodes = [];
let position = 0;
let returnValue = '';
let include = false;
for (const token of tokens) {
if (end !== undefined && position >= end) {
break;
}
if (token.type === 'ansi') {
activeCodes.push(token);
if (include) {
returnValue += token.code;
}
} else {
// Character
if (!include && position >= start) {
include = true;
// Simplify active codes
activeCodes = reduceAnsiCodes(activeCodes);
returnValue = activeCodes.map(({code}) => code).join('');
}
if (include) {
returnValue += token.value;
}
position += token.isFullWidth ? 2 : token.value.length;
}
}
return output;
// Disable active codes at the end
returnValue += undoAnsiCodes(activeCodes);
return returnValue;
}
{
"name": "slice-ansi",
"version": "5.0.0",
"version": "6.0.0",
"description": "Slice a string with ANSI escape codes",

@@ -11,3 +11,3 @@ "license": "MIT",

"engines": {
"node": ">=12"
"node": ">=14.16"
},

@@ -44,12 +44,12 @@ "scripts": {

"dependencies": {
"ansi-styles": "^6.0.0",
"ansi-styles": "^6.2.1",
"is-fullwidth-code-point": "^4.0.0"
},
"devDependencies": {
"ava": "^3.15.0",
"chalk": "^4.1.0",
"random-item": "^4.0.0",
"strip-ansi": "^7.0.0",
"xo": "^0.38.2"
"ava": "^5.2.0",
"chalk": "^5.2.0",
"random-item": "^4.0.1",
"strip-ansi": "^7.0.1",
"xo": "^0.53.1"
}
}

@@ -7,5 +7,5 @@ # slice-ansi [![XO: Linted](https://img.shields.io/badge/xo-linted-blue.svg)](https://github.com/xojs/xo)

```sh
npm install slice-ansi
```
$ npm install slice-ansi
```

@@ -26,3 +26,3 @@ ## Usage

### sliceAnsi(string, beginSlice, endSlice?)
### sliceAnsi(string, startSlice, endSlice?)

@@ -35,7 +35,7 @@ #### string

#### beginSlice
#### startSlice
Type: `number`
Zero-based index at which to begin the slice.
Zero-based index at which to start the slice.

@@ -58,13 +58,1 @@ #### endSlice

- [Josh Junon](https://github.com/qix-)
---
<div align="center">
<b>
<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>
</b>
<br>
<sub>
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
</sub>
</div>
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc