@stacksjs/strings 0.70.88 → 0.70.90

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/case.d.ts ADDED
@@ -0,0 +1,91 @@
1
+ /**
2
+ * First letter uppercase, other lowercase
3
+ * @category string
4
+ * @example
5
+ * ```
6
+ * capitalize('hello world') => 'Hello world'
7
+ * ```
8
+ */
9
+ export declare function capitalize(str: string): string;
10
+ export declare function lowercase(str: string): string;
11
+ /**
12
+ * Split any cased input strings into an array of words.
13
+ */
14
+ export declare function split(value: string): string[];
15
+ /**
16
+ * Split the input string into an array of words, separating numbers.
17
+ */
18
+ export declare function splitSeparateNumbers(value: string): string[];
19
+ /**
20
+ * Convert a string to space separated lower case (`foo bar`).
21
+ */
22
+ export declare function noCase(input: string, options?: CaseOptions): string;
23
+ /**
24
+ * Convert a string to camel case (`fooBar`).
25
+ */
26
+ export declare function camelCase(input: string, options?: PascalCaseOptions): string;
27
+ /**
28
+ * Convert a string to pascal case (`FooBar`).
29
+ */
30
+ export declare function pascalCase(input: string, options?: PascalCaseOptions): string;
31
+ /**
32
+ * Convert a string to pascal snake case (`Foo_Bar`).
33
+ */
34
+ export declare function pascalSnakeCase(input: string, options?: CaseOptions): string;
35
+ /**
36
+ * Convert a string to capital case (`Foo Bar`).
37
+ */
38
+ export declare function capitalCase(input: string, options?: CaseOptions): string;
39
+ /**
40
+ * Convert a string to constant case (`FOO_BAR`).
41
+ */
42
+ export declare function constantCase(input: string, options?: CaseOptions): string;
43
+ /**
44
+ * Convert a string to dot case (`foo.bar`).
45
+ */
46
+ export declare function dotCase(input: string, options?: CaseOptions): string;
47
+ /**
48
+ * Convert a string to kebab case (`foo-bar`).
49
+ */
50
+ export declare function kebabCase(input: string, options?: CaseOptions): string;
51
+ /**
52
+ * Convert a string to path case (`foo/bar`).
53
+ */
54
+ export declare function pathCase(input: string, options?: CaseOptions): string;
55
+ /**
56
+ * Convert a string to path case (`Foo bar`).
57
+ */
58
+ export declare function sentenceCase(input: string, options?: CaseOptions): string;
59
+ /**
60
+ * Convert a string to snake case (`foo_bar`).
61
+ */
62
+ export declare function snakeCase(input: string, options?: CaseOptions): string;
63
+ /**
64
+ * Convert a string to header case (`Foo-Bar`).
65
+ */
66
+ export declare function trainCase(input: string, options?: CaseOptions): string;
67
+ export declare function paramCase(input: string, options?: CaseOptions): string;
68
+ /**
69
+ * Options used for converting strings to pascal/camel case.
70
+ */
71
+ export declare interface PascalCaseOptions extends CaseOptions {
72
+ mergeAmbiguousCharacters?: boolean
73
+ }
74
+ /**
75
+ * Options used for converting strings to any case.
76
+ */
77
+ export declare interface CaseOptions {
78
+ locale?: Locale
79
+ split?: (value: string) => string[]
80
+ delimiter?: string
81
+ prefixCharacters?: string
82
+ suffixCharacters?: string
83
+ }
84
+ /**
85
+ * Supported locale values. Use `false` to ignore locale.
86
+ * Defaults to `undefined`, which uses the host environment.
87
+ */
88
+ export type Locale = string[] | string | false | undefined;
89
+ export * from './sponge-case';
90
+ export * from './swap-case';
91
+ export * from './title-case';
package/dist/case.js ADDED
@@ -0,0 +1,133 @@
1
+ export function capitalize(str) {
2
+ return str[0] ? str[0].toUpperCase() + str.slice(1).toLowerCase() : "";
3
+ }
4
+ export function lowercase(str) {
5
+ return str.toLowerCase();
6
+ }
7
+ const SPLIT_LOWER_UPPER_RE = /([\p{Ll}\d])(\p{Lu})/gu, SPLIT_UPPER_UPPER_RE = /(\p{Lu})(\p{Lu}\p{Ll})/gu, SPLIT_SEPARATE_NUMBER_RE = /(\d)\p{Ll}|(\p{L})\d/u, DEFAULT_STRIP_REGEXP = /[^\p{L}\d]+/giu, SPLIT_REPLACE_VALUE = "$1\x00$2", DEFAULT_PREFIX_SUFFIX_CHARACTERS = "";
8
+ export function split(value) {
9
+ let result = value.trim();
10
+ result = result.replace(SPLIT_LOWER_UPPER_RE, SPLIT_REPLACE_VALUE).replace(SPLIT_UPPER_UPPER_RE, SPLIT_REPLACE_VALUE);
11
+ result = result.replace(DEFAULT_STRIP_REGEXP, "\x00");
12
+ let start = 0, end = result.length;
13
+ while (result.charAt(start) === "\x00")
14
+ start++;
15
+ if (start === end)
16
+ return [];
17
+ while (result.charAt(end - 1) === "\x00")
18
+ end--;
19
+ return result.slice(start, end).split(/\0/g);
20
+ }
21
+ export function splitSeparateNumbers(value) {
22
+ const words = split(value);
23
+ for (let i = 0;i < words.length; i++) {
24
+ const word = words[i];
25
+ if (word === void 0)
26
+ continue;
27
+ const match = SPLIT_SEPARATE_NUMBER_RE.exec(word);
28
+ if (match) {
29
+ const offset = match.index + (match[1] ?? match[2] ?? "").length;
30
+ words.splice(i, 1, word.slice(0, offset), word.slice(offset));
31
+ }
32
+ }
33
+ return words;
34
+ }
35
+ export function noCase(input, options) {
36
+ const [prefix, words, suffix] = splitPrefixSuffix(input, options);
37
+ return prefix + words.map(lowerFactory(options?.locale)).join(options?.delimiter ?? " ") + suffix;
38
+ }
39
+ export function camelCase(input, options) {
40
+ const [prefix, words, suffix] = splitPrefixSuffix(input, options), lower = lowerFactory(options?.locale), upper = upperFactory(options?.locale), transform = options?.mergeAmbiguousCharacters ? capitalCaseTransformFactory(lower, upper) : pascalCaseTransformFactory(lower, upper);
41
+ return prefix + words.map((word, index) => {
42
+ if (index === 0)
43
+ return lower(word);
44
+ return transform(word, index);
45
+ }).join(options?.delimiter ?? "") + suffix;
46
+ }
47
+ export function pascalCase(input, options) {
48
+ const [prefix, words, suffix] = splitPrefixSuffix(input, options), lower = lowerFactory(options?.locale), upper = upperFactory(options?.locale), transform = options?.mergeAmbiguousCharacters ? capitalCaseTransformFactory(lower, upper) : pascalCaseTransformFactory(lower, upper);
49
+ return prefix + words.map(transform).join(options?.delimiter ?? "") + suffix;
50
+ }
51
+ export function pascalSnakeCase(input, options) {
52
+ return capitalCase(input, { delimiter: "_", ...options });
53
+ }
54
+ export function capitalCase(input, options) {
55
+ const [prefix, words, suffix] = splitPrefixSuffix(input, options), lower = lowerFactory(options?.locale), upper = upperFactory(options?.locale);
56
+ return prefix + words.map(capitalCaseTransformFactory(lower, upper)).join(options?.delimiter ?? " ") + suffix;
57
+ }
58
+ export function constantCase(input, options) {
59
+ const [prefix, words, suffix] = splitPrefixSuffix(input, options);
60
+ return prefix + words.map(upperFactory(options?.locale)).join(options?.delimiter ?? "_") + suffix;
61
+ }
62
+ export function dotCase(input, options) {
63
+ return noCase(input, { delimiter: ".", ...options });
64
+ }
65
+ export function kebabCase(input, options) {
66
+ return noCase(input, { delimiter: "-", ...options });
67
+ }
68
+ export function pathCase(input, options) {
69
+ return noCase(input, { delimiter: "/", ...options });
70
+ }
71
+ export function sentenceCase(input, options) {
72
+ const [prefix, words, suffix] = splitPrefixSuffix(input, options), lower = lowerFactory(options?.locale), upper = upperFactory(options?.locale), transform = capitalCaseTransformFactory(lower, upper);
73
+ return prefix + words.map((word, index) => {
74
+ if (index === 0)
75
+ return transform(word);
76
+ return lower(word);
77
+ }).join(options?.delimiter ?? " ") + suffix;
78
+ }
79
+ export function snakeCase(input, options) {
80
+ return noCase(input, { delimiter: "_", ...options });
81
+ }
82
+ export function trainCase(input, options) {
83
+ return capitalCase(input, { delimiter: "-", ...options });
84
+ }
85
+ export function paramCase(input, options) {
86
+ return kebabCase(input, options);
87
+ }
88
+ function lowerFactory(locale) {
89
+ return locale === !1 ? (input) => input.toLowerCase() : (input) => input.toLocaleLowerCase(locale);
90
+ }
91
+ function upperFactory(locale) {
92
+ return locale === !1 ? (input) => input.toUpperCase() : (input) => input.toLocaleUpperCase(locale);
93
+ }
94
+ function capitalCaseTransformFactory(lower, upper) {
95
+ return (word) => {
96
+ if (!word)
97
+ return word;
98
+ return `${upper(word[0] ?? "")}${lower(word.slice(1))}`;
99
+ };
100
+ }
101
+ function pascalCaseTransformFactory(lower, upper) {
102
+ return (word, index) => {
103
+ if (!word)
104
+ return word;
105
+ const char0 = word[0] ?? "";
106
+ return (index > 0 && char0 >= "0" && char0 <= "9" ? `_${char0}` : upper(char0)) + lower(word.slice(1));
107
+ };
108
+ }
109
+ function splitPrefixSuffix(input, options = {}) {
110
+ const splitFn = options.split ?? split, prefixCharacters = options.prefixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS, suffixCharacters = options.suffixCharacters ?? DEFAULT_PREFIX_SUFFIX_CHARACTERS;
111
+ let prefixIndex = 0, suffixIndex = input.length;
112
+ while (prefixIndex < input.length) {
113
+ const char = input.charAt(prefixIndex);
114
+ if (!prefixCharacters.includes(char))
115
+ break;
116
+ prefixIndex++;
117
+ }
118
+ while (suffixIndex > prefixIndex) {
119
+ const index = suffixIndex - 1, char = input.charAt(index);
120
+ if (!suffixCharacters.includes(char))
121
+ break;
122
+ suffixIndex = index;
123
+ }
124
+ return [
125
+ input.slice(0, prefixIndex),
126
+ splitFn(input.slice(prefixIndex, suffixIndex)),
127
+ input.slice(suffixIndex)
128
+ ];
129
+ }
130
+
131
+ export * from "./sponge-case";
132
+ export * from "./swap-case";
133
+ export * from "./title-case";
@@ -0,0 +1,2 @@
1
+ export declare function detectIndent(string: string): { amount: number, type?: string, indent: string };
2
+ export default detectIndent;
@@ -0,0 +1,72 @@
1
+ const INDENT_REGEX = /^(?:( )+|\t+)/, INDENT_TYPE_SPACE = "space", INDENT_TYPE_TAB = "tab";
2
+ function makeIndentsMap(string, ignoreSingleSpaces = !0) {
3
+ const indents = new Map;
4
+ let previousSize = 0, previousIndentType, key = "";
5
+ for (const line of string.split(/\n/g)) {
6
+ if (!line)
7
+ continue;
8
+ let indent, indentType, use, weight, entry;
9
+ const matches = line.match(INDENT_REGEX);
10
+ if (matches === null) {
11
+ previousSize = 0;
12
+ previousIndentType = "";
13
+ } else {
14
+ indent = matches[0].length;
15
+ indentType = matches[1] ? INDENT_TYPE_SPACE : INDENT_TYPE_TAB;
16
+ if (ignoreSingleSpaces && indentType === INDENT_TYPE_SPACE && indent === 1)
17
+ continue;
18
+ if (indentType !== previousIndentType)
19
+ previousSize = 0;
20
+ previousIndentType = indentType;
21
+ use = 1;
22
+ weight = 0;
23
+ const indentDifference = indent - previousSize;
24
+ previousSize = indent;
25
+ if (indentDifference === 0) {
26
+ use = 0;
27
+ weight = 1;
28
+ } else {
29
+ const absoluteIndentDifference = indentDifference > 0 ? indentDifference : -indentDifference;
30
+ key = encodeIndentsKey(indentType, absoluteIndentDifference);
31
+ }
32
+ entry = indents.get(key);
33
+ entry = entry === void 0 ? [1, 0] : [entry[0] + use, entry[1] + weight];
34
+ indents.set(key, entry);
35
+ }
36
+ }
37
+ return indents;
38
+ }
39
+ function encodeIndentsKey(indentType, indentAmount) {
40
+ return (indentType === INDENT_TYPE_SPACE ? "s" : "t") + String(indentAmount);
41
+ }
42
+ function decodeIndentsKey(indentsKey) {
43
+ const type = indentsKey[0] === "s" ? INDENT_TYPE_SPACE : INDENT_TYPE_TAB, amount = Number(indentsKey.slice(1));
44
+ return { type, amount };
45
+ }
46
+ function getMostUsedKey(indents) {
47
+ let result, maxUsed = 0, maxWeight = 0;
48
+ for (const [key, [usedCount, weight]] of indents)
49
+ if (usedCount > maxUsed || usedCount === maxUsed && weight > maxWeight) {
50
+ maxUsed = usedCount;
51
+ maxWeight = weight;
52
+ result = key;
53
+ }
54
+ return result;
55
+ }
56
+ function makeIndentString(type, amount) {
57
+ return (type === INDENT_TYPE_SPACE ? " " : "\t").repeat(amount);
58
+ }
59
+ export function detectIndent(string) {
60
+ if (typeof string !== "string")
61
+ throw TypeError("Expected a string");
62
+ let indents = makeIndentsMap(string, !0);
63
+ if (indents.size === 0)
64
+ indents = makeIndentsMap(string, !1);
65
+ const keyOfMostUsedIndent = getMostUsedKey(indents), decoded = keyOfMostUsedIndent !== void 0 ? decodeIndentsKey(keyOfMostUsedIndent) : void 0, type = decoded?.type, amount = decoded?.amount ?? 0, indent = decoded ? makeIndentString(type, amount) : "";
66
+ return {
67
+ amount,
68
+ type,
69
+ indent
70
+ };
71
+ }
72
+ export default detectIndent;
@@ -0,0 +1,2 @@
1
+ export declare function detectNewline(string: string): string | undefined;
2
+ export declare function detectNewlineGraceful(string: string): string;
@@ -0,0 +1,16 @@
1
+ export function detectNewline(string) {
2
+ if (typeof string !== "string")
3
+ throw TypeError("Expected a string");
4
+ const newlines = string.match(/\r?\n/g) || [];
5
+ if (newlines.length === 0)
6
+ return;
7
+ const crlf = newlines.filter((newline) => newline === `\r
8
+ `).length, lf = newlines.length - crlf;
9
+ return crlf > lf ? `\r
10
+ ` : `
11
+ `;
12
+ }
13
+ export function detectNewlineGraceful(string) {
14
+ return typeof string === "string" && detectNewline(string) || `
15
+ `;
16
+ }
@@ -0,0 +1,23 @@
1
+ export declare function toString(v: any): string;
2
+ /**
3
+ * Mask a portion of a string with a repeated character, Laravel-style
4
+ * (stacksjs/stacks#314).
5
+ *
6
+ * Useful for redacting PII in logs (credit card middle, phone digits,
7
+ * email local part) without losing the format. The mask character is
8
+ * repeated for `length` characters starting at `index`; `length` defaults
9
+ * to "all remaining characters from index to end of string."
10
+ *
11
+ * `index` is the character offset, not a byte offset. Negative `index`
12
+ * counts from the end of the string (`-4` = "start four characters from
13
+ * the end"). An out-of-range `index` returns the original string.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * mask('1234567890123456', '*', 4, 8) // → '1234********3456'
18
+ * mask('1234567890123456', '*', 4) // → '1234************'
19
+ * mask('1234567890123456', '*', -4, 4) // → '123456789012****'
20
+ * mask('hello@example.com', '*', 1, 4) // → 'h****@example.com'
21
+ * ```
22
+ */
23
+ export declare function mask(value: string, character: string, index: number, length?: number): string;
@@ -0,0 +1,15 @@
1
+ export function toString(v) {
2
+ return Object.prototype.toString.call(v);
3
+ }
4
+ export function mask(value, character, index, length) {
5
+ if (character === "")
6
+ return value;
7
+ const len = value.length, start = index < 0 ? Math.max(0, len + index) : index;
8
+ if (start >= len)
9
+ return value;
10
+ const maskLen = length === void 0 ? len - start : Math.max(0, length);
11
+ if (maskLen === 0)
12
+ return value;
13
+ const end = Math.min(len, start + maskLen), fill = character.charAt(0).repeat(end - start);
14
+ return value.slice(0, start) + fill + value.slice(end);
15
+ }
@@ -0,0 +1,2 @@
1
+ export * from './string';
2
+ export * as string from './string';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./string";
2
+ export * as string from "./string";
package/dist/is.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * String validation utilities
3
+ * Re-exports from native validators
4
+ */
5
+ export * from './validators';
package/dist/is.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./validators";
@@ -0,0 +1,40 @@
1
+ export declare const Str: {
2
+ slash: (str: string) => string;
3
+ ensurePrefix: (prefix: string, str: string) => string;
4
+ ensureSuffix: (suffix: string, str: string) => string;
5
+ template: (str: string, ...args: any[]) => string;
6
+ /**
7
+ * Truncate a string
8
+ */
9
+ truncate: (str: string, length: number, end?: string) => string;
10
+ random: (length?: number, dict?: string) => string;
11
+ capitalize: (str: string) => string;
12
+ slug: (str: string) => string;
13
+ detectIndent: (str: string) => {
14
+ amount: number
15
+ indent: string
16
+ type?: string | undefined
17
+ };
18
+ detectNewline: (str: string) => string | undefined;
19
+ camelCase: (str: string) => string;
20
+ capitalCase: (str: string) => string;
21
+ constantCase: (str: string) => string;
22
+ dotCase: (str: string) => string;
23
+ noCase: (str: string) => string;
24
+ paramCase: (str: string) => string;
25
+ pascalCase: (str: string) => string;
26
+ pathCase: (str: string) => string;
27
+ sentenceCase: (str: string) => string;
28
+ snakeCase: (str: string) => string;
29
+ titleCase: (str: string) => string;
30
+ kebabCase: (str: string) => string;
31
+ plural: (str: string) => string;
32
+ singular: (str: string) => string;
33
+ isPlural: (str: string) => boolean;
34
+ isSingular: (str: string) => boolean;
35
+ addPluralRule: (rule: string | RegExp, repl: string) => void;
36
+ addSingularRule: (rule: string | RegExp, repl: string) => void;
37
+ addIrregularRule: (single: string, plural: string) => void;
38
+ addUncountableRule: (word: string | RegExp) => void
39
+ };
40
+ export declare const str: typeof Str;
package/dist/macro.js ADDED
@@ -0,0 +1,95 @@
1
+ import * as c from "./case";
2
+ import p from "./pluralize";
3
+ import * as u from "./utils";
4
+ export const Str = {
5
+ slash(str) {
6
+ return u.slash(str);
7
+ },
8
+ ensurePrefix(prefix, str) {
9
+ return u.ensurePrefix(prefix, str);
10
+ },
11
+ ensureSuffix(suffix, str) {
12
+ return u.ensureSuffix(suffix, str);
13
+ },
14
+ template(str, ...args) {
15
+ return u.template(str, ...args);
16
+ },
17
+ truncate(str, length, end = "...") {
18
+ return u.truncate(str, length, end);
19
+ },
20
+ random(length = 16, dict) {
21
+ return u.random(length, dict);
22
+ },
23
+ capitalize(str) {
24
+ return c.capitalize(str);
25
+ },
26
+ slug(str) {
27
+ return u.slug(str);
28
+ },
29
+ detectIndent(str) {
30
+ return u.detectIndent(str);
31
+ },
32
+ detectNewline(str) {
33
+ return u.detectNewline(str);
34
+ },
35
+ camelCase(str) {
36
+ return c.camelCase(str);
37
+ },
38
+ capitalCase(str) {
39
+ return c.capitalCase(str);
40
+ },
41
+ constantCase(str) {
42
+ return c.constantCase(str);
43
+ },
44
+ dotCase(str) {
45
+ return c.dotCase(str);
46
+ },
47
+ noCase(str) {
48
+ return c.noCase(str);
49
+ },
50
+ paramCase(str) {
51
+ return c.paramCase(str);
52
+ },
53
+ pascalCase(str) {
54
+ return c.pascalCase(str);
55
+ },
56
+ pathCase(str) {
57
+ return c.pathCase(str);
58
+ },
59
+ sentenceCase(str) {
60
+ return c.sentenceCase(str);
61
+ },
62
+ snakeCase(str) {
63
+ return c.snakeCase(str);
64
+ },
65
+ titleCase(str) {
66
+ return c.titleCase(str);
67
+ },
68
+ kebabCase(str) {
69
+ return c.kebabCase(str);
70
+ },
71
+ plural(str) {
72
+ return p.plural(str);
73
+ },
74
+ singular(str) {
75
+ return p.singular(str);
76
+ },
77
+ isPlural(str) {
78
+ return p.isPlural(str);
79
+ },
80
+ isSingular(str) {
81
+ return p.isSingular(str);
82
+ },
83
+ addPluralRule(rule, repl) {
84
+ p.addPluralRule(rule, repl);
85
+ },
86
+ addSingularRule(rule, repl) {
87
+ p.addSingularRule(rule, repl);
88
+ },
89
+ addIrregularRule(single, plural) {
90
+ p.addIrregularRule(single, plural);
91
+ },
92
+ addUncountableRule(word) {
93
+ p.addUncountableRule(word);
94
+ }
95
+ }, str = Str;
@@ -0,0 +1,20 @@
1
+ export declare const pluralize: PluralizeFunction;
2
+ export declare const singular: PluralizeFunction;
3
+ export declare const plural: PluralizeFunction;
4
+ export declare interface PluralizeOptions {
5
+ count?: number
6
+ inclusive?: boolean
7
+ }
8
+ declare interface PluralizeFunction {
9
+ (word: string, options?: PluralizeOptions): string
10
+ plural: (word: string) => string
11
+ isPlural: (word: string) => boolean
12
+ singular: (word: string) => string
13
+ isSingular: (word: string) => boolean
14
+ addPluralRule: (rule: StringOrRegExp, replacement: string) => void
15
+ addSingularRule: (rule: StringOrRegExp, replacement: string) => void
16
+ addUncountableRule: (word: string | RegExp) => void
17
+ addIrregularRule: (single: string, plural: string) => void
18
+ }
19
+ declare type Rule = [RegExp, string];
20
+ declare type StringOrRegExp = string | RegExp;