@synstack/str 1.0.1-alpha.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ };