@salespark/toolkit 2.1.8 → 2.1.9

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/README.md CHANGED
@@ -26,7 +26,7 @@ npm i @salespark/toolkit
26
26
 
27
27
  - **Array utilities**: chunk, uniqBy, deep equality, flatten, groupBy, etc.
28
28
  - **Object utilities**: pick, omit, clean objects, deep merge, etc.
29
- - **String utilities**: slugify, template fill, deburr, sanitize, etc.
29
+ - **String utilities**: slugify, template fill, deburr, sanitize, capitalize words/sentences.
30
30
  - **Number utilities**: clamp, round, safe arithmetic/comparisons, safe parse (locale-aware), random digits, etc.
31
31
  - **Function utilities**: debounce, throttle, formatCurrency, parseName, currency conversions, etc.
32
32
  - **Boolean utilities**: safe boolean conversion with common representations
@@ -317,6 +317,30 @@ deburr("café résumé naïve");
317
317
  // Result: "cafe resume naive"
318
318
  ```
319
319
 
320
+ **`capitalizeFirst(input: string, options?: { lowerRest?: boolean; locale?: string | string[] }): string`** — Capitalizes only the first character; optionally lowercases the rest.
321
+
322
+ ```javascript
323
+ capitalizeFirst("hELLO world");
324
+ // Result: "Hello world"
325
+ ```
326
+
327
+ **`capitalizeWords(input: string, options?: { lowerRest?: boolean; locale?: string | string[]; treatHyphenAsSeparator?: boolean }): string`** — Capitalizes each word; can treat hyphen as separator.
328
+
329
+ ```javascript
330
+ capitalizeWords("e-mail marketing");
331
+ // Result: "E-mail Marketing"
332
+
333
+ capitalizeWords("e-mail marketing", { treatHyphenAsSeparator: true });
334
+ // Result: "E-Mail Marketing"
335
+ ```
336
+
337
+ **`sentenceCase(input: string, options?: { lowerRest?: boolean; locale?: string | string[] }): string`** — Capitalizes the start of each sentence (. ! ?); optionally lowercases the rest.
338
+
339
+ ```javascript
340
+ sentenceCase("hello world. this is fine!");
341
+ // Result: "Hello world. This is fine!"
342
+ ```
343
+
320
344
  **`sanitize(input: unknown, maxLength?: number): string`** — Sanitizes input by removing dangerous content.
321
345
 
322
346
  ```javascript
@@ -871,5 +895,5 @@ MIT © [SalesPark](https://salespark.io)
871
895
 
872
896
  ---
873
897
 
874
- _Document version: 10_
875
- _Last update: 11-12-2025_
898
+ _Document version: 11_
899
+ _Last update: 19-12-2025_
package/dist/index.cjs CHANGED
@@ -211,6 +211,12 @@ function cleanObject(obj, removeEmptyString = false) {
211
211
  }
212
212
 
213
213
  // src/utils/string.ts
214
+ function upper(value, locale) {
215
+ return locale ? value.toLocaleUpperCase(locale) : value.toUpperCase();
216
+ }
217
+ function lower(value, locale) {
218
+ return locale ? value.toLocaleLowerCase(locale) : value.toLowerCase();
219
+ }
214
220
  function slugify(input) {
215
221
  return input.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
216
222
  }
@@ -224,6 +230,38 @@ function deburr(str) {
224
230
  return str;
225
231
  }
226
232
  }
233
+ function capitalizeFirst(input, options) {
234
+ if (typeof input !== "string" || input.length === 0) return "";
235
+ const { lowerRest = true, locale } = options ?? {};
236
+ const first = upper(input[0], locale);
237
+ const rest = lowerRest ? lower(input.slice(1), locale) : input.slice(1);
238
+ return first + rest;
239
+ }
240
+ function capitalizeWords(input, options) {
241
+ if (typeof input !== "string" || input.length === 0) return "";
242
+ const {
243
+ lowerRest = true,
244
+ locale,
245
+ treatHyphenAsSeparator = false
246
+ } = options ?? {};
247
+ const wordPattern = treatHyphenAsSeparator ? /[\p{L}\p{N}]+(?:['’][\p{L}\p{N}]+)*/gu : /[\p{L}\p{N}]+(?:['’\-][\p{L}\p{N}]+)*/gu;
248
+ return input.replace(wordPattern, (word) => {
249
+ const first = upper(word[0], locale);
250
+ const rest = lowerRest ? lower(word.slice(1), locale) : word.slice(1);
251
+ return first + rest;
252
+ });
253
+ }
254
+ function sentenceCase(input, options) {
255
+ if (typeof input !== "string" || input.length === 0) return "";
256
+ const { lowerRest = true, locale } = options ?? {};
257
+ const base = lowerRest ? lower(input, locale) : input;
258
+ const sentencePattern = /(^\s*[\p{L}])|([.!?]\s*[\p{L}])/gu;
259
+ return base.replace(sentencePattern, (match) => {
260
+ const lastChar = match[match.length - 1];
261
+ const upperChar = upper(lastChar, locale);
262
+ return match.slice(0, -1) + upperChar;
263
+ });
264
+ }
227
265
  var removeDiacritics = deburr;
228
266
  function sanitize(input, maxLength) {
229
267
  if (typeof input !== "string") return "";
@@ -1702,6 +1740,8 @@ exports.areArraysDeepEqualUnordered = areArraysDeepEqualUnordered;
1702
1740
  exports.areArraysEqual = areArraysEqual;
1703
1741
  exports.assessSecurityRisks = assessSecurityRisks;
1704
1742
  exports.basicSanitize = basicSanitize;
1743
+ exports.capitalizeFirst = capitalizeFirst;
1744
+ exports.capitalizeWords = capitalizeWords;
1705
1745
  exports.checkMarkdownSecurity = checkMarkdownSecurity;
1706
1746
  exports.chunk = chunk;
1707
1747
  exports.clamp = clamp;
@@ -1769,6 +1809,7 @@ exports.safeParseInt = safeParseInt;
1769
1809
  exports.safeSubtract = safeSubtract;
1770
1810
  exports.sanitize = sanitize;
1771
1811
  exports.sanitizeMarkdown = sanitizeMarkdown;
1812
+ exports.sentenceCase = sentenceCase;
1772
1813
  exports.shuffle = shuffle;
1773
1814
  exports.slugify = slugify;
1774
1815
  exports.sortBy = sortBy;