@synstack/str 1.0.1-alpha.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.
@@ -0,0 +1,291 @@
1
+ import { Pipeable } from "@synstack/pipe";
2
+ import * as changeCase from "change-case";
3
+ import * as lib from "./str.lib";
4
+
5
+ export type Stringable = {
6
+ toString: () => string;
7
+ };
8
+
9
+ export class Str extends Pipeable<Str, string> {
10
+ public constructor(private readonly text: string) {
11
+ super();
12
+ }
13
+
14
+ public valueOf(): string {
15
+ return this.text;
16
+ }
17
+
18
+ public toString() {
19
+ return this.text;
20
+ }
21
+
22
+ public instanceOf(): Str {
23
+ return this;
24
+ }
25
+
26
+ /**
27
+ * Remove empty lines at the start of the text but leave whitespace on the first line with content
28
+ */
29
+ public chopEmptyLinesStart() {
30
+ return new Str(lib.chopEmptyLinesStart(this.text));
31
+ }
32
+
33
+ /**
34
+ * Remove empty lines at the end of the text but leave whitespace on the last line with content
35
+ */
36
+ public chopEmptyLinesEnd() {
37
+ return new Str(lib.chopEmptyLinesEnd(this.text));
38
+ }
39
+
40
+ /**
41
+ * Remove all space (\s) characters in lines without content
42
+ */
43
+ public trimEmptyLines() {
44
+ return new Str(lib.trimEmptyLines(this.text));
45
+ }
46
+
47
+ /**
48
+ * Remove all spaces (\s) characters at the end of lines
49
+ */
50
+ public trimLinesTrailingSpaces() {
51
+ return new Str(lib.trimLinesTrailingSpaces(this.text));
52
+ }
53
+
54
+ /**
55
+ * Removes the leading and trailing white space and line terminator characters
56
+ */
57
+ public trim() {
58
+ return new Str(lib.trim(this.text));
59
+ }
60
+
61
+ /**
62
+ * Removes the leading white space and line terminator characters
63
+ */
64
+ public trimStart() {
65
+ return new Str(lib.trimStart(this.text));
66
+ }
67
+
68
+ /**
69
+ * Removes the trailing white space and line terminator characters
70
+ */
71
+ public trimEnd() {
72
+ return new Str(lib.trimEnd(this.text));
73
+ }
74
+
75
+ /**
76
+ * Split a string into substrings using the specified separator and return them as an array
77
+ */
78
+ public split(separator: string | RegExp, limit?: number) {
79
+ return lib.split(this.text, separator, limit).map((v) => new Str(v));
80
+ }
81
+
82
+ /**
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 ":"
86
+ */
87
+ public addLineNumbers(separator: string = ":") {
88
+ return new Str(lib.addLineNumbers(this.text, separator));
89
+ }
90
+
91
+ /**
92
+ * Returns the character at the specified index
93
+ * @return string or undefined if the index is out of bounds
94
+ */
95
+ public at(index: number) {
96
+ return this.text.at(index);
97
+ }
98
+
99
+ /**
100
+ * Returns the length of the string
101
+ */
102
+ public length() {
103
+ return this.text.length;
104
+ }
105
+
106
+ /**
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 " "
110
+ */
111
+ public indent(size: number, char: string = " ") {
112
+ return new Str(lib.indent(this.text, size, char));
113
+ }
114
+
115
+ /**
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.
119
+ */
120
+ public dedent(indentation?: number) {
121
+ return new Str(lib.dedent(this.text, indentation));
122
+ }
123
+
124
+ /**
125
+ * Chop the string at the start by the specified number of characters
126
+ */
127
+ public chopStart(count: number) {
128
+ return new Str(lib.chopStart(this.text, count));
129
+ }
130
+
131
+ /**
132
+ * Chop the string at the end by the specified number of characters
133
+ */
134
+ public chopEnd(count: number) {
135
+ if (count === 0) return this;
136
+ return new Str(lib.chopEnd(this.text, count));
137
+ }
138
+
139
+ /**
140
+ * Remove successive newlines of the specified repetition or more
141
+ * @param maxRepeat the maximum number of newlines to allow
142
+ */
143
+ public chopRepeatNewlines(maxRepeat: number) {
144
+ if (maxRepeat === 0) return this;
145
+ return new Str(lib.chopRepeatNewlines(this.text, maxRepeat));
146
+ }
147
+
148
+ /**
149
+ * Take the first n characters of the string
150
+ */
151
+ public takeStart(count: number) {
152
+ return new Str(lib.takeStart(this.text, count));
153
+ }
154
+
155
+ /**
156
+ * Take the last n characters of the string
157
+ */
158
+ public takeEnd(count: number) {
159
+ return new Str(lib.takeEnd(this.text, count));
160
+ }
161
+
162
+ /**
163
+ * Returns the last line of the string
164
+ */
165
+ public lastLine() {
166
+ return new Str(lib.lastLine(this.text));
167
+ }
168
+
169
+ /**
170
+ * Returns the first line of the string
171
+ */
172
+ public firstLine() {
173
+ return new Str(lib.firstLine(this.text));
174
+ }
175
+
176
+ /**
177
+ * Returns the number of leading spaces in the string
178
+ */
179
+ public leadingSpacesCount() {
180
+ return lib.leadingSpacesCount(this.text);
181
+ }
182
+
183
+ /**
184
+ * Returns the indentation level of the string skipping empty lines in the process
185
+ */
186
+ public indentation() {
187
+ return lib.indentation(this.text);
188
+ }
189
+
190
+ /**
191
+ * Returns true if the string is empty or contains only whitespace
192
+ */
193
+ public isEmpty() {
194
+ return lib.isEmpty(this.text);
195
+ }
196
+
197
+ /**
198
+ * Converts the string to camel case
199
+ */
200
+ public camelCase() {
201
+ return new Str(changeCase.camelCase(this.text));
202
+ }
203
+
204
+ /**
205
+ * Converts the string to capital case
206
+ */
207
+ public capitalCase() {
208
+ return new Str(changeCase.capitalCase(this.text));
209
+ }
210
+
211
+ /**
212
+ * Converts the string to constant case
213
+ */
214
+ public constantCase() {
215
+ return new Str(changeCase.constantCase(this.text));
216
+ }
217
+
218
+ /**
219
+ * Converts the string to dot case
220
+ */
221
+ public dotCase() {
222
+ return new Str(changeCase.dotCase(this.text));
223
+ }
224
+
225
+ /**
226
+ * Converts the string to kebab case
227
+ */
228
+ public kebabCase() {
229
+ return new Str(changeCase.kebabCase(this.text));
230
+ }
231
+
232
+ /**
233
+ * Converts the string to no case
234
+ */
235
+ public noCase() {
236
+ return new Str(changeCase.noCase(this.text));
237
+ }
238
+
239
+ /**
240
+ * Converts the string to pascal case
241
+ */
242
+ public pascalCase() {
243
+ return new Str(changeCase.pascalCase(this.text));
244
+ }
245
+
246
+ /**
247
+ * Converts the string to pascal snake case
248
+ */
249
+ public pascalSnakeCase() {
250
+ return new Str(changeCase.pascalSnakeCase(this.text));
251
+ }
252
+
253
+ /**
254
+ * Converts the string to path case
255
+ */
256
+ public pathCase() {
257
+ return new Str(changeCase.pathCase(this.text));
258
+ }
259
+
260
+ /**
261
+ * Converts the string to sentence case
262
+ */
263
+ public sentenceCase() {
264
+ return new Str(changeCase.sentenceCase(this.text));
265
+ }
266
+
267
+ /**
268
+ * Converts the string to snake case
269
+ */
270
+ public snakeCase() {
271
+ return new Str(changeCase.snakeCase(this.text));
272
+ }
273
+
274
+ /**
275
+ * Converts the string to train case
276
+ */
277
+ public trainCase() {
278
+ return new Str(changeCase.trainCase(this.text));
279
+ }
280
+
281
+ /**
282
+ * Shorthand for `.toString()`
283
+ */
284
+ public get str() {
285
+ return this.toString();
286
+ }
287
+ }
288
+
289
+ export const str = (text: Stringable) => {
290
+ return new Str(text.toString());
291
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./str.bundle";
2
+ export type { Str } from "./str.chainable";
package/src/str.lib.ts ADDED
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Remove empty lines at the start of the text but leave whitespace on the first line with content
3
+ */
4
+ export const chopEmptyLinesStart = (text: string) => {
5
+ return text.replace(/^(\s*\n)+/, "");
6
+ };
7
+
8
+ /**
9
+ * Remove empty lines at the end of the text but leave whitespace on the last line with content
10
+ */
11
+ export const chopEmptyLinesEnd = (text: string) => {
12
+ return text.replace(/(\n\s*)+$/, "");
13
+ };
14
+
15
+ /**
16
+ * Remove all space (\s) characters in lines without content
17
+ */
18
+ export const trimEmptyLines = (text: string) => {
19
+ return text.replace(/(^|\n)\s+(\n|$)/g, "$1$2");
20
+ };
21
+
22
+ /**
23
+ * Remove all space (\s) characters at the end of lines
24
+ */
25
+ export const trimLinesTrailingSpaces = (text: string) => {
26
+ return text.replace(/ +(\n|$)/g, "$1");
27
+ };
28
+
29
+ /**
30
+ * Removes the leading and trailing white space and line terminator characters
31
+ */
32
+ export const trim = (text: string) => {
33
+ return text.trim();
34
+ };
35
+
36
+ /**
37
+ * Removes the leading white space and line terminator characters
38
+ */
39
+ export const trimStart = (text: string) => {
40
+ return text.trimStart();
41
+ };
42
+
43
+ /**
44
+ * Removes the trailing white space and line terminator characters
45
+ */
46
+ export const trimEnd = (text: string) => {
47
+ return text.trimEnd();
48
+ };
49
+
50
+ /**
51
+ * Split a string into substrings using the specified separator and return them as an array
52
+ */
53
+ export const split = (
54
+ text: string,
55
+ separator: string | RegExp,
56
+ limit?: number,
57
+ ) => {
58
+ return text.split(separator, limit);
59
+ };
60
+
61
+ /**
62
+ * Add line numbers to a string
63
+ * @param text The string to add line numbers to
64
+ * @param separator The separator to use between the line number and the line content.
65
+ * Defaults to ":"
66
+ */
67
+ export const addLineNumbers = (text: string, separator: string = ":") => {
68
+ return text
69
+ .split("\n")
70
+ .map((line, index) => `${index}${separator}${line}`)
71
+ .join("\n");
72
+ };
73
+
74
+ /**
75
+ * Returns the indentation level of the string skipping empty lines in the process
76
+ */
77
+ export const indentation = (text: string) => {
78
+ return (
79
+ text.split("\n").reduce((acc: number | null, line) => {
80
+ if (line.trim() === "") return acc;
81
+ const indentation = leadingSpacesCount(line);
82
+ if (acc === null) return indentation;
83
+ return Math.min(acc, indentation);
84
+ }, null) ?? 0
85
+ );
86
+ };
87
+
88
+ /**
89
+ * Indent the string by the specified number of spaces
90
+ * @param size The number of spaces to indent by
91
+ * @param char The character to use for indentation. Defaults to " "
92
+ */
93
+ export const indent = (text: string, size: number, char: string = " ") => {
94
+ if (size === 0) return text;
95
+
96
+ const indentStr = char.repeat(size);
97
+ return text
98
+ .split("\n")
99
+ .map((line) => indentStr + line)
100
+ .join("\n");
101
+ };
102
+
103
+ /**
104
+ * Dedent the string by the specified number of spaces
105
+ * @param indentation The number of spaces to dedent by.
106
+ * If not provided, it will be calculated automatically based on the maximum indentation in the string.
107
+ */
108
+ export const dedent = (text: string, size?: number) => {
109
+ const _size = size ?? indentation(text);
110
+ if (_size === 0) return text;
111
+ const regex = new RegExp(`^\\s{1,${_size}}`);
112
+ return text
113
+ .split("\n")
114
+ .map((line) => line.replace(regex, ""))
115
+ .join("\n");
116
+ };
117
+
118
+ /**
119
+ * Chop the string at the end by the specified number of characters
120
+ */
121
+ export const chopEnd = (text: string, count: number) => {
122
+ if (count === 0) return text;
123
+ return text.slice(0, -count);
124
+ };
125
+
126
+ /**
127
+ * Chop the string at the start by the specified number of characters
128
+ */
129
+ export const chopStart = (text: string, count: number) => {
130
+ if (count === 0) return text;
131
+ return text.slice(count);
132
+ };
133
+
134
+ /**
135
+ * Remove successive newlines of the specified repetition or more
136
+ * @param maxRepeat the maximum number of newlines to allow
137
+ */
138
+ export const chopRepeatNewlines = (text: string, maxRepeat: number) => {
139
+ if (maxRepeat === 0) return text;
140
+ return text.replace(
141
+ new RegExp(`\n{${maxRepeat + 1},}`, "g"),
142
+ "\n".repeat(maxRepeat),
143
+ );
144
+ };
145
+
146
+ /**
147
+ * Take the first n characters of the string
148
+ */
149
+ export const takeStart = (text: string, count: number) => {
150
+ return text.slice(0, count);
151
+ };
152
+
153
+ /**
154
+ * Take the last n characters of the string
155
+ */
156
+ export const takeEnd = (text: string, count: number) => {
157
+ return text.slice(-count);
158
+ };
159
+
160
+ /**
161
+ * Returns the last line of the string
162
+ */
163
+ export const lastLine = (text: string) => {
164
+ return text.split("\n").at(-1) ?? "";
165
+ };
166
+
167
+ /**
168
+ * Returns the first line of the string
169
+ */
170
+ export const firstLine = (text: string) => {
171
+ return text.split("\n").at(0) ?? "";
172
+ };
173
+
174
+ /**
175
+ * Returns the number of leading spaces in the string
176
+ */
177
+ export const leadingSpacesCount = (text: string) => {
178
+ return text.match(/^\s+/)?.at(0)?.length ?? 0;
179
+ };
180
+
181
+ /**
182
+ * Returns true if the string is empty or contains only whitespace
183
+ */
184
+ export const isEmpty = (text: string) => {
185
+ return text.trim() === "";
186
+ };