@alextheman/utility 5.12.0 → 5.13.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.
- package/dist/index.cjs +487 -426
- package/dist/index.d.cts +174 -59
- package/dist/index.d.ts +174 -59
- package/dist/index.js +488 -426
- package/dist/internal/index.cjs +244 -185
- package/dist/internal/index.d.cts +101 -41
- package/dist/internal/index.d.ts +101 -41
- package/dist/internal/index.js +244 -185
- package/dist/node/index.cjs +197 -138
- package/dist/node/index.d.cts +1 -1
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +197 -138
- package/dist/v6/index.cjs +114 -115
- package/dist/v6/index.d.cts +12 -12
- package/dist/v6/index.d.ts +12 -12
- package/dist/v6/index.js +114 -115
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -63,77 +63,42 @@ function paralleliseArrays(firstArray, secondArray) {
|
|
|
63
63
|
return outputArray;
|
|
64
64
|
}
|
|
65
65
|
//#endregion
|
|
66
|
-
//#region src/
|
|
67
|
-
const httpErrorCodeLookup = {
|
|
68
|
-
400: "BAD_REQUEST",
|
|
69
|
-
401: "UNAUTHORISED",
|
|
70
|
-
403: "FORBIDDEN",
|
|
71
|
-
404: "NOT_FOUND",
|
|
72
|
-
418: "I_AM_A_TEAPOT",
|
|
73
|
-
500: "INTERNAL_SERVER_ERROR"
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Represents common errors you may get from a HTTP API request.
|
|
77
|
-
*
|
|
78
|
-
* @category Types
|
|
79
|
-
*/
|
|
80
|
-
var APIError = class APIError extends Error {
|
|
81
|
-
status;
|
|
82
|
-
/**
|
|
83
|
-
* @param status - A HTTP status code. Can be any number, but numbers between 400 and 600 are encouraged to fit with HTTP status code conventions.
|
|
84
|
-
* @param message - An error message to display alongside the status code.
|
|
85
|
-
* @param options - Extra options to be passed to super Error constructor.
|
|
86
|
-
*/
|
|
87
|
-
constructor(status = 500, message, options) {
|
|
88
|
-
super(message, options);
|
|
89
|
-
this.status = status;
|
|
90
|
-
if (message) this.message = message;
|
|
91
|
-
else this.message = httpErrorCodeLookup[this.status] ?? "API_ERROR";
|
|
92
|
-
Object.defineProperty(this, "message", { enumerable: true });
|
|
93
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Checks whether the given input may have been caused by an APIError.
|
|
97
|
-
*
|
|
98
|
-
* @param input - The input to check.
|
|
99
|
-
*
|
|
100
|
-
* @returns `true` if the input is an APIError, and `false` otherwise. The type of the input will also be narrowed down to APIError if `true`.
|
|
101
|
-
*/
|
|
102
|
-
static check(input) {
|
|
103
|
-
if (input instanceof APIError) return true;
|
|
104
|
-
const data = input;
|
|
105
|
-
return typeof data === "object" && data !== null && typeof data?.status === "number" && typeof data?.message === "string";
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
//#endregion
|
|
109
|
-
//#region src/root/types/DataError.ts
|
|
66
|
+
//#region src/v6/CodeError.ts
|
|
110
67
|
/**
|
|
111
|
-
* Represents errors
|
|
68
|
+
* Represents errors that can be described using a standardised error code, and a human-readable error message.
|
|
112
69
|
*
|
|
113
70
|
* @category Types
|
|
114
71
|
*
|
|
115
|
-
* @template
|
|
72
|
+
* @template ErrorCode The type of the standardised error code.
|
|
116
73
|
*/
|
|
117
|
-
var
|
|
74
|
+
var CodeError = class CodeError extends Error {
|
|
118
75
|
code;
|
|
119
|
-
data;
|
|
120
76
|
/**
|
|
121
|
-
* @param data - The data that caused the error.
|
|
122
77
|
* @param code - A standardised code (e.g. UNEXPECTED_DATA).
|
|
123
78
|
* @param message - A human-readable error message (e.g. The data provided is invalid).
|
|
124
79
|
* @param options - Extra options to pass to super Error constructor.
|
|
125
80
|
*/
|
|
126
|
-
constructor(
|
|
81
|
+
constructor(code, message = "Something went wrong.", options) {
|
|
127
82
|
super(message, options);
|
|
128
83
|
if (Error.captureStackTrace) Error.captureStackTrace(this, new.target);
|
|
129
84
|
this.name = new.target.name;
|
|
130
85
|
this.code = code;
|
|
131
|
-
this.data = data;
|
|
132
86
|
Object.defineProperty(this, "message", { enumerable: true });
|
|
133
87
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
134
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Checks whether the given input may have been caused by a CodeError.
|
|
91
|
+
*
|
|
92
|
+
* @param input - The input to check.
|
|
93
|
+
*
|
|
94
|
+
* @returns `true` if the input is a CodeError, and `false` otherwise. The type of the input will also be narrowed down to CodeError if `true`.
|
|
95
|
+
*/
|
|
96
|
+
static check(input) {
|
|
97
|
+
if (input instanceof CodeError) return true;
|
|
98
|
+
return typeof input === "object" && input !== null && "message" in input && typeof input.message === "string" && "code" in input && typeof input.code === "string";
|
|
99
|
+
}
|
|
135
100
|
static checkCaughtError(error, options) {
|
|
136
|
-
if (
|
|
101
|
+
if (this.check(error)) {
|
|
137
102
|
if (options?.expectedCode && error.code !== options.expectedCode) throw new Error(normaliseIndents`The error code on the thrown error does not match the expected error code.
|
|
138
103
|
|
|
139
104
|
Expected: ${options.expectedCode}
|
|
@@ -144,223 +109,110 @@ var DataError = class DataError extends Error {
|
|
|
144
109
|
throw error;
|
|
145
110
|
}
|
|
146
111
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* @param input - The input to check.
|
|
150
|
-
*
|
|
151
|
-
* @returns `true` if the input is a DataError, and `false` otherwise. The type of the input will also be narrowed down to DataError if `true`.
|
|
152
|
-
*/
|
|
153
|
-
static check(input) {
|
|
154
|
-
if (input instanceof DataError) return true;
|
|
155
|
-
const data = input;
|
|
156
|
-
return typeof data === "object" && data !== null && typeof data.message === "string" && typeof data.code === "string" && "data" in data;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Gets the thrown `DataError` from a given function if one was thrown, and re-throws any other errors, or throws a default `DataError` if no error thrown.
|
|
112
|
+
* Gets the thrown `CodeError` from a given function if one was thrown, and re-throws any other errors, or throws a default `CodeError` if no error thrown.
|
|
160
113
|
*
|
|
161
114
|
* @param errorFunction - The function expected to throw the error.
|
|
162
115
|
* @param options - Extra options to apply.
|
|
163
116
|
*
|
|
164
|
-
* @throws {Error} Any other errors thrown by the `errorFunction` that are not a `
|
|
165
|
-
* @throws {Error} If no `
|
|
117
|
+
* @throws {Error} Any other errors thrown by the `errorFunction` that are not a `CodeError`.
|
|
118
|
+
* @throws {Error} If no `CodeError` was thrown by the `errorFunction`
|
|
166
119
|
*
|
|
167
|
-
* @returns The `
|
|
120
|
+
* @returns The `CodeError` that was thrown by the `errorFunction`
|
|
168
121
|
*/
|
|
169
122
|
static expectError(errorFunction, options) {
|
|
170
123
|
try {
|
|
171
124
|
errorFunction();
|
|
172
125
|
} catch (error) {
|
|
173
|
-
return
|
|
126
|
+
return this.checkCaughtError(error, options);
|
|
174
127
|
}
|
|
175
|
-
throw new Error(
|
|
128
|
+
throw new Error(`Expected a ${this.name} to be thrown but none was thrown`);
|
|
176
129
|
}
|
|
177
130
|
/**
|
|
178
|
-
* Gets the thrown `
|
|
131
|
+
* Gets the thrown `CodeError` from a given asynchronous function if one was thrown, and re-throws any other errors, or throws a default `CodeError` if no error thrown.
|
|
179
132
|
*
|
|
180
133
|
* @param errorFunction - The function expected to throw the error.
|
|
181
134
|
* @param options - Extra options to apply.
|
|
182
135
|
*
|
|
183
|
-
* @throws {Error} Any other errors thrown by the `errorFunction` that are not a `
|
|
184
|
-
* @throws {Error} If no `
|
|
136
|
+
* @throws {Error} Any other errors thrown by the `errorFunction` that are not a `CodeError`.
|
|
137
|
+
* @throws {Error} If no `CodeError` was thrown by the `errorFunction`
|
|
185
138
|
*
|
|
186
|
-
* @returns The `
|
|
139
|
+
* @returns The `CodeError` that was thrown by the `errorFunction`
|
|
187
140
|
*/
|
|
188
141
|
static async expectErrorAsync(errorFunction, options) {
|
|
189
142
|
try {
|
|
190
143
|
await errorFunction();
|
|
191
144
|
} catch (error) {
|
|
192
|
-
return
|
|
145
|
+
return this.checkCaughtError(error, options);
|
|
193
146
|
}
|
|
194
|
-
throw new Error(
|
|
147
|
+
throw new Error(`Expected a ${this.name} to be thrown but none was thrown`);
|
|
195
148
|
}
|
|
196
149
|
};
|
|
197
150
|
//#endregion
|
|
198
|
-
//#region src/
|
|
151
|
+
//#region src/v6/DataError.ts
|
|
199
152
|
/**
|
|
200
|
-
* Represents
|
|
153
|
+
* Represents errors you may get that may've been caused by a specific piece of data.
|
|
201
154
|
*
|
|
202
155
|
* @category Types
|
|
156
|
+
*
|
|
157
|
+
* @template DataType - The type of the data that caused the error.
|
|
203
158
|
*/
|
|
204
|
-
var
|
|
205
|
-
|
|
206
|
-
/** The major number. Increments when a feature is removed or changed in a way that is not backwards-compatible with the previous release. */
|
|
207
|
-
major = 0;
|
|
208
|
-
/** The minor number. Increments when a new feature is added/deprecated and is expected to be backwards-compatible with the previous release. */
|
|
209
|
-
minor = 0;
|
|
210
|
-
/** The patch number. Increments when the next release is fixing a bug or doing a small refactor that should not be noticeable in practice. */
|
|
211
|
-
patch = 0;
|
|
212
|
-
/**
|
|
213
|
-
* @param input - The input to create a new instance of `VersionNumber` from.
|
|
214
|
-
*/
|
|
215
|
-
constructor(input) {
|
|
216
|
-
if (input instanceof VersionNumber) {
|
|
217
|
-
this.major = input.major;
|
|
218
|
-
this.minor = input.minor;
|
|
219
|
-
this.patch = input.patch;
|
|
220
|
-
} else if (typeof input === "string") {
|
|
221
|
-
if (!VERSION_NUMBER_REGEX.test(input)) throw new DataError({ input }, "INVALID_VERSION", `"${input}" is not a valid version number. Version numbers must be of the format "X.Y.Z" or "vX.Y.Z", where X, Y, and Z are non-negative integers.`);
|
|
222
|
-
const [major, minor, patch] = VersionNumber.formatString(input, { omitPrefix: true }).split(".").map((number) => {
|
|
223
|
-
return parseIntStrict(number);
|
|
224
|
-
});
|
|
225
|
-
this.major = major;
|
|
226
|
-
this.minor = minor;
|
|
227
|
-
this.patch = patch;
|
|
228
|
-
} else if (Array.isArray(input)) {
|
|
229
|
-
if (input.length !== 3) throw new DataError({ input }, "INVALID_LENGTH", VersionNumber.NON_NEGATIVE_TUPLE_ERROR);
|
|
230
|
-
const [major, minor, patch] = input.map((number) => {
|
|
231
|
-
const parsedInteger = parseIntStrict(number?.toString());
|
|
232
|
-
if (parsedInteger < 0) throw new DataError({ input }, "NEGATIVE_INPUTS", VersionNumber.NON_NEGATIVE_TUPLE_ERROR);
|
|
233
|
-
return parsedInteger;
|
|
234
|
-
});
|
|
235
|
-
this.major = major;
|
|
236
|
-
this.minor = minor;
|
|
237
|
-
this.patch = patch;
|
|
238
|
-
} else throw new DataError({ input }, "INVALID_INPUT", normaliseIndents`
|
|
239
|
-
The provided input can not be parsed into a valid version number.
|
|
240
|
-
Expected either a string of format X.Y.Z or vX.Y.Z, a tuple of three numbers, or another \`VersionNumber\` instance.
|
|
241
|
-
`);
|
|
242
|
-
}
|
|
159
|
+
var DataError = class DataError extends CodeError {
|
|
160
|
+
data;
|
|
243
161
|
/**
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* @
|
|
162
|
+
* @param data - The data that caused the error.
|
|
163
|
+
* @param code - A standardised code (e.g. UNEXPECTED_DATA).
|
|
164
|
+
* @param message - A human-readable error message (e.g. The data provided is invalid).
|
|
165
|
+
* @param options - Extra options to pass to super Error constructor.
|
|
247
166
|
*/
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
167
|
+
constructor(data, code = "INVALID_DATA", message = "The data provided is invalid", options) {
|
|
168
|
+
super(code, message, options);
|
|
169
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, new.target);
|
|
170
|
+
this.name = new.target.name;
|
|
171
|
+
this.code = code;
|
|
172
|
+
this.data = data;
|
|
173
|
+
Object.defineProperty(this, "message", { enumerable: true });
|
|
174
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
256
175
|
}
|
|
257
176
|
/**
|
|
258
|
-
* Checks
|
|
177
|
+
* Checks whether the given input may have been caused by a DataError.
|
|
259
178
|
*
|
|
260
|
-
* @param
|
|
261
|
-
* @param secondVersion - The second version number to compare.
|
|
179
|
+
* @param input - The input to check.
|
|
262
180
|
*
|
|
263
|
-
* @returns `true` if the
|
|
181
|
+
* @returns `true` if the input is a DataError, and `false` otherwise. The type of the input will also be narrowed down to DataError if `true`.
|
|
264
182
|
*/
|
|
265
|
-
static
|
|
266
|
-
|
|
183
|
+
static check(input) {
|
|
184
|
+
if (input instanceof DataError) return true;
|
|
185
|
+
return typeof input === "object" && input !== null && "message" in input && typeof input.message === "string" && "code" in input && typeof input.code === "string" && "data" in input;
|
|
267
186
|
}
|
|
268
187
|
/**
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
* @param options - Options to apply to the string formatting.
|
|
188
|
+
* Gets the thrown `DataError` from a given function if one was thrown, and re-throws any other errors, or throws a default `DataError` if no error thrown.
|
|
272
189
|
*
|
|
273
|
-
* @
|
|
274
|
-
|
|
275
|
-
format(options) {
|
|
276
|
-
let baseOutput = `${this.major}`;
|
|
277
|
-
if (!options?.omitMinor) {
|
|
278
|
-
baseOutput += `.${this.minor}`;
|
|
279
|
-
if (!options?.omitPatch) baseOutput += `.${this.patch}`;
|
|
280
|
-
}
|
|
281
|
-
return VersionNumber.formatString(baseOutput, { omitPrefix: options?.omitPrefix });
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Increments the current version number by the given increment type, returning the result as a new reference in memory.
|
|
190
|
+
* @param errorFunction - The function expected to throw the error.
|
|
191
|
+
* @param options - Extra options to apply.
|
|
285
192
|
*
|
|
286
|
-
* @
|
|
287
|
-
*
|
|
288
|
-
* - `"minor"`: Change the minor version `v1.2.3` → `v1.3.0`
|
|
289
|
-
* - `"patch"`: Change the patch version `v1.2.3` → `v1.2.4`
|
|
290
|
-
* @param incrementAmount - The amount to increment by (defaults to 1).
|
|
193
|
+
* @throws {Error} Any other errors thrown by the `errorFunction` that are not a `DataError`.
|
|
194
|
+
* @throws {Error} If no `DataError` was thrown by the `errorFunction`
|
|
291
195
|
*
|
|
292
|
-
* @returns
|
|
196
|
+
* @returns The `DataError` that was thrown by the `errorFunction`
|
|
293
197
|
*/
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const calculatedRawVersion = {
|
|
297
|
-
major: [
|
|
298
|
-
this.major + incrementBy,
|
|
299
|
-
0,
|
|
300
|
-
0
|
|
301
|
-
],
|
|
302
|
-
minor: [
|
|
303
|
-
this.major,
|
|
304
|
-
this.minor + incrementBy,
|
|
305
|
-
0
|
|
306
|
-
],
|
|
307
|
-
patch: [
|
|
308
|
-
this.major,
|
|
309
|
-
this.minor,
|
|
310
|
-
this.patch + incrementBy
|
|
311
|
-
]
|
|
312
|
-
}[incrementType];
|
|
313
|
-
try {
|
|
314
|
-
return new VersionNumber(calculatedRawVersion);
|
|
315
|
-
} catch (error) {
|
|
316
|
-
if (DataError.check(error) && error.code === "NEGATIVE_INPUTS") throw new DataError({
|
|
317
|
-
currentVersion: this.toString(),
|
|
318
|
-
calculatedRawVersion: `v${calculatedRawVersion.join(".")}`,
|
|
319
|
-
incrementAmount
|
|
320
|
-
}, "NEGATIVE_VERSION", "Cannot apply this increment amount as it would lead to a negative version number.");
|
|
321
|
-
else throw error;
|
|
322
|
-
}
|
|
198
|
+
static expectError(errorFunction, options) {
|
|
199
|
+
return super.expectError(errorFunction, options);
|
|
323
200
|
}
|
|
324
201
|
/**
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
* @param hint - Not used as of now, but generally used to help with numeric coercion, I think (which we most likely do not need for version numbers).
|
|
202
|
+
* Gets the thrown `DataError` from a given asynchronous function if one was thrown, and re-throws any other errors, or throws a default `DataError` if no error thrown.
|
|
328
203
|
*
|
|
329
|
-
* @
|
|
330
|
-
|
|
331
|
-
[Symbol.toPrimitive](hint) {
|
|
332
|
-
if (hint === "number") throw new DataError({ thisVersion: this.toString() }, "INVALID_COERCION", "VersionNumber cannot be coerced to a number type.");
|
|
333
|
-
return this.toString();
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Ensures that the VersionNumber behaves correctly when attempted to be converted to JSON.
|
|
204
|
+
* @param errorFunction - The function expected to throw the error.
|
|
205
|
+
* @param options - Extra options to apply.
|
|
337
206
|
*
|
|
338
|
-
* @
|
|
339
|
-
|
|
340
|
-
toJSON() {
|
|
341
|
-
return this.toString();
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Get a string representation of the current version number.
|
|
207
|
+
* @throws {Error} Any other errors thrown by the `errorFunction` that are not a `DataError`.
|
|
208
|
+
* @throws {Error} If no `DataError` was thrown by the `errorFunction`
|
|
345
209
|
*
|
|
346
|
-
* @returns
|
|
210
|
+
* @returns The `DataError` that was thrown by the `errorFunction`
|
|
347
211
|
*/
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
return VersionNumber.formatString(rawString, { omitPrefix: false });
|
|
212
|
+
static async expectErrorAsync(errorFunction, options) {
|
|
213
|
+
return await super.expectErrorAsync(errorFunction, options);
|
|
351
214
|
}
|
|
352
215
|
};
|
|
353
|
-
const zodVersionNumber = z$1.union([
|
|
354
|
-
z$1.string(),
|
|
355
|
-
z$1.tuple([
|
|
356
|
-
z$1.number(),
|
|
357
|
-
z$1.number(),
|
|
358
|
-
z$1.number()
|
|
359
|
-
]),
|
|
360
|
-
z$1.instanceof(VersionNumber)
|
|
361
|
-
]).transform((rawVersionNumber) => {
|
|
362
|
-
return new VersionNumber(rawVersionNumber);
|
|
363
|
-
});
|
|
364
216
|
//#endregion
|
|
365
217
|
//#region src/root/functions/parsers/parseIntStrict.ts
|
|
366
218
|
/**
|
|
@@ -760,231 +612,116 @@ function isOrdered(array) {
|
|
|
760
612
|
return true;
|
|
761
613
|
}
|
|
762
614
|
//#endregion
|
|
763
|
-
//#region src/root/functions/
|
|
615
|
+
//#region src/root/functions/miscellaneous/sayHello.ts
|
|
764
616
|
/**
|
|
765
|
-
* Returns
|
|
617
|
+
* Returns a string representing the lyrics to the package's theme song, Commit To You
|
|
766
618
|
*
|
|
767
|
-
*
|
|
768
|
-
*
|
|
769
|
-
* ```
|
|
770
|
-
* interpolate`Template string here`;
|
|
771
|
-
* ```
|
|
772
|
-
*
|
|
773
|
-
* In this case, it will be functionally the same as if you just wrote the template string by itself.
|
|
774
|
-
*
|
|
775
|
-
* @category Tagged Template
|
|
776
|
-
*
|
|
777
|
-
* @template InterpolationsType - The type of the interpolations.
|
|
778
|
-
*
|
|
779
|
-
* @param strings - The strings from the template to process.
|
|
780
|
-
* @param interpolations - An array of all interpolations from the template.
|
|
781
|
-
*
|
|
782
|
-
* @returns A new string with the strings and interpolations from the template applied.
|
|
783
|
-
*/
|
|
784
|
-
function interpolate(strings, ...interpolations) {
|
|
785
|
-
let result = "";
|
|
786
|
-
for (const [string, interpolation = ""] of paralleliseArrays(strings, interpolations)) result += string + interpolation;
|
|
787
|
-
return result;
|
|
788
|
-
}
|
|
789
|
-
//#endregion
|
|
790
|
-
//#region src/root/functions/taggedTemplate/normaliseIndents.ts
|
|
791
|
-
function calculateTabSize(line, whitespaceLength) {
|
|
792
|
-
const potentialWhitespacePart = line.slice(0, whitespaceLength);
|
|
793
|
-
const trimmedString = line.trimStart();
|
|
794
|
-
if (potentialWhitespacePart.trim() !== "") return 0;
|
|
795
|
-
const tabSize = line.length - (trimmedString.length + whitespaceLength);
|
|
796
|
-
return tabSize < 0 ? 0 : tabSize;
|
|
797
|
-
}
|
|
798
|
-
function getWhitespaceLength(lines) {
|
|
799
|
-
const [firstNonEmptyLine] = lines.filter((line) => {
|
|
800
|
-
return line.trim() !== "";
|
|
801
|
-
});
|
|
802
|
-
return firstNonEmptyLine.length - firstNonEmptyLine.trimStart().length;
|
|
803
|
-
}
|
|
804
|
-
function reduceLines(lines, { preserveTabs = true }) {
|
|
805
|
-
const slicedLines = lines.slice(1);
|
|
806
|
-
const isFirstLineEmpty = lines[0].trim() === "";
|
|
807
|
-
const whitespaceLength = getWhitespaceLength(isFirstLineEmpty ? lines : slicedLines);
|
|
808
|
-
return (isFirstLineEmpty ? slicedLines : lines).map((line) => {
|
|
809
|
-
const tabSize = calculateTabSize(line, whitespaceLength);
|
|
810
|
-
return (preserveTabs ? fillArray(() => {
|
|
811
|
-
return " ";
|
|
812
|
-
}, tabSize).join("") : "") + line.trimStart();
|
|
813
|
-
}).join("\n");
|
|
814
|
-
}
|
|
815
|
-
/**
|
|
816
|
-
* Applies any options if provided, then removes any extraneous indents from a multi-line template string.
|
|
817
|
-
*
|
|
818
|
-
* You can pass a template string directly by doing:
|
|
819
|
-
*
|
|
820
|
-
* ```typescript
|
|
821
|
-
* normaliseIndents`Template string here
|
|
822
|
-
* with a new line
|
|
823
|
-
* and another new line`;
|
|
824
|
-
* ```
|
|
825
|
-
*
|
|
826
|
-
* You may also pass the options first, then invoke the resulting function with a template string:
|
|
827
|
-
*
|
|
828
|
-
* ```typescript
|
|
829
|
-
* normaliseIndents({ preserveTabs: false })`Template string here
|
|
830
|
-
* with a new line
|
|
831
|
-
* and another new line`;
|
|
832
|
-
* ```
|
|
833
|
-
*
|
|
834
|
-
* @category Tagged Template
|
|
835
|
-
*
|
|
836
|
-
* @param first - The strings from the template to process, or the options to apply.
|
|
837
|
-
* @param args - An array of all interpolations from the template.
|
|
838
|
-
*
|
|
839
|
-
* @returns An additional function to invoke, or a new string with the strings and interpolations from the template applied, and extraneous indents removed.
|
|
840
|
-
*/
|
|
841
|
-
function normaliseIndents(first, ...args) {
|
|
842
|
-
if (typeof first === "object" && first !== null && !Array.isArray(first)) {
|
|
843
|
-
const options = first;
|
|
844
|
-
return (strings, ...interpolations) => {
|
|
845
|
-
return normaliseIndents(strings, ...interpolations, options);
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
const strings = first;
|
|
849
|
-
const options = typeof args[args.length - 1] === "object" && !Array.isArray(args[args.length - 1]) ? args.pop() : {};
|
|
850
|
-
return reduceLines(interpolate(strings, ...[...args]).split("\n"), options);
|
|
851
|
-
}
|
|
852
|
-
/**
|
|
853
|
-
* Applies any options if provided, then removes any extraneous indents from a multi-line template string.
|
|
854
|
-
*
|
|
855
|
-
* You can pass a template string directly by doing:
|
|
856
|
-
*
|
|
857
|
-
* ```typescript
|
|
858
|
-
* normalizeIndents`Template string here
|
|
859
|
-
* with a new line
|
|
860
|
-
* and another new line`.
|
|
861
|
-
* ```
|
|
862
|
-
*
|
|
863
|
-
* You may also pass the options first, then invoke the resulting function with a template string:
|
|
864
|
-
*
|
|
865
|
-
* ```typescript
|
|
866
|
-
* normalizeIndents({ preserveTabs: false })`Template string here
|
|
867
|
-
* with a new line
|
|
868
|
-
* and another new line`.
|
|
869
|
-
* ```
|
|
870
|
-
*
|
|
871
|
-
* @param first - The strings from the template to process, or the options to apply.
|
|
872
|
-
* @param args - An array of all interpolations from the template.
|
|
873
|
-
*
|
|
874
|
-
* @returns An additional function to invoke, or a new string with the strings and interpolations from the template applied, and extraneous indents removed.
|
|
875
|
-
*/
|
|
876
|
-
const normalizeIndents = normaliseIndents;
|
|
877
|
-
//#endregion
|
|
878
|
-
//#region src/root/functions/miscellaneous/sayHello.ts
|
|
879
|
-
/**
|
|
880
|
-
* Returns a string representing the lyrics to the package's theme song, Commit To You
|
|
881
|
-
*
|
|
882
|
-
* [Pls listen!](https://www.youtube.com/watch?v=mH-Sg-8EnxM)
|
|
619
|
+
* [Pls listen!](https://www.youtube.com/watch?v=mH-Sg-8EnxM)
|
|
883
620
|
*
|
|
884
621
|
* @returns The lyrics string in markdown format.
|
|
885
622
|
*/
|
|
886
623
|
function sayHello() {
|
|
887
|
-
return
|
|
888
|
-
|
|
624
|
+
return `
|
|
625
|
+
# Commit To You
|
|
889
626
|
|
|
890
|
-
|
|
627
|
+
### Verse 1
|
|
891
628
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
629
|
+
I know you've been checking me out,
|
|
630
|
+
Shall we take it to the next level now?
|
|
631
|
+
'Cause I really wanna be there all for you,
|
|
632
|
+
All for you!
|
|
633
|
+
Come on now, let's make a fresh start!
|
|
634
|
+
Pin my number, then you can take me out!
|
|
635
|
+
Can't you see I really do care about you,
|
|
636
|
+
About you!
|
|
900
637
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
638
|
+
### Pre-chorus 1
|
|
639
|
+
Although our calendars are imperfect, at best,
|
|
640
|
+
I'd like to organise time with you! (with you!).
|
|
641
|
+
Just tell me when and I'll make it clear,
|
|
642
|
+
All clear for you,
|
|
643
|
+
All clear for you!
|
|
644
|
+
(One, two, three, go!)
|
|
908
645
|
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
646
|
+
### Chorus
|
|
647
|
+
I wanna be of utility, I'll help you on the run!
|
|
648
|
+
I'll be the one here in the back, while you go have some fun!
|
|
649
|
+
Looking out for you tonight, I'll be the one you can rely on!
|
|
650
|
+
Watch you go and watch me pass by,
|
|
651
|
+
I'll be here!
|
|
652
|
+
I'll commit to you!
|
|
916
653
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
654
|
+
### Verse 2
|
|
655
|
+
Though sometimes it won't be easy,
|
|
656
|
+
You'll be here to bring out the best in me,
|
|
657
|
+
And I'll hold myself to high standards for you!
|
|
658
|
+
All for you!
|
|
659
|
+
We'll grow as a pair, you and me,
|
|
660
|
+
We'll build up a healthy dependency,
|
|
661
|
+
You can build with me and I'll develop with you!
|
|
662
|
+
I'm with you!
|
|
926
663
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
664
|
+
### Pre-chorus 2
|
|
665
|
+
I'll be with you when you're up or you're down,
|
|
666
|
+
We'll deal with all our problems together (together!)
|
|
667
|
+
Just tell me what you want, I'll make it clear,
|
|
668
|
+
All clear for you,
|
|
669
|
+
All clear for you!
|
|
670
|
+
(One, three, one, go!)
|
|
934
671
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
672
|
+
### Chorus
|
|
673
|
+
I wanna be of utility, I'll help you on the run!
|
|
674
|
+
(help you on the run!)
|
|
675
|
+
I'll be the one here in the back, while you go have some fun!
|
|
676
|
+
(you go have some fun!)
|
|
677
|
+
Looking out for you tonight, I'll be the one you can rely on!
|
|
678
|
+
Watch you go and watch me pass by,
|
|
679
|
+
I'll be here!
|
|
680
|
+
I'll commit to you!
|
|
944
681
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
682
|
+
### Bridge
|
|
683
|
+
Looking into our stack!
|
|
684
|
+
I'll commit to you!
|
|
685
|
+
We've got a lot to unpack!
|
|
686
|
+
I'll commit to you!
|
|
687
|
+
The environment that we're in!
|
|
688
|
+
I'll commit to you!
|
|
689
|
+
Delicate as a string!
|
|
690
|
+
I'll commit to you!
|
|
954
691
|
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
692
|
+
But I think you're my type!
|
|
693
|
+
I'll commit to you!
|
|
694
|
+
Oh, this feels all so right!
|
|
695
|
+
I'll commit to you!
|
|
696
|
+
Nothing stopping us now!
|
|
697
|
+
I'll commit to you!
|
|
698
|
+
Let's show them what we're about!
|
|
699
|
+
Two, three, four, go!
|
|
963
700
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
701
|
+
### Final Chorus
|
|
702
|
+
I wanna be of utility, I'll help you on the run!
|
|
703
|
+
(help you on the run!)
|
|
704
|
+
I'll be the one here in the back, while you go have some fun!
|
|
705
|
+
(you go have some fun!)
|
|
706
|
+
Looking out for you tonight, I'll be the one you can rely on!
|
|
707
|
+
Watch you go and watch me pass by,
|
|
708
|
+
I'll be here!
|
|
709
|
+
I'll commit to you!
|
|
973
710
|
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
711
|
+
I wanna be of utility, I'll help you on the run!
|
|
712
|
+
(I'll commit to you!)
|
|
713
|
+
I'll be the one here in the back, while you go have some fun!
|
|
714
|
+
(I'll commit to you!)
|
|
715
|
+
Looking out for you tonight, I'll be the one you can rely on!
|
|
716
|
+
(I'll commit to you!)
|
|
717
|
+
Watch you go and watch me pass by,
|
|
718
|
+
(I'll commit to you!)
|
|
719
|
+
I'll be here!
|
|
983
720
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
721
|
+
### Outro
|
|
722
|
+
I'll commit to you!
|
|
723
|
+
I'll commit to you!
|
|
724
|
+
I'll commit to you!
|
|
988
725
|
`;
|
|
989
726
|
}
|
|
990
727
|
//#endregion
|
|
@@ -1171,7 +908,7 @@ function _parseZodSchema(parsedResult, input, onError) {
|
|
|
1171
908
|
* @param input - The data to parse.
|
|
1172
909
|
* @param onError - A custom error to throw on invalid data (defaults to `DataError`). May either be the error itself, or a function that returns the error or nothing. If nothing is returned, the default error is thrown instead.
|
|
1173
910
|
*
|
|
1174
|
-
* @throws {
|
|
911
|
+
* @throws {DataErrorCode} If the given data cannot be parsed according to the schema.
|
|
1175
912
|
*
|
|
1176
913
|
* @returns The parsed data from the Zod schema.
|
|
1177
914
|
*/
|
|
@@ -1547,6 +1284,33 @@ function getStringsAndInterpolations(strings, ...interpolations) {
|
|
|
1547
1284
|
return [createTemplateStringsArray(strings), ...interpolations];
|
|
1548
1285
|
}
|
|
1549
1286
|
//#endregion
|
|
1287
|
+
//#region src/root/functions/taggedTemplate/interpolate.ts
|
|
1288
|
+
/**
|
|
1289
|
+
* Returns the result of interpolating a template string when given the strings and interpolations separately.
|
|
1290
|
+
*
|
|
1291
|
+
* You can pass a template string directly by doing:
|
|
1292
|
+
*
|
|
1293
|
+
* ```
|
|
1294
|
+
* interpolate`Template string here`;
|
|
1295
|
+
* ```
|
|
1296
|
+
*
|
|
1297
|
+
* In this case, it will be functionally the same as if you just wrote the template string by itself.
|
|
1298
|
+
*
|
|
1299
|
+
* @category Tagged Template
|
|
1300
|
+
*
|
|
1301
|
+
* @template InterpolationsType - The type of the interpolations.
|
|
1302
|
+
*
|
|
1303
|
+
* @param strings - The strings from the template to process.
|
|
1304
|
+
* @param interpolations - An array of all interpolations from the template.
|
|
1305
|
+
*
|
|
1306
|
+
* @returns A new string with the strings and interpolations from the template applied.
|
|
1307
|
+
*/
|
|
1308
|
+
function interpolate(strings, ...interpolations) {
|
|
1309
|
+
let result = "";
|
|
1310
|
+
for (const [string, interpolation = ""] of paralleliseArrays(strings, interpolations)) result += string + interpolation;
|
|
1311
|
+
return result;
|
|
1312
|
+
}
|
|
1313
|
+
//#endregion
|
|
1550
1314
|
//#region src/root/functions/taggedTemplate/interpolateObjects.ts
|
|
1551
1315
|
/**
|
|
1552
1316
|
* Returns the result of interpolating a template string, also stringifying objects.
|
|
@@ -1589,4 +1353,302 @@ function isTemplateStringsArray(input) {
|
|
|
1589
1353
|
return typeof input === "object" && input !== null && "raw" in input;
|
|
1590
1354
|
}
|
|
1591
1355
|
//#endregion
|
|
1592
|
-
|
|
1356
|
+
//#region src/root/functions/taggedTemplate/normaliseIndents.ts
|
|
1357
|
+
function calculateTabSize(line, whitespaceLength) {
|
|
1358
|
+
const potentialWhitespacePart = line.slice(0, whitespaceLength);
|
|
1359
|
+
const trimmedString = line.trimStart();
|
|
1360
|
+
if (potentialWhitespacePart.trim() !== "") return 0;
|
|
1361
|
+
const tabSize = line.length - (trimmedString.length + whitespaceLength);
|
|
1362
|
+
return tabSize < 0 ? 0 : tabSize;
|
|
1363
|
+
}
|
|
1364
|
+
function getWhitespaceLength(lines) {
|
|
1365
|
+
const [firstNonEmptyLine] = lines.filter((line) => {
|
|
1366
|
+
return line.trim() !== "";
|
|
1367
|
+
});
|
|
1368
|
+
return firstNonEmptyLine.length - firstNonEmptyLine.trimStart().length;
|
|
1369
|
+
}
|
|
1370
|
+
function reduceLines(lines, { preserveTabs = true }) {
|
|
1371
|
+
const slicedLines = lines.slice(1);
|
|
1372
|
+
const isFirstLineEmpty = lines[0].trim() === "";
|
|
1373
|
+
const whitespaceLength = getWhitespaceLength(isFirstLineEmpty ? lines : slicedLines);
|
|
1374
|
+
return (isFirstLineEmpty ? slicedLines : lines).map((line) => {
|
|
1375
|
+
const tabSize = calculateTabSize(line, whitespaceLength);
|
|
1376
|
+
return (preserveTabs ? fillArray(() => {
|
|
1377
|
+
return " ";
|
|
1378
|
+
}, tabSize).join("") : "") + line.trimStart();
|
|
1379
|
+
}).join("\n");
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Applies any options if provided, then removes any extraneous indents from a multi-line template string.
|
|
1383
|
+
*
|
|
1384
|
+
* You can pass a template string directly by doing:
|
|
1385
|
+
*
|
|
1386
|
+
* ```typescript
|
|
1387
|
+
* normaliseIndents`Template string here
|
|
1388
|
+
* with a new line
|
|
1389
|
+
* and another new line`;
|
|
1390
|
+
* ```
|
|
1391
|
+
*
|
|
1392
|
+
* You may also pass the options first, then invoke the resulting function with a template string:
|
|
1393
|
+
*
|
|
1394
|
+
* ```typescript
|
|
1395
|
+
* normaliseIndents({ preserveTabs: false })`Template string here
|
|
1396
|
+
* with a new line
|
|
1397
|
+
* and another new line`;
|
|
1398
|
+
* ```
|
|
1399
|
+
*
|
|
1400
|
+
* @category Tagged Template
|
|
1401
|
+
*
|
|
1402
|
+
* @param first - The strings from the template to process, or the options to apply.
|
|
1403
|
+
* @param args - An array of all interpolations from the template.
|
|
1404
|
+
*
|
|
1405
|
+
* @returns An additional function to invoke, or a new string with the strings and interpolations from the template applied, and extraneous indents removed.
|
|
1406
|
+
*/
|
|
1407
|
+
function normaliseIndents(first, ...args) {
|
|
1408
|
+
if (typeof first === "object" && first !== null && !Array.isArray(first)) {
|
|
1409
|
+
const options = first;
|
|
1410
|
+
return (strings, ...interpolations) => {
|
|
1411
|
+
return normaliseIndents(strings, ...interpolations, options);
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
const strings = first;
|
|
1415
|
+
const options = typeof args[args.length - 1] === "object" && !Array.isArray(args[args.length - 1]) ? args.pop() : {};
|
|
1416
|
+
return reduceLines(interpolate(strings, ...[...args]).split("\n"), options);
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Applies any options if provided, then removes any extraneous indents from a multi-line template string.
|
|
1420
|
+
*
|
|
1421
|
+
* You can pass a template string directly by doing:
|
|
1422
|
+
*
|
|
1423
|
+
* ```typescript
|
|
1424
|
+
* normalizeIndents`Template string here
|
|
1425
|
+
* with a new line
|
|
1426
|
+
* and another new line`.
|
|
1427
|
+
* ```
|
|
1428
|
+
*
|
|
1429
|
+
* You may also pass the options first, then invoke the resulting function with a template string:
|
|
1430
|
+
*
|
|
1431
|
+
* ```typescript
|
|
1432
|
+
* normalizeIndents({ preserveTabs: false })`Template string here
|
|
1433
|
+
* with a new line
|
|
1434
|
+
* and another new line`.
|
|
1435
|
+
* ```
|
|
1436
|
+
*
|
|
1437
|
+
* @param first - The strings from the template to process, or the options to apply.
|
|
1438
|
+
* @param args - An array of all interpolations from the template.
|
|
1439
|
+
*
|
|
1440
|
+
* @returns An additional function to invoke, or a new string with the strings and interpolations from the template applied, and extraneous indents removed.
|
|
1441
|
+
*/
|
|
1442
|
+
const normalizeIndents = normaliseIndents;
|
|
1443
|
+
//#endregion
|
|
1444
|
+
//#region src/root/types/APIError.ts
|
|
1445
|
+
const httpErrorCodeLookup = {
|
|
1446
|
+
400: "BAD_REQUEST",
|
|
1447
|
+
401: "UNAUTHORISED",
|
|
1448
|
+
403: "FORBIDDEN",
|
|
1449
|
+
404: "NOT_FOUND",
|
|
1450
|
+
418: "I_AM_A_TEAPOT",
|
|
1451
|
+
500: "INTERNAL_SERVER_ERROR"
|
|
1452
|
+
};
|
|
1453
|
+
/**
|
|
1454
|
+
* Represents common errors you may get from a HTTP API request.
|
|
1455
|
+
*
|
|
1456
|
+
* @category Types
|
|
1457
|
+
*/
|
|
1458
|
+
var APIError = class APIError extends Error {
|
|
1459
|
+
status;
|
|
1460
|
+
/**
|
|
1461
|
+
* @param status - A HTTP status code. Can be any number, but numbers between 400 and 600 are encouraged to fit with HTTP status code conventions.
|
|
1462
|
+
* @param message - An error message to display alongside the status code.
|
|
1463
|
+
* @param options - Extra options to be passed to super Error constructor.
|
|
1464
|
+
*/
|
|
1465
|
+
constructor(status = 500, message, options) {
|
|
1466
|
+
super(message, options);
|
|
1467
|
+
this.status = status;
|
|
1468
|
+
if (message) this.message = message;
|
|
1469
|
+
else this.message = httpErrorCodeLookup[this.status] ?? "API_ERROR";
|
|
1470
|
+
Object.defineProperty(this, "message", { enumerable: true });
|
|
1471
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1472
|
+
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Checks whether the given input may have been caused by an APIError.
|
|
1475
|
+
*
|
|
1476
|
+
* @param input - The input to check.
|
|
1477
|
+
*
|
|
1478
|
+
* @returns `true` if the input is an APIError, and `false` otherwise. The type of the input will also be narrowed down to APIError if `true`.
|
|
1479
|
+
*/
|
|
1480
|
+
static check(input) {
|
|
1481
|
+
if (input instanceof APIError) return true;
|
|
1482
|
+
const data = input;
|
|
1483
|
+
return typeof data === "object" && data !== null && typeof data?.status === "number" && typeof data?.message === "string";
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
//#endregion
|
|
1487
|
+
//#region src/root/types/VersionNumber.ts
|
|
1488
|
+
/**
|
|
1489
|
+
* Represents a software version number, considered to be made up of a major, minor, and patch part.
|
|
1490
|
+
*
|
|
1491
|
+
* @category Types
|
|
1492
|
+
*/
|
|
1493
|
+
var VersionNumber = class VersionNumber {
|
|
1494
|
+
static NON_NEGATIVE_TUPLE_ERROR = "Input array must be a tuple of three non-negative integers.";
|
|
1495
|
+
/** The major number. Increments when a feature is removed or changed in a way that is not backwards-compatible with the previous release. */
|
|
1496
|
+
major = 0;
|
|
1497
|
+
/** The minor number. Increments when a new feature is added/deprecated and is expected to be backwards-compatible with the previous release. */
|
|
1498
|
+
minor = 0;
|
|
1499
|
+
/** The patch number. Increments when the next release is fixing a bug or doing a small refactor that should not be noticeable in practice. */
|
|
1500
|
+
patch = 0;
|
|
1501
|
+
/**
|
|
1502
|
+
* @param input - The input to create a new instance of `VersionNumber` from.
|
|
1503
|
+
*/
|
|
1504
|
+
constructor(input) {
|
|
1505
|
+
if (input instanceof VersionNumber) {
|
|
1506
|
+
this.major = input.major;
|
|
1507
|
+
this.minor = input.minor;
|
|
1508
|
+
this.patch = input.patch;
|
|
1509
|
+
} else if (typeof input === "string") {
|
|
1510
|
+
if (!VERSION_NUMBER_REGEX.test(input)) throw new DataError({ input }, "INVALID_VERSION", `"${input}" is not a valid version number. Version numbers must be of the format "X.Y.Z" or "vX.Y.Z", where X, Y, and Z are non-negative integers.`);
|
|
1511
|
+
const [major, minor, patch] = VersionNumber.formatString(input, { omitPrefix: true }).split(".").map((number) => {
|
|
1512
|
+
return parseIntStrict(number);
|
|
1513
|
+
});
|
|
1514
|
+
this.major = major;
|
|
1515
|
+
this.minor = minor;
|
|
1516
|
+
this.patch = patch;
|
|
1517
|
+
} else if (Array.isArray(input)) {
|
|
1518
|
+
if (input.length !== 3) throw new DataError({ input }, "INVALID_LENGTH", VersionNumber.NON_NEGATIVE_TUPLE_ERROR);
|
|
1519
|
+
const [major, minor, patch] = input.map((number) => {
|
|
1520
|
+
const parsedInteger = parseIntStrict(number?.toString());
|
|
1521
|
+
if (parsedInteger < 0) throw new DataError({ input }, "NEGATIVE_INPUTS", VersionNumber.NON_NEGATIVE_TUPLE_ERROR);
|
|
1522
|
+
return parsedInteger;
|
|
1523
|
+
});
|
|
1524
|
+
this.major = major;
|
|
1525
|
+
this.minor = minor;
|
|
1526
|
+
this.patch = patch;
|
|
1527
|
+
} else throw new DataError({ input }, "INVALID_INPUT", normaliseIndents`
|
|
1528
|
+
The provided input can not be parsed into a valid version number.
|
|
1529
|
+
Expected either a string of format X.Y.Z or vX.Y.Z, a tuple of three numbers, or another \`VersionNumber\` instance.
|
|
1530
|
+
`);
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Gets the current version type of the current instance of `VersionNumber`.
|
|
1534
|
+
*
|
|
1535
|
+
* @returns Either `"major"`, `"minor"`, or `"patch"`, depending on the version type.
|
|
1536
|
+
*/
|
|
1537
|
+
get type() {
|
|
1538
|
+
if (this.minor === 0 && this.patch === 0) return VersionType.MAJOR;
|
|
1539
|
+
if (this.patch === 0) return VersionType.MINOR;
|
|
1540
|
+
return VersionType.PATCH;
|
|
1541
|
+
}
|
|
1542
|
+
static formatString(input, options) {
|
|
1543
|
+
if (options?.omitPrefix) return input.startsWith("v") ? input.slice(1) : input;
|
|
1544
|
+
return input.startsWith("v") ? input : `v${input}`;
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Checks if the provided version numbers have the exact same major, minor, and patch numbers.
|
|
1548
|
+
*
|
|
1549
|
+
* @param firstVersion - The first version number to compare.
|
|
1550
|
+
* @param secondVersion - The second version number to compare.
|
|
1551
|
+
*
|
|
1552
|
+
* @returns `true` if the provided version numbers have exactly the same major, minor, and patch numbers, and returns `false` otherwise.
|
|
1553
|
+
*/
|
|
1554
|
+
static isEqual(firstVersion, secondVersion) {
|
|
1555
|
+
return firstVersion.major === secondVersion.major && firstVersion.minor === secondVersion.minor && firstVersion.patch === secondVersion.patch;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Get a formatted string representation of the current version number
|
|
1559
|
+
*
|
|
1560
|
+
* @param options - Options to apply to the string formatting.
|
|
1561
|
+
*
|
|
1562
|
+
* @returns A formatted string representation of the current version number with the options applied.
|
|
1563
|
+
*/
|
|
1564
|
+
format(options) {
|
|
1565
|
+
let baseOutput = `${this.major}`;
|
|
1566
|
+
if (!options?.omitMinor) {
|
|
1567
|
+
baseOutput += `.${this.minor}`;
|
|
1568
|
+
if (!options?.omitPatch) baseOutput += `.${this.patch}`;
|
|
1569
|
+
}
|
|
1570
|
+
return VersionNumber.formatString(baseOutput, { omitPrefix: options?.omitPrefix });
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* Increments the current version number by the given increment type, returning the result as a new reference in memory.
|
|
1574
|
+
*
|
|
1575
|
+
* @param incrementType - The type of increment. Can be one of the following:
|
|
1576
|
+
* - `"major"`: Change the major version `v1.2.3` → `v2.0.0`
|
|
1577
|
+
* - `"minor"`: Change the minor version `v1.2.3` → `v1.3.0`
|
|
1578
|
+
* - `"patch"`: Change the patch version `v1.2.3` → `v1.2.4`
|
|
1579
|
+
* @param incrementAmount - The amount to increment by (defaults to 1).
|
|
1580
|
+
*
|
|
1581
|
+
* @returns A new instance of `VersionNumber` with the increment applied.
|
|
1582
|
+
*/
|
|
1583
|
+
increment(incrementType, incrementAmount = 1) {
|
|
1584
|
+
const incrementBy = parseIntStrict(String(incrementAmount));
|
|
1585
|
+
const calculatedRawVersion = {
|
|
1586
|
+
major: [
|
|
1587
|
+
this.major + incrementBy,
|
|
1588
|
+
0,
|
|
1589
|
+
0
|
|
1590
|
+
],
|
|
1591
|
+
minor: [
|
|
1592
|
+
this.major,
|
|
1593
|
+
this.minor + incrementBy,
|
|
1594
|
+
0
|
|
1595
|
+
],
|
|
1596
|
+
patch: [
|
|
1597
|
+
this.major,
|
|
1598
|
+
this.minor,
|
|
1599
|
+
this.patch + incrementBy
|
|
1600
|
+
]
|
|
1601
|
+
}[incrementType];
|
|
1602
|
+
try {
|
|
1603
|
+
return new VersionNumber(calculatedRawVersion);
|
|
1604
|
+
} catch (error) {
|
|
1605
|
+
if (DataError.check(error) && error.code === "NEGATIVE_INPUTS") throw new DataError({
|
|
1606
|
+
currentVersion: this.toString(),
|
|
1607
|
+
calculatedRawVersion: `v${calculatedRawVersion.join(".")}`,
|
|
1608
|
+
incrementAmount
|
|
1609
|
+
}, "NEGATIVE_VERSION", "Cannot apply this increment amount as it would lead to a negative version number.");
|
|
1610
|
+
else throw error;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* Ensures that the VersionNumber behaves correctly when attempted to be coerced to a string.
|
|
1615
|
+
*
|
|
1616
|
+
* @param hint - Not used as of now, but generally used to help with numeric coercion, I think (which we most likely do not need for version numbers).
|
|
1617
|
+
*
|
|
1618
|
+
* @returns A stringified representation of the current version number, prefixed with `v`.
|
|
1619
|
+
*/
|
|
1620
|
+
[Symbol.toPrimitive](hint) {
|
|
1621
|
+
if (hint === "number") throw new DataError({ thisVersion: this.toString() }, "INVALID_COERCION", "VersionNumber cannot be coerced to a number type.");
|
|
1622
|
+
return this.toString();
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1625
|
+
* Ensures that the VersionNumber behaves correctly when attempted to be converted to JSON.
|
|
1626
|
+
*
|
|
1627
|
+
* @returns A stringified representation of the current version number, prefixed with `v`.
|
|
1628
|
+
*/
|
|
1629
|
+
toJSON() {
|
|
1630
|
+
return this.toString();
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Get a string representation of the current version number.
|
|
1634
|
+
*
|
|
1635
|
+
* @returns A stringified representation of the current version number with the prefix.
|
|
1636
|
+
*/
|
|
1637
|
+
toString() {
|
|
1638
|
+
const rawString = `${this.major}.${this.minor}.${this.patch}`;
|
|
1639
|
+
return VersionNumber.formatString(rawString, { omitPrefix: false });
|
|
1640
|
+
}
|
|
1641
|
+
};
|
|
1642
|
+
const zodVersionNumber = z$1.union([
|
|
1643
|
+
z$1.string(),
|
|
1644
|
+
z$1.tuple([
|
|
1645
|
+
z$1.number(),
|
|
1646
|
+
z$1.number(),
|
|
1647
|
+
z$1.number()
|
|
1648
|
+
]),
|
|
1649
|
+
z$1.instanceof(VersionNumber)
|
|
1650
|
+
]).transform((rawVersionNumber) => {
|
|
1651
|
+
return new VersionNumber(rawVersionNumber);
|
|
1652
|
+
});
|
|
1653
|
+
//#endregion
|
|
1654
|
+
export { APIError, Env, FILE_PATH_PATTERN, FILE_PATH_REGEX, ONE_DAY_IN_MILLISECONDS, UUID_PATTERN, UUID_REGEX, VERSION_NUMBER_PATTERN, VERSION_NUMBER_REGEX, VersionNumber, VersionType, addDaysToDate, appendSemicolon, calculateMonthlyDifference, camelToKebab, convertFileToBase64, createFormData, createTemplateStringsArray, deepCopy, deepFreeze, escapeRegexPattern, fillArray, formatDateAndTime, getRandomNumber, getRecordKeys, getStringsAndInterpolations, httpErrorCodeLookup, interpolate, interpolateObjects, isAnniversary, isLeapYear, isMonthlyMultiple, isOrdered, isSameDate, isTemplateStringsArray, kebabToCamel, normaliseIndents, normalizeIndents, omitProperties, paralleliseArrays, parseBoolean, parseEnv, parseFormData, parseIntStrict, parseUUID, parseVersionType, parseZodSchema, parseZodSchemaAsync, randomiseArray, range, removeDuplicates, removeUndefinedFromObject, sayHello, stringListToArray, stringifyDotenv, toTitleCase, truncate, wait, zodVersionNumber };
|