@visulima/string 3.0.0-alpha.1 → 3.0.0-alpha.10
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/CHANGELOG.md +140 -0
- package/LICENSE.md +429 -1
- package/README.md +72 -20
- package/dist/align-text.d.ts +7 -10
- package/dist/align-text.js +7 -5
- package/dist/case/camel-case.d.ts +3 -5
- package/dist/case/camel-case.js +7 -7
- package/dist/case/capital-case.d.ts +3 -5
- package/dist/case/capital-case.js +3 -3
- package/dist/case/constant-case.d.ts +3 -5
- package/dist/case/dot-case.d.ts +3 -5
- package/dist/case/flat-case.d.ts +3 -5
- package/dist/case/flip-case.d.ts +4 -7
- package/dist/case/flip-case.js +8 -2
- package/dist/case/identify-case.d.ts +3 -5
- package/dist/case/identify-case.js +2 -1
- package/dist/case/index.d.ts +23 -25
- package/dist/case/index.js +1 -1
- package/dist/case/kebab-case.d.ts +6 -9
- package/dist/case/kebab-case.js +3 -3
- package/dist/case/lower-first.d.ts +3 -5
- package/dist/case/no-case.d.ts +3 -5
- package/dist/case/pascal-case.d.ts +3 -5
- package/dist/case/pascal-case.js +3 -3
- package/dist/case/pascal-snake-case.d.ts +3 -5
- package/dist/case/path-case.d.ts +3 -5
- package/dist/case/sentence-case.d.ts +3 -5
- package/dist/case/sentence-case.js +7 -7
- package/dist/case/snake-case.d.ts +3 -5
- package/dist/case/split-by-case.d.ts +11 -14
- package/dist/case/split-by-case.js +171 -52
- package/dist/case/title-case.d.ts +3 -5
- package/dist/case/title-case.js +3 -5
- package/dist/case/train-case.d.ts +3 -5
- package/dist/case/train-case.js +1 -1
- package/dist/case/upper-first.d.ts +3 -5
- package/dist/closest-string.d.ts +3 -5
- package/dist/closest-string.js +5 -8
- package/dist/compare-similarity.d.ts +3 -5
- package/dist/compare-similarity.js +2 -2
- package/dist/get-string-truncated-width.d.ts +18 -20
- package/dist/get-string-truncated-width.js +2 -33
- package/dist/get-string-width.d.ts +2 -5
- package/dist/index.d.ts +49 -45
- package/dist/index.js +12 -4
- package/dist/native-string-types.d.ts +145 -128
- package/dist/outdent.d.ts +9 -11
- package/dist/outdent.js +7 -15
- package/dist/packem_shared/closestN-DUsjgiXb.js +25 -0
- package/dist/packem_shared/{constants-CTzC6Gjg.js → constants-BsZS5f0z.js} +1 -1
- package/dist/packem_shared/countOccurrences-CS9XprQN.js +22 -0
- package/dist/packem_shared/direction-C9gfWWTK.js +16 -0
- package/dist/packem_shared/eastAsianWidthType-SD3YniiT.js +20 -0
- package/dist/packem_shared/excerpt-COsVNttN.js +1502 -0
- package/dist/packem_shared/indent-D3DSCa6s.js +33 -0
- package/dist/packem_shared/isFullwidthCodePoint-IFXZxNjq.js +10 -0
- package/dist/packem_shared/{joinSegments-CuU8RGpP.js → joinSegments-CvxSgKz0.js} +1 -1
- package/dist/packem_shared/lookup-BE8lEqy4.js +104 -0
- package/dist/packem_shared/lru-cache.d-BsP6kbVJ.d.ts +13 -0
- package/dist/packem_shared/{normalize-german-eszett-DEB8-ZPT.js → normalize-german-eszett-4p3yKEzn.js} +2 -1
- package/dist/packem_shared/redent-DSb1IJWn.js +8 -0
- package/dist/packem_shared/{replaceString-vYvRBMfC.js → replaceString-Ce8X2ZQ-.js} +19 -17
- package/dist/packem_shared/stripIndent-D_TRjxZ_.js +20 -0
- package/dist/packem_shared/{transliterate-CYnKKT8f.js → transliterate-CKt9VK7D.js} +10 -12
- package/dist/packem_shared/{types-Daae0hGf.d.ts → types.d-BVNv675q.d.ts} +18 -21
- package/dist/packem_shared/{types-CfPsw9ix.d.ts → types.d-DfgbcNKh.d.ts} +19 -21
- package/dist/slice.d.ts +5 -8
- package/dist/slice.js +9 -7
- package/dist/slugify.d.ts +1 -3
- package/dist/slugify.js +1 -1
- package/dist/test/utils.d.ts +20 -22
- package/dist/test/utils.js +2 -2
- package/dist/test/vitest.d.ts +3 -6
- package/dist/truncate.d.ts +7 -10
- package/dist/truncate.js +49 -26
- package/dist/utilities.d.ts +2 -4
- package/dist/utilities.js +6 -8
- package/dist/word-similarity-sort.d.ts +3 -5
- package/dist/word-wrap.d.ts +9 -11
- package/dist/word-wrap.js +37 -35
- package/package.json +2 -2
- package/dist/packem_shared/closestN-BREy4E7C.js +0 -19
- package/dist/packem_shared/lru-cache-B_t27XwI.d.ts +0 -14
package/dist/test/utils.d.ts
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
declare const formatAnsiString: (ansiString: string) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
ansi: string;
|
|
3
|
+
json: string;
|
|
4
|
+
lengthDifference: number;
|
|
5
|
+
stripped: string;
|
|
6
|
+
visible: string;
|
|
7
7
|
};
|
|
8
8
|
interface ExpectationResult {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
actual?: unknown;
|
|
10
|
+
expected?: unknown;
|
|
11
|
+
message: () => string;
|
|
12
|
+
pass: boolean;
|
|
13
13
|
}
|
|
14
14
|
declare const expectAnsiStrings: (actual: string, expected: string) => ExpectationResult;
|
|
15
15
|
declare const compareAnsiStrings: (actual: string, expected: string) => {
|
|
16
|
-
|
|
16
|
+
actual: ReturnType<typeof formatAnsiString>;
|
|
17
|
+
ansiEqual: boolean;
|
|
18
|
+
expected: ReturnType<typeof formatAnsiString>;
|
|
19
|
+
strippedEqual: boolean;
|
|
20
|
+
summary: {
|
|
21
|
+
actualLength: number;
|
|
22
|
+
actualStrippedLength: number;
|
|
17
23
|
ansiEqual: boolean;
|
|
18
|
-
|
|
24
|
+
expectedLength: number;
|
|
25
|
+
expectedStrippedLength: number;
|
|
19
26
|
strippedEqual: boolean;
|
|
20
|
-
|
|
21
|
-
actualLength: number;
|
|
22
|
-
actualStrippedLength: number;
|
|
23
|
-
ansiEqual: boolean;
|
|
24
|
-
expectedLength: number;
|
|
25
|
-
expectedStrippedLength: number;
|
|
26
|
-
strippedEqual: boolean;
|
|
27
|
-
};
|
|
27
|
+
};
|
|
28
28
|
};
|
|
29
|
-
|
|
30
|
-
export { compareAnsiStrings, expectAnsiStrings, formatAnsiString };
|
|
31
|
-
export type { ExpectationResult };
|
|
29
|
+
export { ExpectationResult, compareAnsiStrings, expectAnsiStrings, formatAnsiString };
|
package/dist/test/utils.js
CHANGED
package/dist/test/vitest.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { ExpectationResult } from
|
|
2
|
-
|
|
1
|
+
import { ExpectationResult } from "./utils.js";
|
|
3
2
|
interface CustomMatchers {
|
|
4
|
-
|
|
3
|
+
toEqualAnsi: (expected: string) => ExpectationResult;
|
|
5
4
|
}
|
|
6
5
|
declare const toEqualAnsi: (actual: string, expected: string) => ExpectationResult;
|
|
7
|
-
|
|
8
|
-
export { toEqualAnsi };
|
|
9
|
-
export type { CustomMatchers };
|
|
6
|
+
export { CustomMatchers, toEqualAnsi };
|
package/dist/truncate.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { StringTruncatedWidthOptions } from
|
|
2
|
-
|
|
1
|
+
import { StringTruncatedWidthOptions } from "./get-string-truncated-width.js";
|
|
3
2
|
type TruncateOptions = {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
ellipsis?: string;
|
|
4
|
+
ellipsisWidth?: number;
|
|
5
|
+
position?: "end" | "middle" | "start";
|
|
6
|
+
preferTruncationOnSpace?: boolean;
|
|
7
|
+
width?: Omit<StringTruncatedWidthOptions, "ellipsis" | "ellipsisWidth" | "limit">;
|
|
9
8
|
};
|
|
10
9
|
declare const truncate: (input: string, limit: number, options?: TruncateOptions) => string;
|
|
11
|
-
|
|
12
|
-
export { truncate };
|
|
13
|
-
export type { TruncateOptions };
|
|
10
|
+
export { TruncateOptions, truncate };
|
package/dist/truncate.js
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import { getStringTruncatedWidth } from './get-string-truncated-width.js';
|
|
2
|
+
import { getStringWidth } from './get-string-width.js';
|
|
2
3
|
import { slice } from './slice.js';
|
|
3
4
|
|
|
4
5
|
const DEFAULT_ELLIPSIS = "…";
|
|
5
6
|
const MAX_SPACE_SEARCH_DISTANCE = 3;
|
|
6
|
-
const findNearestSpace = (
|
|
7
|
-
if (
|
|
7
|
+
const findNearestSpace = (value, startIndex, searchRight = false) => {
|
|
8
|
+
if (value.charAt(startIndex) === " ") {
|
|
8
9
|
return startIndex;
|
|
9
10
|
}
|
|
10
11
|
const direction = searchRight ? 1 : -1;
|
|
11
|
-
const limit = Math.min(MAX_SPACE_SEARCH_DISTANCE, searchRight ?
|
|
12
|
+
const limit = Math.min(MAX_SPACE_SEARCH_DISTANCE, searchRight ? value.length - startIndex : startIndex);
|
|
12
13
|
for (let offset = 1; offset <= limit; offset++) {
|
|
13
14
|
const index = startIndex + offset * direction;
|
|
14
|
-
if (
|
|
15
|
+
if (value.charAt(index) === " ") {
|
|
15
16
|
return index;
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
return startIndex;
|
|
19
20
|
};
|
|
21
|
+
const widthToIndex = (input, targetWidth, widthOptions) => {
|
|
22
|
+
const result = getStringTruncatedWidth(input, {
|
|
23
|
+
...widthOptions,
|
|
24
|
+
ellipsis: "",
|
|
25
|
+
ellipsisWidth: 0,
|
|
26
|
+
limit: targetWidth
|
|
27
|
+
});
|
|
28
|
+
return result.index;
|
|
29
|
+
};
|
|
30
|
+
const indexToWidth = (input, stringIndex, widthOptions) => getStringWidth(input.slice(0, stringIndex), widthOptions);
|
|
20
31
|
const truncate = (input, limit, options = {}) => {
|
|
21
32
|
if (typeof input !== "string") {
|
|
22
33
|
throw new TypeError(`Expected \`input\` to be a string, got ${typeof input}`);
|
|
@@ -27,56 +38,68 @@ const truncate = (input, limit, options = {}) => {
|
|
|
27
38
|
if (input === "" || limit <= 0) {
|
|
28
39
|
return "";
|
|
29
40
|
}
|
|
30
|
-
|
|
41
|
+
const normalizedInput = input.normalize("NFC");
|
|
31
42
|
const { ellipsis = DEFAULT_ELLIPSIS, position = "end", preferTruncationOnSpace = false } = options;
|
|
32
43
|
let ellipsisWidth = options.ellipsisWidth ?? ellipsis === DEFAULT_ELLIPSIS ? 1 : void 0;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
const { width } = getStringTruncatedWidth(input, {
|
|
44
|
+
ellipsisWidth ??= getStringTruncatedWidth(ellipsis, {
|
|
45
|
+
...options.width,
|
|
46
|
+
ellipsis: "",
|
|
47
|
+
ellipsisWidth: 0,
|
|
48
|
+
limit: Number.POSITIVE_INFINITY
|
|
49
|
+
}).width;
|
|
50
|
+
const { width } = getStringTruncatedWidth(normalizedInput, {
|
|
42
51
|
...options.width,
|
|
43
52
|
ellipsis,
|
|
44
53
|
ellipsisWidth
|
|
45
54
|
});
|
|
46
55
|
if (width <= limit) {
|
|
47
|
-
return
|
|
56
|
+
return normalizedInput;
|
|
48
57
|
}
|
|
49
58
|
switch (position) {
|
|
50
59
|
case "end": {
|
|
51
60
|
if (preferTruncationOnSpace) {
|
|
52
|
-
const
|
|
53
|
-
|
|
61
|
+
const targetWidth = limit - ellipsisWidth;
|
|
62
|
+
const stringIndex = widthToIndex(normalizedInput, targetWidth, options.width);
|
|
63
|
+
const nearestSpace = findNearestSpace(normalizedInput, stringIndex);
|
|
64
|
+
const nearestSpaceWidth = indexToWidth(normalizedInput, nearestSpace, options.width);
|
|
65
|
+
return slice(normalizedInput, 0, nearestSpaceWidth, {
|
|
54
66
|
width: options.width
|
|
55
67
|
}) + ellipsis;
|
|
56
68
|
}
|
|
57
|
-
return slice(
|
|
69
|
+
return slice(normalizedInput, 0, limit - ellipsisWidth, {
|
|
58
70
|
width: options.width
|
|
59
71
|
}) + ellipsis;
|
|
60
72
|
}
|
|
61
73
|
case "middle": {
|
|
62
74
|
const half = Math.floor(limit / 2);
|
|
75
|
+
const totalTextWidth = Math.max(0, limit - ellipsisWidth);
|
|
76
|
+
const leftWidth = Math.min(half, totalTextWidth);
|
|
77
|
+
const rightWidth = Math.max(0, totalTextWidth - leftWidth);
|
|
63
78
|
if (preferTruncationOnSpace) {
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
79
|
+
const firstBreakIndex = widthToIndex(normalizedInput, leftWidth, options.width);
|
|
80
|
+
const firstBreak = findNearestSpace(normalizedInput, firstBreakIndex);
|
|
81
|
+
const firstBreakWidth = indexToWidth(normalizedInput, firstBreak, options.width);
|
|
82
|
+
const secondBreakWidthTarget = width - rightWidth;
|
|
83
|
+
const secondBreakIndex = widthToIndex(normalizedInput, secondBreakWidthTarget, options.width);
|
|
84
|
+
const secondBreak = findNearestSpace(normalizedInput, secondBreakIndex, true);
|
|
85
|
+
const secondBreakWidthActual = indexToWidth(normalizedInput, secondBreak, options.width);
|
|
86
|
+
return slice(normalizedInput, 0, firstBreakWidth, { width: options.width }) + ellipsis + slice(normalizedInput, secondBreakWidthActual, width, { width: options.width }).trim();
|
|
67
87
|
}
|
|
68
|
-
return slice(
|
|
88
|
+
return slice(normalizedInput, 0, leftWidth, {
|
|
69
89
|
width: options.width
|
|
70
|
-
}) + ellipsis + slice(
|
|
90
|
+
}) + ellipsis + slice(normalizedInput, width - rightWidth, width, {
|
|
71
91
|
width: options.width
|
|
72
92
|
});
|
|
73
93
|
}
|
|
74
94
|
case "start": {
|
|
75
95
|
if (preferTruncationOnSpace) {
|
|
76
|
-
const
|
|
77
|
-
|
|
96
|
+
const targetWidth = width - limit + ellipsisWidth;
|
|
97
|
+
const stringIndex = widthToIndex(normalizedInput, targetWidth, options.width);
|
|
98
|
+
const nearestSpace = findNearestSpace(normalizedInput, stringIndex, true);
|
|
99
|
+
const nearestSpaceWidth = indexToWidth(normalizedInput, nearestSpace, options.width);
|
|
100
|
+
return ellipsis + slice(normalizedInput, nearestSpaceWidth, width, { width: options.width }).trim();
|
|
78
101
|
}
|
|
79
|
-
return ellipsis + slice(
|
|
102
|
+
return ellipsis + slice(normalizedInput, width - limit + ellipsisWidth, width, {
|
|
80
103
|
width: options.width
|
|
81
104
|
});
|
|
82
105
|
}
|
package/dist/utilities.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { L as LRUCache } from
|
|
3
|
-
|
|
1
|
+
import { a as IntervalArray } from "./packem_shared/types.d-BVNv675q.js";
|
|
2
|
+
export { L as LRUCache } from "./packem_shared/lru-cache.d-BsP6kbVJ.js";
|
|
4
3
|
declare const escapeRegExp: (char: string) => string;
|
|
5
4
|
declare const inRange: (number_: number, ranges: IntervalArray) => boolean;
|
|
6
5
|
declare const hasChinese: (char: string) => boolean;
|
|
7
6
|
declare const hasPunctuationOrSpace: (char: string) => boolean;
|
|
8
7
|
declare const findStringOccurrences: (source: string, needles: string[]) => IntervalArray;
|
|
9
|
-
|
|
10
8
|
export { escapeRegExp, findStringOccurrences, hasChinese, hasPunctuationOrSpace, inRange };
|
package/dist/utilities.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
export { default as LRUCache } from './packem_shared/LRUCache-3r3SovvR.js';
|
|
2
2
|
|
|
3
|
+
const RE_REGEXP_SPECIAL = /[.*+?^${}()|[\]\\]/g;
|
|
4
|
+
const RE_CHINESE = /[\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u3005\u3007\u3021-\u3029\u3038-\u303B\u3400-\u4DBF\u4E00-\u9FFC\uF900-\uFA6D\uFA70-\uFAD9]|\uD81B[\uDFF0\uDFF1]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A]/;
|
|
5
|
+
const RE_PUNCTUATION_OR_SPACE = /[\p{P}\p{Z}]/u;
|
|
3
6
|
const escapeRegExp = (char) => (
|
|
4
7
|
// $& means the whole matched string
|
|
5
|
-
char.replaceAll(
|
|
8
|
+
char.replaceAll(RE_REGEXP_SPECIAL, String.raw`\$&`)
|
|
6
9
|
);
|
|
7
10
|
const inRange = (number_, ranges) => ranges.some((range) => number_ >= range[0] && number_ <= range[1]);
|
|
8
|
-
const hasChinese = (char) =>
|
|
9
|
-
|
|
10
|
-
);
|
|
11
|
-
const hasPunctuationOrSpace = (char) => (
|
|
12
|
-
// Uses Unicode property escapes for Punctuation and general category for Space
|
|
13
|
-
/[\p{P}\p{Z}]/u.test(char)
|
|
14
|
-
);
|
|
11
|
+
const hasChinese = (char) => RE_CHINESE.test(char);
|
|
12
|
+
const hasPunctuationOrSpace = (char) => RE_PUNCTUATION_OR_SPACE.test(char);
|
|
15
13
|
const findStringOccurrences = (source, needles) => {
|
|
16
14
|
const ranges = [];
|
|
17
15
|
if (!Array.isArray(needles)) {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
interface WordSimilaritySortOptions {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
caseSensitive?: boolean;
|
|
3
|
+
compareFunction?: (a: string, b: string) => number;
|
|
4
4
|
}
|
|
5
5
|
declare const wordSimilaritySort: (givenWord: string, possibleWords: ReadonlyArray<string>, options?: WordSimilaritySortOptions) => string[];
|
|
6
|
-
|
|
7
|
-
export { wordSimilaritySort };
|
|
8
|
-
export type { WordSimilaritySortOptions };
|
|
6
|
+
export { WordSimilaritySortOptions, wordSimilaritySort };
|
package/dist/word-wrap.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
declare const WrapMode: {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
readonly BREAK_AT_CHARACTERS: "BREAK_AT_CHARACTERS";
|
|
3
|
+
readonly BREAK_WORDS: "BREAK_WORDS";
|
|
4
|
+
readonly PRESERVE_WORDS: "PRESERVE_WORDS";
|
|
5
|
+
readonly STRICT_WIDTH: "STRICT_WIDTH";
|
|
6
6
|
};
|
|
7
7
|
interface WordWrapOptions {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
removeZeroWidthCharacters?: boolean;
|
|
9
|
+
trim?: boolean;
|
|
10
|
+
width?: number;
|
|
11
|
+
wrapMode?: keyof typeof WrapMode;
|
|
12
12
|
}
|
|
13
13
|
declare const wordWrap: (string: string, options?: WordWrapOptions) => string;
|
|
14
|
-
|
|
15
|
-
export { WrapMode, wordWrap };
|
|
16
|
-
export type { WordWrapOptions };
|
|
14
|
+
export { WordWrapOptions, WrapMode, wordWrap };
|
package/dist/word-wrap.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { O as ESCAPES, P as ANSI_ESCAPE_LINK, Q as ANSI_SGR_TERMINATOR, S as ANSI_ESCAPE_BELL, T as ANSI_CSI, U as RE_ESCAPE_PATTERN, V as ANSI_RESET_CODES, W as END_CODE, X as RE_ZERO_WIDTH } from './packem_shared/constants-
|
|
1
|
+
import { O as ESCAPES, P as ANSI_ESCAPE_LINK, Q as ANSI_SGR_TERMINATOR, S as ANSI_ESCAPE_BELL, T as ANSI_CSI, U as RE_ESCAPE_PATTERN, V as ANSI_RESET_CODES, W as END_CODE, X as RE_ZERO_WIDTH } from './packem_shared/constants-BsZS5f0z.js';
|
|
2
2
|
import { getStringWidth } from './get-string-width.js';
|
|
3
3
|
|
|
4
|
+
const RE_ANSI_CODE = /\x1B\[(\d+)m/;
|
|
4
5
|
class AnsiStateTracker {
|
|
5
|
-
activeForeground =
|
|
6
|
-
activeBackground =
|
|
6
|
+
activeForeground = void 0;
|
|
7
|
+
activeBackground = void 0;
|
|
7
8
|
// Track other formatting (bold, italic, etc.)
|
|
8
9
|
activeFormatting = [];
|
|
9
10
|
/**
|
|
@@ -11,24 +12,24 @@ class AnsiStateTracker {
|
|
|
11
12
|
* @param sequence The escape sequence to process
|
|
12
13
|
*/
|
|
13
14
|
processEscape(sequence) {
|
|
14
|
-
const match =
|
|
15
|
+
const match = RE_ANSI_CODE.exec(sequence);
|
|
15
16
|
if (!match) {
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
const code = Number.parseInt(match[1], 10);
|
|
19
20
|
switch (code) {
|
|
20
21
|
case 0: {
|
|
21
|
-
this.activeForeground =
|
|
22
|
-
this.activeBackground =
|
|
22
|
+
this.activeForeground = void 0;
|
|
23
|
+
this.activeBackground = void 0;
|
|
23
24
|
this.activeFormatting = [];
|
|
24
25
|
break;
|
|
25
26
|
}
|
|
26
27
|
case 39: {
|
|
27
|
-
this.activeForeground =
|
|
28
|
+
this.activeForeground = void 0;
|
|
28
29
|
break;
|
|
29
30
|
}
|
|
30
31
|
case 49: {
|
|
31
|
-
this.activeBackground =
|
|
32
|
+
this.activeBackground = void 0;
|
|
32
33
|
break;
|
|
33
34
|
}
|
|
34
35
|
default: {
|
|
@@ -62,7 +63,7 @@ class AnsiStateTracker {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
/**
|
|
65
|
-
* Gets all active escape sequences to apply
|
|
66
|
+
* Gets all active escape sequences to apply.
|
|
66
67
|
* @returns String with all active escapes
|
|
67
68
|
*/
|
|
68
69
|
getStartEscapesForAllActiveAttributes() {
|
|
@@ -92,7 +93,7 @@ class AnsiStateTracker {
|
|
|
92
93
|
"\x1B[9m": "\x1B[29m"
|
|
93
94
|
// Strikethrough
|
|
94
95
|
};
|
|
95
|
-
[...this.activeFormatting].
|
|
96
|
+
[...this.activeFormatting].toReversed().forEach((formatCode) => {
|
|
96
97
|
const resetCode = formatResetMap[formatCode];
|
|
97
98
|
if (resetCode) {
|
|
98
99
|
closingEscapes.push(resetCode);
|
|
@@ -122,7 +123,6 @@ const processAnsiString = (string, options = {}) => {
|
|
|
122
123
|
const stateTracker = new AnsiStateTracker();
|
|
123
124
|
let currentText = "";
|
|
124
125
|
let isInsideEscape = false;
|
|
125
|
-
let isInsideLinkEscape = false;
|
|
126
126
|
let escapeBuffer = "";
|
|
127
127
|
let currentUrl = "";
|
|
128
128
|
let isInHyperlink = false;
|
|
@@ -150,7 +150,7 @@ const processAnsiString = (string, options = {}) => {
|
|
|
150
150
|
isInsideEscape = true;
|
|
151
151
|
escapeBuffer = character;
|
|
152
152
|
const escapeInfo = checkEscapeSequence(chars, index);
|
|
153
|
-
isInsideLinkEscape = escapeInfo
|
|
153
|
+
const { isInsideLinkEscape } = escapeInfo;
|
|
154
154
|
if (isInsideLinkEscape) {
|
|
155
155
|
let urlEnd = index + 1;
|
|
156
156
|
currentUrl = "";
|
|
@@ -177,7 +177,6 @@ const processAnsiString = (string, options = {}) => {
|
|
|
177
177
|
index = urlEnd;
|
|
178
178
|
isInHyperlink = true;
|
|
179
179
|
isInsideEscape = false;
|
|
180
|
-
isInsideLinkEscape = false;
|
|
181
180
|
escapeBuffer = "";
|
|
182
181
|
continue;
|
|
183
182
|
}
|
|
@@ -264,7 +263,7 @@ const processAnsiString = (string, options = {}) => {
|
|
|
264
263
|
|
|
265
264
|
const wrapAnsiCode = (code) => {
|
|
266
265
|
const escapeChar = ESCAPES.values().next().value;
|
|
267
|
-
return `${escapeChar}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
266
|
+
return `${escapeChar}${ANSI_CSI}${String(code)}${ANSI_SGR_TERMINATOR}`;
|
|
268
267
|
};
|
|
269
268
|
|
|
270
269
|
const wrapAnsiHyperlink = (url) => {
|
|
@@ -318,6 +317,8 @@ const preserveAnsi = (rawLines) => {
|
|
|
318
317
|
return returnValue;
|
|
319
318
|
};
|
|
320
319
|
|
|
320
|
+
const RE_SPLIT_WHITESPACE = /(?=\s)|(?<=\s)/;
|
|
321
|
+
const RE_WHITESPACE_ONLY = /^\s+$/;
|
|
321
322
|
const resetAnsiAtLineBreak = (currentLine) => {
|
|
322
323
|
if (!currentLine.includes("\x1B")) {
|
|
323
324
|
return currentLine;
|
|
@@ -356,7 +357,8 @@ const wrapWithBreakAtWidth = (string, width, trim) => {
|
|
|
356
357
|
let isInsideEscape = false;
|
|
357
358
|
let isInsideLinkEscape = false;
|
|
358
359
|
let escapeBuffer = "";
|
|
359
|
-
|
|
360
|
+
let index = 0;
|
|
361
|
+
while (index < string.length) {
|
|
360
362
|
const char = string[index];
|
|
361
363
|
if (ESCAPES.has(char)) {
|
|
362
364
|
isInsideEscape = true;
|
|
@@ -364,6 +366,7 @@ const wrapWithBreakAtWidth = (string, width, trim) => {
|
|
|
364
366
|
currentLine += char;
|
|
365
367
|
const escapeInfo = checkEscapeSequence([...string], index);
|
|
366
368
|
isInsideLinkEscape = escapeInfo.isInsideLinkEscape;
|
|
369
|
+
index += 1;
|
|
367
370
|
continue;
|
|
368
371
|
}
|
|
369
372
|
if (isInsideEscape) {
|
|
@@ -377,12 +380,14 @@ const wrapWithBreakAtWidth = (string, width, trim) => {
|
|
|
377
380
|
isInsideEscape = false;
|
|
378
381
|
ansiTracker.processEscape(escapeBuffer);
|
|
379
382
|
}
|
|
383
|
+
index += 1;
|
|
380
384
|
continue;
|
|
381
385
|
}
|
|
382
386
|
const charWidth = getStringWidth(char);
|
|
383
387
|
const isSpace = char === " ";
|
|
384
388
|
if (charWidth === 0) {
|
|
385
389
|
currentLine += char;
|
|
390
|
+
index += 1;
|
|
386
391
|
continue;
|
|
387
392
|
}
|
|
388
393
|
if (currentWidth + charWidth > width) {
|
|
@@ -394,12 +399,6 @@ const wrapWithBreakAtWidth = (string, width, trim) => {
|
|
|
394
399
|
if (isSpace && trim) {
|
|
395
400
|
while (index < string.length && string[index] === " ") {
|
|
396
401
|
index += 1;
|
|
397
|
-
if (index >= string.length) {
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
if (index < string.length) {
|
|
402
|
-
index--;
|
|
403
402
|
}
|
|
404
403
|
continue;
|
|
405
404
|
}
|
|
@@ -415,9 +414,10 @@ const wrapWithBreakAtWidth = (string, width, trim) => {
|
|
|
415
414
|
while (index < string.length && string[index] === " ") {
|
|
416
415
|
index += 1;
|
|
417
416
|
}
|
|
418
|
-
|
|
417
|
+
continue;
|
|
419
418
|
}
|
|
420
419
|
}
|
|
420
|
+
index += 1;
|
|
421
421
|
}
|
|
422
422
|
if (currentLine) {
|
|
423
423
|
rows.push(currentLine + ansiTracker.getEndEscapesForAllActiveAttributes());
|
|
@@ -437,13 +437,15 @@ const wrapCharByChar = (string, width, trim) => {
|
|
|
437
437
|
let currentWidth = 0;
|
|
438
438
|
processAnsiString(inputToProcess, {
|
|
439
439
|
getWidth: getStringWidth,
|
|
440
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity,sonarjs/no-invariant-returns
|
|
440
441
|
onSegment: (segment, stateTracker) => {
|
|
442
|
+
const segText = segment.text ?? "";
|
|
441
443
|
if (segment.isEscapeSequence) {
|
|
442
|
-
currentLine +=
|
|
444
|
+
currentLine += segText;
|
|
443
445
|
} else {
|
|
444
|
-
const isSpace =
|
|
446
|
+
const isSpace = segText === " ";
|
|
445
447
|
if (segment.width === 0) {
|
|
446
|
-
currentLine +=
|
|
448
|
+
currentLine += segText;
|
|
447
449
|
return true;
|
|
448
450
|
}
|
|
449
451
|
if (currentWidth + segment.width > width) {
|
|
@@ -456,11 +458,11 @@ const wrapCharByChar = (string, width, trim) => {
|
|
|
456
458
|
if (trim) {
|
|
457
459
|
return true;
|
|
458
460
|
}
|
|
459
|
-
rows.push(stateTracker.getStartEscapesForAllActiveAttributes() +
|
|
461
|
+
rows.push(stateTracker.getStartEscapesForAllActiveAttributes() + segText);
|
|
460
462
|
return true;
|
|
461
463
|
}
|
|
462
464
|
}
|
|
463
|
-
currentLine +=
|
|
465
|
+
currentLine += segText;
|
|
464
466
|
currentWidth += segment.width;
|
|
465
467
|
}
|
|
466
468
|
return true;
|
|
@@ -479,14 +481,14 @@ const wrapWithWordBoundaries = (string, width, trim) => {
|
|
|
479
481
|
if (inputToProcess.length === 0) {
|
|
480
482
|
return [];
|
|
481
483
|
}
|
|
482
|
-
const tokens = inputToProcess.split(
|
|
484
|
+
const tokens = inputToProcess.split(RE_SPLIT_WHITESPACE);
|
|
483
485
|
const rows = [];
|
|
484
486
|
let currentLine = "";
|
|
485
487
|
let currentWidth = 0;
|
|
486
488
|
let index = 0;
|
|
487
489
|
while (index < tokens.length) {
|
|
488
490
|
const token = tokens[index];
|
|
489
|
-
const isSpace =
|
|
491
|
+
const isSpace = RE_WHITESPACE_ONLY.test(token);
|
|
490
492
|
const tokenVisibleWidth = getStringWidth(token);
|
|
491
493
|
if (token.length === 0) {
|
|
492
494
|
index += 1;
|
|
@@ -527,14 +529,14 @@ const wrapAndBreakWords = (string, width, trim) => {
|
|
|
527
529
|
if (inputToProcess.length === 0) {
|
|
528
530
|
return [];
|
|
529
531
|
}
|
|
530
|
-
const tokens = inputToProcess.split(
|
|
532
|
+
const tokens = inputToProcess.split(RE_SPLIT_WHITESPACE);
|
|
531
533
|
const rows = [];
|
|
532
534
|
let currentLine = "";
|
|
533
535
|
let currentWidth = 0;
|
|
534
536
|
let index = 0;
|
|
535
537
|
while (index < tokens.length) {
|
|
536
538
|
const token = tokens[index];
|
|
537
|
-
const isSpace =
|
|
539
|
+
const isSpace = RE_WHITESPACE_ONLY.test(token);
|
|
538
540
|
const tokenVisibleWidth = getStringWidth(token);
|
|
539
541
|
if (token.length === 0) {
|
|
540
542
|
index += 1;
|
|
@@ -550,10 +552,10 @@ const wrapAndBreakWords = (string, width, trim) => {
|
|
|
550
552
|
}
|
|
551
553
|
const brokenLines = wrapWithBreakAtWidth(token, width, trim);
|
|
552
554
|
if (brokenLines.length > 0) {
|
|
553
|
-
for (let
|
|
554
|
-
rows.push(brokenLines[
|
|
555
|
+
for (let brokenLineIndex = 0; brokenLineIndex < brokenLines.length - 1; brokenLineIndex += 1) {
|
|
556
|
+
rows.push(brokenLines[brokenLineIndex]);
|
|
555
557
|
}
|
|
556
|
-
currentLine = brokenLines
|
|
558
|
+
currentLine = brokenLines.at(-1);
|
|
557
559
|
currentWidth = getStringWidth(currentLine);
|
|
558
560
|
} else {
|
|
559
561
|
currentLine = "";
|
|
@@ -603,7 +605,7 @@ const wordWrap = (string, options = {}) => {
|
|
|
603
605
|
if (trim && string.trim() === "") {
|
|
604
606
|
return "";
|
|
605
607
|
}
|
|
606
|
-
let normalizedString =
|
|
608
|
+
let normalizedString = string.normalize("NFC").replaceAll("\r\n", "\n");
|
|
607
609
|
if (removeZeroWidthCharacters) {
|
|
608
610
|
normalizedString = normalizedString.replaceAll(RE_ZERO_WIDTH, "");
|
|
609
611
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visulima/string",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.10",
|
|
4
4
|
"description": "Functions for manipulating strings.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"visulima",
|
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
"CHANGELOG.md"
|
|
229
229
|
],
|
|
230
230
|
"engines": {
|
|
231
|
-
"node": "
|
|
231
|
+
"node": "^22.14.0 || >=24.10.0"
|
|
232
232
|
},
|
|
233
233
|
"publishConfig": {
|
|
234
234
|
"access": "public",
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { distance } from './closest-IHuSvnSn.js';
|
|
2
|
-
export { closest } from './closest-IHuSvnSn.js';
|
|
3
|
-
|
|
4
|
-
const closestN = (string_, array, n) => {
|
|
5
|
-
const distances = new Array(n).fill(Infinity);
|
|
6
|
-
const values = new Array(n).fill(null);
|
|
7
|
-
for (let value of array) {
|
|
8
|
-
let distribution = distance(string_, value);
|
|
9
|
-
for (let index = 0; index < n; index++) {
|
|
10
|
-
if (distribution < distances[index]) {
|
|
11
|
-
[distribution, distances[index]] = [distances[index], distribution];
|
|
12
|
-
[value, values[index]] = [values[index], value];
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return values;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export { closestN, distance };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
declare class LRUCache<K, V> {
|
|
2
|
-
private readonly capacity;
|
|
3
|
-
private readonly cache;
|
|
4
|
-
private keyOrder;
|
|
5
|
-
constructor(capacity: number);
|
|
6
|
-
get(key: K): V | undefined;
|
|
7
|
-
has(key: K): boolean;
|
|
8
|
-
set(key: K, value: V): void;
|
|
9
|
-
delete(key: K): void;
|
|
10
|
-
clear(): void;
|
|
11
|
-
size(): number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export { LRUCache as L };
|