@synstack/str 1.1.2 → 1.2.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.
@@ -3,133 +3,261 @@ import * as changeCase from "change-case";
3
3
  import { type Stringable } from "../../shared/src/ts.utils.ts";
4
4
  import * as lib from "./str.lib.ts";
5
5
 
6
+ /**
7
+ * A chainable string manipulation class that extends Pipeable
8
+ * Provides a fluent interface for string operations with full TypeScript support
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { str } from '@synstack/str'
13
+ *
14
+ * // Basic chaining
15
+ * const result = str('Hello World')
16
+ * .trim()
17
+ * .split(' ')
18
+ * .at(0)
19
+ * .$
20
+ *
21
+ * // Advanced chaining with Pipeable methods
22
+ * const modified = str('hello-world')
23
+ * ._((s) => s.camelCase())
24
+ * ._$((value) => value.toUpperCase())
25
+ * .$
26
+ * ```
27
+ */
6
28
  export class Str extends Pipeable<Str, string> {
7
29
  private readonly text: string;
8
30
 
31
+ /**
32
+ * Create a new Str instance
33
+ * @param text - The input string to wrap
34
+ * @example
35
+ * ```typescript
36
+ * const s = new Str('Hello World')
37
+ * // or use the convenience function
38
+ * const s = str('Hello World')
39
+ * ```
40
+ */
9
41
  public constructor(text: string) {
10
42
  super();
11
43
  this.text = text;
12
44
  }
13
45
 
46
+ /**
47
+ * Get the underlying string value
48
+ * @returns The wrapped string value
49
+ */
14
50
  public valueOf(): string {
15
51
  return this.text;
16
52
  }
17
53
 
54
+ /**
55
+ * Convert the Str instance to a string
56
+ * @returns The wrapped string value
57
+ */
18
58
  public toString() {
19
59
  return this.text;
20
60
  }
21
61
 
62
+ /**
63
+ * Get the current Str instance
64
+ * @returns The current Str instance
65
+ * @internal Used by Pipeable
66
+ */
22
67
  public instanceOf(): Str {
23
68
  return this;
24
69
  }
25
70
 
26
71
  /**
27
- * Remove empty lines at the start of the text but leave whitespace on the first line with content
72
+ * Remove empty lines at the start of the text
73
+ * @returns A new Str instance with empty lines removed from the start
74
+ * @example
75
+ * ```typescript
76
+ * str('\n\n Hello').chopEmptyLinesStart().$ // ' Hello'
77
+ * ```
28
78
  */
29
79
  public chopEmptyLinesStart() {
30
80
  return new Str(lib.chopEmptyLinesStart(this.text));
31
81
  }
32
82
 
33
83
  /**
34
- * Remove empty lines at the end of the text but leave whitespace on the last line with content
84
+ * Remove empty lines at the end of the text
85
+ * @returns A new Str instance with empty lines removed from the end
86
+ * @example
87
+ * ```typescript
88
+ * str('Hello\n\n').chopEmptyLinesEnd().$ // 'Hello'
89
+ * ```
35
90
  */
36
91
  public chopEmptyLinesEnd() {
37
92
  return new Str(lib.chopEmptyLinesEnd(this.text));
38
93
  }
39
94
 
40
95
  /**
41
- * Remove all space (\s) characters in lines without content
96
+ * Remove whitespace from empty lines
97
+ * @returns A new Str instance with whitespace removed from empty lines
98
+ * @example
99
+ * ```typescript
100
+ * str('Hello\n \nWorld').trimEmptyLines().$ // 'Hello\n\nWorld'
101
+ * ```
42
102
  */
43
103
  public trimEmptyLines() {
44
104
  return new Str(lib.trimEmptyLines(this.text));
45
105
  }
46
106
 
47
107
  /**
48
- * Remove all spaces (\s) characters at the end of lines
108
+ * Remove trailing spaces from all lines
109
+ * @returns A new Str instance with trailing spaces removed from all lines
110
+ * @example
111
+ * ```typescript
112
+ * str('Hello \nWorld ').trimLinesTrailingSpaces().$ // 'Hello\nWorld'
113
+ * ```
49
114
  */
50
115
  public trimLinesTrailingSpaces() {
51
116
  return new Str(lib.trimLinesTrailingSpaces(this.text));
52
117
  }
53
118
 
54
119
  /**
55
- * Removes the leading and trailing white space and line terminator characters
120
+ * Remove leading and trailing whitespace
121
+ * @returns A new Str instance with whitespace removed from both ends
122
+ * @example
123
+ * ```typescript
124
+ * str(' Hello ').trim().$ // 'Hello'
125
+ * ```
56
126
  */
57
127
  public trim() {
58
128
  return new Str(lib.trim(this.text));
59
129
  }
60
130
 
61
131
  /**
62
- * Removes the leading white space and line terminator characters
132
+ * Remove leading whitespace
133
+ * @returns A new Str instance with leading whitespace removed
134
+ * @example
135
+ * ```typescript
136
+ * str(' Hello ').trimStart().$ // 'Hello '
137
+ * ```
63
138
  */
64
139
  public trimStart() {
65
140
  return new Str(lib.trimStart(this.text));
66
141
  }
67
142
 
68
143
  /**
69
- * Removes the trailing white space and line terminator characters
144
+ * Remove trailing whitespace
145
+ * @returns A new Str instance with trailing whitespace removed
146
+ * @example
147
+ * ```typescript
148
+ * str(' Hello ').trimEnd().$ // ' Hello'
149
+ * ```
70
150
  */
71
151
  public trimEnd() {
72
152
  return new Str(lib.trimEnd(this.text));
73
153
  }
74
154
 
75
155
  /**
76
- * Split a string into substrings using the specified separator and return them as an array
156
+ * Split the string into an array of Str instances
157
+ * @param separator - String or RegExp to split on
158
+ * @param limit - Maximum number of splits to perform
159
+ * @returns Array of Str instances
160
+ * @example
161
+ * ```typescript
162
+ * str('a,b,c').split(',') // [Str('a'), Str('b'), Str('c')]
163
+ * str('a b c').split(' ', 2) // [Str('a'), Str('b')]
164
+ * ```
77
165
  */
78
166
  public split(separator: string | RegExp, limit?: number) {
79
167
  return lib.split(this.text, separator, limit).map((v) => new Str(v));
80
168
  }
81
169
 
82
170
  /**
83
- * Add line numbers to a string
84
- * @param separator The separator to use between the line number and the line content.
85
- * Defaults to ":"
171
+ * Add line numbers to each line
172
+ * @param separator - String to separate line numbers from content
173
+ * @returns A new Str instance with line numbers added
174
+ * @example
175
+ * ```typescript
176
+ * str('A\nB').addLineNumbers().$ // '0:A\n1:B'
177
+ * str('A\nB').addLineNumbers(' -> ').$ // '0 -> A\n1 -> B'
178
+ * ```
86
179
  */
87
180
  public addLineNumbers(separator: string = ":") {
88
181
  return new Str(lib.addLineNumbers(this.text, separator));
89
182
  }
90
183
 
91
184
  /**
92
- * Returns the character at the specified index
93
- * @return string or undefined if the index is out of bounds
185
+ * Get the character at a specific index
186
+ * @param index - Zero-based position in the string
187
+ * @returns The character at the index, or undefined if out of bounds
188
+ * @example
189
+ * ```typescript
190
+ * str('Hello').at(0) // 'H'
191
+ * str('Hello').at(-1) // 'o'
192
+ * ```
94
193
  */
95
194
  public at(index: number) {
96
195
  return this.text.at(index);
97
196
  }
98
197
 
99
198
  /**
100
- * Returns the length of the string
199
+ * Get the length of the string
200
+ * @returns The number of characters in the string
201
+ * @example
202
+ * ```typescript
203
+ * str('Hello').length() // 5
204
+ * str('').length() // 0
205
+ * ```
101
206
  */
102
207
  public length() {
103
208
  return this.text.length;
104
209
  }
105
210
 
106
211
  /**
107
- * Indent the string by the specified number of spaces
108
- * @param size The number of spaces to indent by
109
- * @param char The character to use for indentation. Defaults to " "
212
+ * Indent each line by a specified number of spaces
213
+ * @param size - Number of spaces to add
214
+ * @param char - Character to use for indentation
215
+ * @returns A new Str instance with added indentation
216
+ * @example
217
+ * ```typescript
218
+ * str('Hello\nWorld').indent(2).$ // ' Hello\n World'
219
+ * str('A\nB').indent(2, '-').$ // '--A\n--B'
220
+ * ```
110
221
  */
111
222
  public indent(size: number, char: string = " ") {
112
223
  return new Str(lib.indent(this.text, size, char));
113
224
  }
114
225
 
115
226
  /**
116
- * Dedent the string by the specified number of spaces
117
- * @param indentation The number of spaces to dedent by.
118
- * If not provided, it will be calculated automatically based on the maximum indentation in the string.
227
+ * Remove indentation from each line
228
+ * @param indentation - Optional number of spaces to remove
229
+ * @returns A new Str instance with indentation removed
230
+ * @example
231
+ * ```typescript
232
+ * str(' Hello\n World').dedent().$ // 'Hello\n World'
233
+ * str(' A\n B').dedent(2).$ // ' A\nB'
234
+ * ```
119
235
  */
120
236
  public dedent(indentation?: number) {
121
237
  return new Str(lib.dedent(this.text, indentation));
122
238
  }
123
239
 
124
240
  /**
125
- * Chop the string at the start by the specified number of characters
241
+ * Remove characters from the start of the string
242
+ * @param count - Number of characters to remove
243
+ * @returns A new Str instance with characters removed from the start
244
+ * @example
245
+ * ```typescript
246
+ * str('Hello').chopStart(2).$ // 'llo'
247
+ * ```
126
248
  */
127
249
  public chopStart(count: number) {
128
250
  return new Str(lib.chopStart(this.text, count));
129
251
  }
130
252
 
131
253
  /**
132
- * Chop the string at the end by the specified number of characters
254
+ * Remove characters from the end of the string
255
+ * @param count - Number of characters to remove
256
+ * @returns A new Str instance with characters removed from the end
257
+ * @example
258
+ * ```typescript
259
+ * str('Hello').chopEnd(2).$ // 'Hel'
260
+ * ```
133
261
  */
134
262
  public chopEnd(count: number) {
135
263
  if (count === 0) return this;
@@ -137,8 +265,14 @@ export class Str extends Pipeable<Str, string> {
137
265
  }
138
266
 
139
267
  /**
140
- * Remove successive newlines of the specified repetition or more
141
- * @param maxRepeat the maximum number of newlines to allow
268
+ * Limit consecutive newlines to a maximum count
269
+ * @param maxRepeat - Maximum number of consecutive newlines to allow
270
+ * @returns A new Str instance with limited consecutive newlines
271
+ * @example
272
+ * ```typescript
273
+ * str('A\n\n\nB').chopRepeatNewlines(1).$ // 'A\nB'
274
+ * str('A\n\n\nB').chopRepeatNewlines(2).$ // 'A\n\nB'
275
+ * ```
142
276
  */
143
277
  public chopRepeatNewlines(maxRepeat: number) {
144
278
  if (maxRepeat === 0) return this;
@@ -146,146 +280,293 @@ export class Str extends Pipeable<Str, string> {
146
280
  }
147
281
 
148
282
  /**
149
- * Take the first n characters of the string
283
+ * Take characters from the start of the string
284
+ * @param count - Number of characters to take
285
+ * @returns A new Str instance with the first n characters
286
+ * @example
287
+ * ```typescript
288
+ * str('Hello').takeStart(2).$ // 'He'
289
+ * ```
150
290
  */
151
291
  public takeStart(count: number) {
152
292
  return new Str(lib.takeStart(this.text, count));
153
293
  }
154
294
 
155
295
  /**
156
- * Take the last n characters of the string
296
+ * Take characters from the end of the string
297
+ * @param count - Number of characters to take
298
+ * @returns A new Str instance with the last n characters
299
+ * @example
300
+ * ```typescript
301
+ * str('Hello').takeEnd(2).$ // 'lo'
302
+ * ```
157
303
  */
158
304
  public takeEnd(count: number) {
159
305
  return new Str(lib.takeEnd(this.text, count));
160
306
  }
161
307
 
162
308
  /**
163
- * Returns the last line of the string
309
+ * Get the last line of the string
310
+ * @returns A new Str instance containing the last line
311
+ * @example
312
+ * ```typescript
313
+ * str('Hello\nWorld').lastLine().$ // 'World'
314
+ * ```
164
315
  */
165
316
  public lastLine() {
166
317
  return new Str(lib.lastLine(this.text));
167
318
  }
168
319
 
169
320
  /**
170
- * Returns the first line of the string
321
+ * Get the first line of the string
322
+ * @returns A new Str instance containing the first line
323
+ * @example
324
+ * ```typescript
325
+ * str('Hello\nWorld').firstLine().$ // 'Hello'
326
+ * ```
171
327
  */
172
328
  public firstLine() {
173
329
  return new Str(lib.firstLine(this.text));
174
330
  }
175
331
 
176
332
  /**
177
- * Returns the number of leading spaces in the string
333
+ * Count leading space characters
334
+ * @returns The number of leading space characters
335
+ * @example
336
+ * ```typescript
337
+ * str(' Hello').leadingSpacesCount() // 2
338
+ * str('Hello').leadingSpacesCount() // 0
339
+ * ```
178
340
  */
179
341
  public leadingSpacesCount() {
180
342
  return lib.leadingSpacesCount(this.text);
181
343
  }
182
344
 
183
345
  /**
184
- * Returns the indentation level of the string skipping empty lines in the process
346
+ * Get the minimum indentation level of non-empty lines
347
+ * @returns The number of spaces in the minimum indentation
348
+ * @example
349
+ * ```typescript
350
+ * str(' Hello\n World').indentation() // 2
351
+ * str('Hello\n World').indentation() // 0
352
+ * ```
185
353
  */
186
354
  public indentation() {
187
355
  return lib.indentation(this.text);
188
356
  }
189
357
 
190
358
  /**
191
- * Returns true if the string is empty or contains only whitespace
359
+ * Check if the string is empty or contains only whitespace
360
+ * @returns True if empty or whitespace-only, false otherwise
361
+ * @example
362
+ * ```typescript
363
+ * str('').isEmpty() // true
364
+ * str(' \n').isEmpty() // true
365
+ * str('Hello').isEmpty() // false
366
+ * ```
192
367
  */
193
368
  public isEmpty() {
194
369
  return lib.isEmpty(this.text);
195
370
  }
196
371
 
197
372
  /**
198
- * Converts the string to camel case
373
+ * Replace the first occurrence of a substring or pattern
374
+ * @param searchValue - The string or pattern to search for
375
+ * @param replaceValue - The string to replace the match with
376
+ * @returns A new Str instance with the first match replaced
377
+ * @example
378
+ * ```typescript
379
+ * str('Hello World').replace('o', '0').$ // 'Hell0 World'
380
+ * str('abc abc').replace(/[a-z]/, 'X').$ // 'Xbc abc'
381
+ * ```
382
+ */
383
+ public replace(searchValue: string | RegExp, replaceValue: string) {
384
+ return new Str(lib.replace(this.text, searchValue, replaceValue));
385
+ }
386
+
387
+ /**
388
+ * Replace all occurrences of a substring or pattern
389
+ * @param searchValue - The string or pattern to search for
390
+ * @param replaceValue - The string to replace the matches with
391
+ * @returns A new Str instance with all matches replaced
392
+ * @example
393
+ * ```typescript
394
+ * str('Hello World').replaceAll('o', '0').$ // 'Hell0 W0rld'
395
+ * str('abc abc').replaceAll(/[a-z]/g, 'X').$ // 'XXX XXX'
396
+ * ```
397
+ */
398
+ public replaceAll(searchValue: string | RegExp, replaceValue: string) {
399
+ return new Str(lib.replaceAll(this.text, searchValue, replaceValue));
400
+ }
401
+
402
+ /**
403
+ * Convert string to camelCase
404
+ * @returns A new Str instance in camelCase
405
+ * @example
406
+ * ```typescript
407
+ * str('hello-world').camelCase().$ // 'helloWorld'
408
+ * ```
199
409
  */
200
410
  public camelCase() {
201
411
  return new Str(changeCase.camelCase(this.text));
202
412
  }
203
413
 
204
414
  /**
205
- * Converts the string to capital case
415
+ * Convert string to Capital Case
416
+ * @returns A new Str instance in Capital Case
417
+ * @example
418
+ * ```typescript
419
+ * str('hello-world').capitalCase().$ // 'Hello World'
420
+ * ```
206
421
  */
207
422
  public capitalCase() {
208
423
  return new Str(changeCase.capitalCase(this.text));
209
424
  }
210
425
 
211
426
  /**
212
- * Converts the string to constant case
427
+ * Convert string to CONSTANT_CASE
428
+ * @returns A new Str instance in CONSTANT_CASE
429
+ * @example
430
+ * ```typescript
431
+ * str('hello-world').constantCase().$ // 'HELLO_WORLD'
432
+ * ```
213
433
  */
214
434
  public constantCase() {
215
435
  return new Str(changeCase.constantCase(this.text));
216
436
  }
217
437
 
218
438
  /**
219
- * Converts the string to dot case
439
+ * Convert string to dot.case
440
+ * @returns A new Str instance in dot.case
441
+ * @example
442
+ * ```typescript
443
+ * str('hello-world').dotCase().$ // 'hello.world'
444
+ * ```
220
445
  */
221
446
  public dotCase() {
222
447
  return new Str(changeCase.dotCase(this.text));
223
448
  }
224
449
 
225
450
  /**
226
- * Converts the string to kebab case
451
+ * Convert string to kebab-case
452
+ * @returns A new Str instance in kebab-case
453
+ * @example
454
+ * ```typescript
455
+ * str('helloWorld').kebabCase().$ // 'hello-world'
456
+ * ```
227
457
  */
228
458
  public kebabCase() {
229
459
  return new Str(changeCase.kebabCase(this.text));
230
460
  }
231
461
 
232
462
  /**
233
- * Converts the string to no case
463
+ * Convert string to no case
464
+ * @returns A new Str instance with no case
465
+ * @example
466
+ * ```typescript
467
+ * str('helloWorld').noCase().$ // 'hello world'
468
+ * ```
234
469
  */
235
470
  public noCase() {
236
471
  return new Str(changeCase.noCase(this.text));
237
472
  }
238
473
 
239
474
  /**
240
- * Converts the string to pascal case
475
+ * Convert string to PascalCase
476
+ * @returns A new Str instance in PascalCase
477
+ * @example
478
+ * ```typescript
479
+ * str('hello-world').pascalCase().$ // 'HelloWorld'
480
+ * ```
241
481
  */
242
482
  public pascalCase() {
243
483
  return new Str(changeCase.pascalCase(this.text));
244
484
  }
245
485
 
246
486
  /**
247
- * Converts the string to pascal snake case
487
+ * Convert string to Pascal_Snake_Case
488
+ * @returns A new Str instance in Pascal_Snake_Case
489
+ * @example
490
+ * ```typescript
491
+ * str('hello-world').pascalSnakeCase().$ // 'Hello_World'
492
+ * ```
248
493
  */
249
494
  public pascalSnakeCase() {
250
495
  return new Str(changeCase.pascalSnakeCase(this.text));
251
496
  }
252
497
 
253
498
  /**
254
- * Converts the string to path case
499
+ * Convert string to path/case
500
+ * @returns A new Str instance in path/case
501
+ * @example
502
+ * ```typescript
503
+ * str('hello-world').pathCase().$ // 'hello/world'
504
+ * ```
255
505
  */
256
506
  public pathCase() {
257
507
  return new Str(changeCase.pathCase(this.text));
258
508
  }
259
509
 
260
510
  /**
261
- * Converts the string to sentence case
511
+ * Convert string to Sentence case
512
+ * @returns A new Str instance in Sentence case
513
+ * @example
514
+ * ```typescript
515
+ * str('hello-world').sentenceCase().$ // 'Hello world'
516
+ * ```
262
517
  */
263
518
  public sentenceCase() {
264
519
  return new Str(changeCase.sentenceCase(this.text));
265
520
  }
266
521
 
267
522
  /**
268
- * Converts the string to snake case
523
+ * Convert string to snake_case
524
+ * @returns A new Str instance in snake_case
525
+ * @example
526
+ * ```typescript
527
+ * str('helloWorld').snakeCase().$ // 'hello_world'
528
+ * ```
269
529
  */
270
530
  public snakeCase() {
271
531
  return new Str(changeCase.snakeCase(this.text));
272
532
  }
273
533
 
274
534
  /**
275
- * Converts the string to train case
535
+ * Convert string to Train-Case
536
+ * @returns A new Str instance in Train-Case
537
+ * @example
538
+ * ```typescript
539
+ * str('hello-world').trainCase().$ // 'Hello-World'
540
+ * ```
276
541
  */
277
542
  public trainCase() {
278
543
  return new Str(changeCase.trainCase(this.text));
279
544
  }
280
545
 
281
546
  /**
282
- * Shorthand for `.toString()`
547
+ * Get the underlying string value
548
+ * @returns The wrapped string value
549
+ * @example
550
+ * ```typescript
551
+ * str('hello').str // 'hello'
552
+ * ```
283
553
  */
284
554
  public get str() {
285
555
  return this.toString();
286
556
  }
287
557
  }
288
558
 
559
+ /**
560
+ * Create a new Str instance from any stringable value
561
+ * @param text - Any value that can be converted to a string
562
+ * @returns A new Str instance wrapping the string value
563
+ * @example
564
+ * ```typescript
565
+ * str('hello') // from string
566
+ * str(123) // from number
567
+ * str({ toString() }) // from object with toString
568
+ * ```
569
+ */
289
570
  export const str = (text: Stringable) => {
290
571
  return new Str(text.toString());
291
572
  };