@cjser/cli-truncate 6.0.0-cjser.2 → 6.1.0-cjser.2

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.
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
26
  ));
27
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
28
 
29
- // packages/@cjser/cli-truncate/index.js
29
+ // packages/@cjser/cli-truncate.tmp-26-1782663828634/index.js
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
32
  default: () => cliTruncate
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  module.exports = __toCommonJS(index_exports);
35
35
  var import_slice_ansi = __toESM(require("@cjser/slice-ansi"), 1);
36
36
  var import_string_width = __toESM(require("@cjser/string-width"), 1);
37
+ var validPositions = /* @__PURE__ */ new Set(["start", "middle", "end"]);
37
38
  function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) {
38
39
  if (string.charAt(wantedIndex) === " ") {
39
40
  return wantedIndex;
@@ -47,6 +48,23 @@ function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) {
47
48
  }
48
49
  return wantedIndex;
49
50
  }
51
+ function validateInput(text, columns, position, truncationCharacter) {
52
+ if (typeof text !== "string") {
53
+ throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`);
54
+ }
55
+ if (typeof columns !== "number") {
56
+ throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`);
57
+ }
58
+ if (!Number.isFinite(columns)) {
59
+ throw new TypeError(`Expected \`columns\` to be a finite number, got ${columns}`);
60
+ }
61
+ if (!validPositions.has(position)) {
62
+ throw new TypeError(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
63
+ }
64
+ if (typeof truncationCharacter !== "string") {
65
+ throw new TypeError(`Expected \`options.truncationCharacter\` to be a string, got ${typeof truncationCharacter}`);
66
+ }
67
+ }
50
68
  function cliTruncate(text, columns, options = {}) {
51
69
  const {
52
70
  position = "end",
@@ -54,12 +72,7 @@ function cliTruncate(text, columns, options = {}) {
54
72
  preferTruncationOnSpace = false
55
73
  } = options;
56
74
  let { truncationCharacter = "\u2026" } = options;
57
- if (typeof text !== "string") {
58
- throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`);
59
- }
60
- if (typeof columns !== "number") {
61
- throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`);
62
- }
75
+ validateInput(text, columns, position, truncationCharacter);
63
76
  if (columns < 1) {
64
77
  return "";
65
78
  }
@@ -135,14 +148,18 @@ function cliTruncate(text, columns, options = {}) {
135
148
  if (position === "middle") {
136
149
  if (space) {
137
150
  truncationCharacter = ` ${truncationCharacter} `;
151
+ if ((0, import_string_width.default)(truncationCharacter) >= columns) {
152
+ truncationCharacter = truncationCharacter.trim();
153
+ }
138
154
  }
139
- const half = Math.floor(columns / 2);
155
+ const truncationWidth = (0, import_string_width.default)(truncationCharacter);
156
+ const half = Math.min(Math.floor(columns / 2), Math.max(0, columns - truncationWidth));
140
157
  if (preferTruncationOnSpace) {
141
158
  const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text, half);
142
- const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + 1, true);
159
+ const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + truncationWidth, true);
143
160
  return (0, import_slice_ansi.default)(text, 0, spaceNearFirstBreakPoint) + truncationCharacter + (0, import_slice_ansi.default)(text, spaceNearSecondBreakPoint, length).trim();
144
161
  }
145
- return (0, import_slice_ansi.default)(text, 0, half) + truncationCharacter + (0, import_slice_ansi.default)(text, length - (columns - half) + (0, import_string_width.default)(truncationCharacter), length);
162
+ return (0, import_slice_ansi.default)(text, 0, half) + truncationCharacter + (0, import_slice_ansi.default)(text, length - (columns - half) + truncationWidth, length);
146
163
  }
