@excofy/utils 1.0.1 → 1.0.3
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 +69 -2
- package/dist/index.d.cts +65 -1
- package/dist/index.d.ts +65 -1
- package/dist/index.js +62 -1
- package/package.json +3 -1
- package/src/helpers/number.ts +31 -0
- package/src/helpers/slug.ts +50 -0
- package/src/helpers/validator.ts +18 -0
- package/src/index.ts +3 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,13 +17,23 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
23
33
|
createValidator: () => createValidator,
|
|
24
|
-
htmlEntityDecode: () => htmlEntityDecode
|
|
34
|
+
htmlEntityDecode: () => htmlEntityDecode,
|
|
35
|
+
numberUtils: () => number_exports,
|
|
36
|
+
slugUtils: () => slug_exports
|
|
25
37
|
});
|
|
26
38
|
module.exports = __toCommonJS(index_exports);
|
|
27
39
|
|
|
@@ -311,6 +323,21 @@ function createValidator() {
|
|
|
311
323
|
}
|
|
312
324
|
return validator;
|
|
313
325
|
},
|
|
326
|
+
url(message) {
|
|
327
|
+
if (shouldSkipValidation()) {
|
|
328
|
+
return validator;
|
|
329
|
+
}
|
|
330
|
+
if (typeof current.value === "string") {
|
|
331
|
+
try {
|
|
332
|
+
new URL(current.value);
|
|
333
|
+
} catch {
|
|
334
|
+
current.pushError(message);
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
current.pushError(message);
|
|
338
|
+
}
|
|
339
|
+
return validator;
|
|
340
|
+
},
|
|
314
341
|
uuid(message) {
|
|
315
342
|
if (shouldSkipValidation()) {
|
|
316
343
|
return validator;
|
|
@@ -452,8 +479,48 @@ function createValidator() {
|
|
|
452
479
|
}
|
|
453
480
|
};
|
|
454
481
|
}
|
|
482
|
+
|
|
483
|
+
// src/helpers/slug.ts
|
|
484
|
+
var slug_exports = {};
|
|
485
|
+
__export(slug_exports, {
|
|
486
|
+
generateUniqueSlug: () => generateUniqueSlug,
|
|
487
|
+
removeTrailingNumber: () => removeTrailingNumber
|
|
488
|
+
});
|
|
489
|
+
var generateUniqueSlug = (baseSlug, existingSlugs) => {
|
|
490
|
+
const suffixes = existingSlugs.map((slug) => {
|
|
491
|
+
const match = slug.match(new RegExp(`^${baseSlug}-(\\d+)$`));
|
|
492
|
+
return match ? Number(match[1]) : slug === baseSlug ? 0 : null;
|
|
493
|
+
}).filter((num) => num !== null);
|
|
494
|
+
const nextSuffix = suffixes.length > 0 ? Math.max(...suffixes) + 1 : 0;
|
|
495
|
+
return nextSuffix === 0 ? baseSlug : `${baseSlug}-${nextSuffix}`;
|
|
496
|
+
};
|
|
497
|
+
var removeTrailingNumber = (slug) => {
|
|
498
|
+
return slug.replace(/-\d+$/, "");
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
// src/helpers/number.ts
|
|
502
|
+
var number_exports = {};
|
|
503
|
+
__export(number_exports, {
|
|
504
|
+
toCents: () => toCents,
|
|
505
|
+
toDecimal: () => toDecimal
|
|
506
|
+
});
|
|
507
|
+
var import_big = __toESM(require("big.js"), 1);
|
|
508
|
+
var toCents = (value) => {
|
|
509
|
+
if (!value) {
|
|
510
|
+
return 0;
|
|
511
|
+
}
|
|
512
|
+
return new import_big.default(value).mul(100).round(0).toNumber();
|
|
513
|
+
};
|
|
514
|
+
var toDecimal = (value) => {
|
|
515
|
+
if (!value) {
|
|
516
|
+
return 0;
|
|
517
|
+
}
|
|
518
|
+
return new import_big.default(value).div(100).round(2).toNumber();
|
|
519
|
+
};
|
|
455
520
|
// Annotate the CommonJS export names for ESM import in node:
|
|
456
521
|
0 && (module.exports = {
|
|
457
522
|
createValidator,
|
|
458
|
-
htmlEntityDecode
|
|
523
|
+
htmlEntityDecode,
|
|
524
|
+
numberUtils,
|
|
525
|
+
slugUtils
|
|
459
526
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -55,6 +55,7 @@ declare function createValidator<TRaw extends Record<string, TInputValue>, TPars
|
|
|
55
55
|
slug(message: string): /*elided*/ any;
|
|
56
56
|
sanitize(): /*elided*/ any;
|
|
57
57
|
sanitizeHTML(tags?: AllowedTag[]): /*elided*/ any;
|
|
58
|
+
url(message: string): /*elided*/ any;
|
|
58
59
|
uuid(message: string): /*elided*/ any;
|
|
59
60
|
oneOf: (types: string[], message: string) => /*elided*/ any;
|
|
60
61
|
videoUrl: {
|
|
@@ -78,6 +79,7 @@ declare function createValidator<TRaw extends Record<string, TInputValue>, TPars
|
|
|
78
79
|
slug(message: string): /*elided*/ any;
|
|
79
80
|
sanitize(): /*elided*/ any;
|
|
80
81
|
sanitizeHTML(tags?: AllowedTag[]): /*elided*/ any;
|
|
82
|
+
url(message: string): /*elided*/ any;
|
|
81
83
|
uuid(message: string): /*elided*/ any;
|
|
82
84
|
oneOf: (types: string[], message: string) => /*elided*/ any;
|
|
83
85
|
videoUrl: {
|
|
@@ -91,4 +93,66 @@ declare function createValidator<TRaw extends Record<string, TInputValue>, TPars
|
|
|
91
93
|
};
|
|
92
94
|
};
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Generates a unique slug by appending a numeric suffix to the base slug if necessary.
|
|
98
|
+
*
|
|
99
|
+
* If the base slug is already used (either exactly or with a numeric suffix),
|
|
100
|
+
* the function finds the highest existing suffix and returns the next one in sequence.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* generateUniqueSlug('my-product', ['my-product', 'my-product-1', 'my-product-2'])
|
|
104
|
+
* // returns 'my-product-3'
|
|
105
|
+
*
|
|
106
|
+
* generateUniqueSlug('item', ['item-1', 'item-2'])
|
|
107
|
+
* // returns 'item'
|
|
108
|
+
*
|
|
109
|
+
* @param {string} baseSlug - The initial slug to use as a base.
|
|
110
|
+
* @param {string[]} existingSlugs - A list of existing slugs to avoid duplicates.
|
|
111
|
+
* @returns {string} A unique slug not present in the existingSlugs list.
|
|
112
|
+
*/
|
|
113
|
+
declare const generateUniqueSlug: (baseSlug: string, existingSlugs: string[]) => string;
|
|
114
|
+
/**
|
|
115
|
+
* Removes a trailing numeric suffix from a slug, if present.
|
|
116
|
+
*
|
|
117
|
+
* This is useful for extracting the base part of a slug before checking
|
|
118
|
+
* or generating new unique variations.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* removeTrailingNumber('product-3') // returns 'product'
|
|
122
|
+
* removeTrailingNumber('item') // returns 'item'
|
|
123
|
+
*
|
|
124
|
+
* @param {string} slug - The slug from which to remove the trailing number.
|
|
125
|
+
* @returns {string} The slug without the trailing numeric suffix.
|
|
126
|
+
*/
|
|
127
|
+
declare const removeTrailingNumber: (slug: string) => string;
|
|
128
|
+
|
|
129
|
+
declare const slug_generateUniqueSlug: typeof generateUniqueSlug;
|
|
130
|
+
declare const slug_removeTrailingNumber: typeof removeTrailingNumber;
|
|
131
|
+
declare namespace slug {
|
|
132
|
+
export { slug_generateUniqueSlug as generateUniqueSlug, slug_removeTrailingNumber as removeTrailingNumber };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Converts a decimal number to an integer by multiplying it by 100.
|
|
137
|
+
* Commonly used to convert monetary values from dollars to cents.
|
|
138
|
+
*
|
|
139
|
+
* @param {number} value - The decimal number to convert (e.g., 10.90).
|
|
140
|
+
* @returns {number} The integer value in cents (e.g., 1090).
|
|
141
|
+
*/
|
|
142
|
+
declare const toCents: (value?: number) => number;
|
|
143
|
+
/**
|
|
144
|
+
* Converts an integer back to a decimal by dividing it by 100.
|
|
145
|
+
* Commonly used to convert monetary values from cents to dollars.
|
|
146
|
+
*
|
|
147
|
+
* @param {number} value - The integer value in cents (e.g., 1090).
|
|
148
|
+
* @returns {number} The decimal value (e.g., 10.90).
|
|
149
|
+
*/
|
|
150
|
+
declare const toDecimal: (value?: number) => number;
|
|
151
|
+
|
|
152
|
+
declare const number_toCents: typeof toCents;
|
|
153
|
+
declare const number_toDecimal: typeof toDecimal;
|
|
154
|
+
declare namespace number {
|
|
155
|
+
export { number_toCents as toCents, number_toDecimal as toDecimal };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { createValidator, htmlEntityDecode, number as numberUtils, slug as slugUtils };
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ declare function createValidator<TRaw extends Record<string, TInputValue>, TPars
|
|
|
55
55
|
slug(message: string): /*elided*/ any;
|
|
56
56
|
sanitize(): /*elided*/ any;
|
|
57
57
|
sanitizeHTML(tags?: AllowedTag[]): /*elided*/ any;
|
|
58
|
+
url(message: string): /*elided*/ any;
|
|
58
59
|
uuid(message: string): /*elided*/ any;
|
|
59
60
|
oneOf: (types: string[], message: string) => /*elided*/ any;
|
|
60
61
|
videoUrl: {
|
|
@@ -78,6 +79,7 @@ declare function createValidator<TRaw extends Record<string, TInputValue>, TPars
|
|
|
78
79
|
slug(message: string): /*elided*/ any;
|
|
79
80
|
sanitize(): /*elided*/ any;
|
|
80
81
|
sanitizeHTML(tags?: AllowedTag[]): /*elided*/ any;
|
|
82
|
+
url(message: string): /*elided*/ any;
|
|
81
83
|
uuid(message: string): /*elided*/ any;
|
|
82
84
|
oneOf: (types: string[], message: string) => /*elided*/ any;
|
|
83
85
|
videoUrl: {
|
|
@@ -91,4 +93,66 @@ declare function createValidator<TRaw extends Record<string, TInputValue>, TPars
|
|
|
91
93
|
};
|
|
92
94
|
};
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Generates a unique slug by appending a numeric suffix to the base slug if necessary.
|
|
98
|
+
*
|
|
99
|
+
* If the base slug is already used (either exactly or with a numeric suffix),
|
|
100
|
+
* the function finds the highest existing suffix and returns the next one in sequence.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* generateUniqueSlug('my-product', ['my-product', 'my-product-1', 'my-product-2'])
|
|
104
|
+
* // returns 'my-product-3'
|
|
105
|
+
*
|
|
106
|
+
* generateUniqueSlug('item', ['item-1', 'item-2'])
|
|
107
|
+
* // returns 'item'
|
|
108
|
+
*
|
|
109
|
+
* @param {string} baseSlug - The initial slug to use as a base.
|
|
110
|
+
* @param {string[]} existingSlugs - A list of existing slugs to avoid duplicates.
|
|
111
|
+
* @returns {string} A unique slug not present in the existingSlugs list.
|
|
112
|
+
*/
|
|
113
|
+
declare const generateUniqueSlug: (baseSlug: string, existingSlugs: string[]) => string;
|
|
114
|
+
/**
|
|
115
|
+
* Removes a trailing numeric suffix from a slug, if present.
|
|
116
|
+
*
|
|
117
|
+
* This is useful for extracting the base part of a slug before checking
|
|
118
|
+
* or generating new unique variations.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* removeTrailingNumber('product-3') // returns 'product'
|
|
122
|
+
* removeTrailingNumber('item') // returns 'item'
|
|
123
|
+
*
|
|
124
|
+
* @param {string} slug - The slug from which to remove the trailing number.
|
|
125
|
+
* @returns {string} The slug without the trailing numeric suffix.
|
|
126
|
+
*/
|
|
127
|
+
declare const removeTrailingNumber: (slug: string) => string;
|
|
128
|
+
|
|
129
|
+
declare const slug_generateUniqueSlug: typeof generateUniqueSlug;
|
|
130
|
+
declare const slug_removeTrailingNumber: typeof removeTrailingNumber;
|
|
131
|
+
declare namespace slug {
|
|
132
|
+
export { slug_generateUniqueSlug as generateUniqueSlug, slug_removeTrailingNumber as removeTrailingNumber };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Converts a decimal number to an integer by multiplying it by 100.
|
|
137
|
+
* Commonly used to convert monetary values from dollars to cents.
|
|
138
|
+
*
|
|
139
|
+
* @param {number} value - The decimal number to convert (e.g., 10.90).
|
|
140
|
+
* @returns {number} The integer value in cents (e.g., 1090).
|
|
141
|
+
*/
|
|
142
|
+
declare const toCents: (value?: number) => number;
|
|
143
|
+
/**
|
|
144
|
+
* Converts an integer back to a decimal by dividing it by 100.
|
|
145
|
+
* Commonly used to convert monetary values from cents to dollars.
|
|
146
|
+
*
|
|
147
|
+
* @param {number} value - The integer value in cents (e.g., 1090).
|
|
148
|
+
* @returns {number} The decimal value (e.g., 10.90).
|
|
149
|
+
*/
|
|
150
|
+
declare const toDecimal: (value?: number) => number;
|
|
151
|
+
|
|
152
|
+
declare const number_toCents: typeof toCents;
|
|
153
|
+
declare const number_toDecimal: typeof toDecimal;
|
|
154
|
+
declare namespace number {
|
|
155
|
+
export { number_toCents as toCents, number_toDecimal as toDecimal };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { createValidator, htmlEntityDecode, number as numberUtils, slug as slugUtils };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
1
7
|
// src/helpers/sanitize.ts
|
|
2
8
|
import { FilterXSS } from "xss";
|
|
3
9
|
var allTags = [
|
|
@@ -284,6 +290,21 @@ function createValidator() {
|
|
|
284
290
|
}
|
|
285
291
|
return validator;
|
|
286
292
|
},
|
|
293
|
+
url(message) {
|
|
294
|
+
if (shouldSkipValidation()) {
|
|
295
|
+
return validator;
|
|
296
|
+
}
|
|
297
|
+
if (typeof current.value === "string") {
|
|
298
|
+
try {
|
|
299
|
+
new URL(current.value);
|
|
300
|
+
} catch {
|
|
301
|
+
current.pushError(message);
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
current.pushError(message);
|
|
305
|
+
}
|
|
306
|
+
return validator;
|
|
307
|
+
},
|
|
287
308
|
uuid(message) {
|
|
288
309
|
if (shouldSkipValidation()) {
|
|
289
310
|
return validator;
|
|
@@ -425,7 +446,47 @@ function createValidator() {
|
|
|
425
446
|
}
|
|
426
447
|
};
|
|
427
448
|
}
|
|
449
|
+
|
|
450
|
+
// src/helpers/slug.ts
|
|
451
|
+
var slug_exports = {};
|
|
452
|
+
__export(slug_exports, {
|
|
453
|
+
generateUniqueSlug: () => generateUniqueSlug,
|
|
454
|
+
removeTrailingNumber: () => removeTrailingNumber
|
|
455
|
+
});
|
|
456
|
+
var generateUniqueSlug = (baseSlug, existingSlugs) => {
|
|
457
|
+
const suffixes = existingSlugs.map((slug) => {
|
|
458
|
+
const match = slug.match(new RegExp(`^${baseSlug}-(\\d+)$`));
|
|
459
|
+
return match ? Number(match[1]) : slug === baseSlug ? 0 : null;
|
|
460
|
+
}).filter((num) => num !== null);
|
|
461
|
+
const nextSuffix = suffixes.length > 0 ? Math.max(...suffixes) + 1 : 0;
|
|
462
|
+
return nextSuffix === 0 ? baseSlug : `${baseSlug}-${nextSuffix}`;
|
|
463
|
+
};
|
|
464
|
+
var removeTrailingNumber = (slug) => {
|
|
465
|
+
return slug.replace(/-\d+$/, "");
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
// src/helpers/number.ts
|
|
469
|
+
var number_exports = {};
|
|
470
|
+
__export(number_exports, {
|
|
471
|
+
toCents: () => toCents,
|
|
472
|
+
toDecimal: () => toDecimal
|
|
473
|
+
});
|
|
474
|
+
import Big from "big.js";
|
|
475
|
+
var toCents = (value) => {
|
|
476
|
+
if (!value) {
|
|
477
|
+
return 0;
|
|
478
|
+
}
|
|
479
|
+
return new Big(value).mul(100).round(0).toNumber();
|
|
480
|
+
};
|
|
481
|
+
var toDecimal = (value) => {
|
|
482
|
+
if (!value) {
|
|
483
|
+
return 0;
|
|
484
|
+
}
|
|
485
|
+
return new Big(value).div(100).round(2).toNumber();
|
|
486
|
+
};
|
|
428
487
|
export {
|
|
429
488
|
createValidator,
|
|
430
|
-
htmlEntityDecode
|
|
489
|
+
htmlEntityDecode,
|
|
490
|
+
number_exports as numberUtils,
|
|
491
|
+
slug_exports as slugUtils
|
|
431
492
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@excofy/utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Biblioteca de utilitários para o Excofy",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -30,11 +30,13 @@
|
|
|
30
30
|
"homepage": "https://github.com/excofy/utils#readme",
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@biomejs/biome": "^1.9.4",
|
|
33
|
+
"@types/big.js": "^6.2.2",
|
|
33
34
|
"@types/node": "^24.0.3",
|
|
34
35
|
"tsup": "^8.5.0",
|
|
35
36
|
"typescript": "^5.8.3"
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
39
|
+
"big.js": "^7.0.1",
|
|
38
40
|
"xss": "^1.0.15"
|
|
39
41
|
},
|
|
40
42
|
"publishConfig": {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Big from 'big.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts a decimal number to an integer by multiplying it by 100.
|
|
5
|
+
* Commonly used to convert monetary values from dollars to cents.
|
|
6
|
+
*
|
|
7
|
+
* @param {number} value - The decimal number to convert (e.g., 10.90).
|
|
8
|
+
* @returns {number} The integer value in cents (e.g., 1090).
|
|
9
|
+
*/
|
|
10
|
+
export const toCents = (value?: number): number => {
|
|
11
|
+
if (!value) {
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return new Big(value).mul(100).round(0).toNumber();
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Converts an integer back to a decimal by dividing it by 100.
|
|
20
|
+
* Commonly used to convert monetary values from cents to dollars.
|
|
21
|
+
*
|
|
22
|
+
* @param {number} value - The integer value in cents (e.g., 1090).
|
|
23
|
+
* @returns {number} The decimal value (e.g., 10.90).
|
|
24
|
+
*/
|
|
25
|
+
export const toDecimal = (value?: number): number => {
|
|
26
|
+
if (!value) {
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return new Big(value).div(100).round(2).toNumber();
|
|
31
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a unique slug by appending a numeric suffix to the base slug if necessary.
|
|
3
|
+
*
|
|
4
|
+
* If the base slug is already used (either exactly or with a numeric suffix),
|
|
5
|
+
* the function finds the highest existing suffix and returns the next one in sequence.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* generateUniqueSlug('my-product', ['my-product', 'my-product-1', 'my-product-2'])
|
|
9
|
+
* // returns 'my-product-3'
|
|
10
|
+
*
|
|
11
|
+
* generateUniqueSlug('item', ['item-1', 'item-2'])
|
|
12
|
+
* // returns 'item'
|
|
13
|
+
*
|
|
14
|
+
* @param {string} baseSlug - The initial slug to use as a base.
|
|
15
|
+
* @param {string[]} existingSlugs - A list of existing slugs to avoid duplicates.
|
|
16
|
+
* @returns {string} A unique slug not present in the existingSlugs list.
|
|
17
|
+
*/
|
|
18
|
+
export const generateUniqueSlug = (
|
|
19
|
+
baseSlug: string,
|
|
20
|
+
existingSlugs: string[]
|
|
21
|
+
): string => {
|
|
22
|
+
const suffixes = existingSlugs
|
|
23
|
+
.map((slug) => {
|
|
24
|
+
const match = slug.match(new RegExp(`^${baseSlug}-(\\d+)$`));
|
|
25
|
+
return match ? Number(match[1]) : slug === baseSlug ? 0 : null;
|
|
26
|
+
})
|
|
27
|
+
.filter((num): num is number => num !== null);
|
|
28
|
+
|
|
29
|
+
const nextSuffix = suffixes.length > 0 ? Math.max(...suffixes) + 1 : 0;
|
|
30
|
+
|
|
31
|
+
return nextSuffix === 0 ? baseSlug : `${baseSlug}-${nextSuffix}`;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Removes a trailing numeric suffix from a slug, if present.
|
|
36
|
+
*
|
|
37
|
+
* This is useful for extracting the base part of a slug before checking
|
|
38
|
+
* or generating new unique variations.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* removeTrailingNumber('product-3') // returns 'product'
|
|
42
|
+
* removeTrailingNumber('item') // returns 'item'
|
|
43
|
+
*
|
|
44
|
+
* @param {string} slug - The slug from which to remove the trailing number.
|
|
45
|
+
* @returns {string} The slug without the trailing numeric suffix.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
export const removeTrailingNumber = (slug: string): string => {
|
|
49
|
+
return slug.replace(/-\d+$/, '');
|
|
50
|
+
};
|
package/src/helpers/validator.ts
CHANGED
|
@@ -292,6 +292,24 @@ export function createValidator<
|
|
|
292
292
|
return validator;
|
|
293
293
|
},
|
|
294
294
|
|
|
295
|
+
url(message: string) {
|
|
296
|
+
if (shouldSkipValidation()) {
|
|
297
|
+
return validator;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (typeof current.value === 'string') {
|
|
301
|
+
try {
|
|
302
|
+
new URL(current.value);
|
|
303
|
+
} catch {
|
|
304
|
+
current.pushError(message);
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
current.pushError(message);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return validator;
|
|
311
|
+
},
|
|
312
|
+
|
|
295
313
|
uuid(message: string) {
|
|
296
314
|
if (shouldSkipValidation()) {
|
|
297
315
|
return validator;
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createValidator } from './helpers/validator';
|
|
2
2
|
import { htmlEntityDecode } from './helpers/sanitize';
|
|
3
|
+
import * as slugUtils from './helpers/slug';
|
|
4
|
+
import * as numberUtils from './helpers/number';
|
|
3
5
|
|
|
4
|
-
export { createValidator, htmlEntityDecode };
|
|
6
|
+
export { createValidator, htmlEntityDecode, slugUtils, numberUtils };
|