147
164
  if (position === "end") {
148
165
  if (preferTruncationOnSpace) {
@@ -156,5 +173,4 @@ function cliTruncate(text, columns, options = {}) {
156
173
  const left = (0, import_slice_ansi.default)(text, 0, columns - (0, import_string_width.default)(truncationCharacter));
157
174
  return appendWithInheritedStyleFromEnd(left, truncationCharacter);
158
175
  }
159
- throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
160
176
  }
package/index.d.ts CHANGED
@@ -76,7 +76,7 @@ export type Options = {
76
76
  Truncate a string to a specific width in the terminal.
77
77
 
78
78
  @param text - The text to truncate.
79
- @param columns - The number of columns to occupy in the terminal.
79
+ @param columns - The finite number of columns to occupy in the terminal.
80
80
 
81
81
  @example
82
82
  ```
@@ -107,7 +107,7 @@ cliTruncate('안녕하세요', 3);
107
107
 
108
108
  // Truncate the paragraph to the terminal width
109
109
  const paragraph = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa.';
110
- cliTruncate(paragraph, process.stdout.columns);
110
+ cliTruncate(paragraph, process.stdout.columns ?? 80);
111
111
  //=> 'Lorem ipsum dolor sit amet, consectetuer adipiscing…'
112
112
  ```
113
113
  */
package/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import sliceAnsi from '@cjser/slice-ansi';
2
2
  import stringWidth from '@cjser/string-width';
3
3
 
4
+ const validPositions = new Set(['start', 'middle', 'end']);
5
+
4
6
  function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) {
5
7
  if (string.charAt(wantedIndex) === ' ') {
6
8
  return wantedIndex;
@@ -18,6 +20,28 @@ function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) {
18
20
  return wantedIndex;
19
21
  }
20
22
 
23
+ function validateInput(text, columns, position, truncationCharacter) {
24
+ if (typeof text !== 'string') {
25
+ throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`);
26
+ }
27
+
28
+ if (typeof columns !== 'number') {
29
+ throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`);
30
+ }
31
+
32
+ if (!Number.isFinite(columns)) {
33
+ throw new TypeError(`Expected \`columns\` to be a finite number, got ${columns}`);
34
+ }
35
+
36
+ if (!validPositions.has(position)) {
37
+ throw new TypeError(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
38
+ }
39
+
40
+ if (typeof truncationCharacter !== 'string') {
41
+ throw new TypeError(`Expected \`options.truncationCharacter\` to be a string, got ${typeof truncationCharacter}`);
42
+ }
43
+ }
44
+
21
45
  export default function cliTruncate(text, columns, options = {}) {
22
46
  const {
23
47
  position = 'end',
@@ -27,13 +51,7 @@ export default function cliTruncate(text, columns, options = {}) {
27
51
 
28
52
  let {truncationCharacter = '…'} = options;
29
53
 
30
- if (typeof text !== 'string') {
31
- throw new TypeError(`Expected \`input\` to be a string, got ${typeof text}`);
32
- }
33
-
34
- if (typeof columns !== 'number') {
35
- throw new TypeError(`Expected \`columns\` to be a number, got ${typeof columns}`);
36
- }
54
+ validateInput(text, columns, position, truncationCharacter);
37
55
 
38
56
  if (columns < 1) {
39
57
  return '';
@@ -132,20 +150,30 @@ export default function cliTruncate(text, columns, options = {}) {
132
150
  if (position === 'middle') {
133
151
  if (space) {
134
152
  truncationCharacter = ` ${truncationCharacter} `;
153
+
154
+ // Drop the padding spaces if the padded character does not fit, so the
155
+ // truncation character itself never exceeds the budget.
156
+ if (stringWidth(truncationCharacter) >= columns) {
157
+ truncationCharacter = truncationCharacter.trim();
158
+ }
135
159
  }
136
160
 
137
- const half = Math.floor(columns / 2);
161
+ const truncationWidth = stringWidth(truncationCharacter);
162
+ // Reserve room for the truncation character before splitting the budget
163
+ // between the two sides, otherwise small budgets overflow (e.g. a width of
164
+ // 4 was returned for `columns: 2`).
165
+ const half = Math.min(Math.floor(columns / 2), Math.max(0, columns - truncationWidth));
138
166
 
139
167
  if (preferTruncationOnSpace) {
140
168
  const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text, half);
141
- const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + 1, true);
169
+ const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + truncationWidth, true);
142
170
  return sliceAnsi(text, 0, spaceNearFirstBreakPoint) + truncationCharacter + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim();
143
171
  }
144
172
 
145
173
  return (
146
174
  sliceAnsi(text, 0, half)
147
175
  + truncationCharacter
148
- + sliceAnsi(text, length - (columns - half) + stringWidth(truncationCharacter), length)
176
+ + sliceAnsi(text, length - (columns - half) + truncationWidth, length)
149
177
  );
150
178
  }
151
179
 
@@ -163,6 +191,4 @@ export default function cliTruncate(text, columns, options = {}) {
163
191
  const left = sliceAnsi(text, 0, columns - stringWidth(truncationCharacter));
164
192
  return appendWithInheritedStyleFromEnd(left, truncationCharacter);
165
193
  }
166
-
167
- throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
168
194
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cjser/cli-truncate",
3
- "version": "6.0.0-cjser.2",
3
+ "version": "6.1.0-cjser.2",
4
4
  "description": "Truncate a string to a specific width in the terminal",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -57,16 +57,16 @@
57
57
  "types": "./index.d.ts",
58
58
  "main": "./dist-cjser/index.cjs",
59
59
  "cjser": {
60
- "sourceVersion": "6.0.0",
60
+ "sourceVersion": "6.1.0",
61
61
  "cjserVersion": 2,
62
62
  "original": {
63
63
  "name": "cli-truncate",
64
- "version": "6.0.0",
64
+ "version": "6.1.0",
65
65
  "exports": {
66
66
  "types": "./index.d.ts",
67
67
  "default": "./index.js"
68
68
  },
69
- "repository": "sindresorhus/cli-truncate",
69
+ "repository": "github:sindresorhus/cli-truncate",
70
70
  "dependencies": {
71
71
  "slice-ansi": "^9.0.0",
72
72
  "string-width": "^8.2.0"
package/readme.md CHANGED
@@ -44,7 +44,7 @@ cliTruncate('안녕하세요', 3);
44
44
 
45
45
  // Truncate the paragraph to the terminal width
46
46
  const paragraph = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa.';
47
- cliTruncate(paragraph, process.stdout.columns);
47
+ cliTruncate(paragraph, process.stdout.columns ?? 80);
48
48
  //=> 'Lorem ipsum dolor sit amet, consectetuer adipiscing…'
49
49
  ```
50
50
 
@@ -62,7 +62,7 @@ The text to truncate.
62
62
 
63
63
  Type: `number`
64
64
 
65
- The number of columns to occupy in the terminal.
65
+ The finite number of columns to occupy in the terminal.
66
66
 
67
67
  #### options
68
68