@ibiliaze/stringman 3.0.0 → 3.2.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.d.ts +123 -1
- package/dist/index.js +161 -3
- package/package.json +2 -2
- package/src/index.ts +171 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean up extra whitespace in a string.
|
|
3
|
+
*
|
|
4
|
+
* - Collapses multiple consecutive whitespace characters (spaces, tabs, newlines)
|
|
5
|
+
* into a single space.
|
|
6
|
+
* - Trims leading and trailing whitespace.
|
|
7
|
+
*
|
|
8
|
+
* @param stringData - The input string to clean
|
|
9
|
+
* @returns The cleaned string with normalized spacing
|
|
10
|
+
*
|
|
11
|
+
* Example:
|
|
12
|
+
* superTrim(" Hello World ");
|
|
13
|
+
* // → "Hello World"
|
|
14
|
+
*
|
|
15
|
+
* superTrim("Line1\n\nLine2");
|
|
16
|
+
* // → "Line1 Line2"
|
|
17
|
+
*/
|
|
1
18
|
export declare const superTrim: (stringData: string) => string;
|
|
19
|
+
/**
|
|
20
|
+
* Remove extra whitespace from a string.
|
|
21
|
+
*
|
|
22
|
+
* - Collapses multiple consecutive whitespace characters into a single empty string (removes them completely).
|
|
23
|
+
* - Useful for cleaning up text where multiple spaces, tabs, or line breaks appear.
|
|
24
|
+
*
|
|
25
|
+
* @param stringData - The input string to clean
|
|
26
|
+
* @returns The string with extra whitespace removed
|
|
27
|
+
*
|
|
28
|
+
* Example:
|
|
29
|
+
* megaTrim("Hello World"); // → "HelloWorld"
|
|
30
|
+
* megaTrim("Line1\n\n\nLine2"); // → "Line1Line2"
|
|
31
|
+
*/
|
|
2
32
|
export declare const megaTrim: (stringData: string) => string;
|
|
33
|
+
/**
|
|
34
|
+
* Format a number to a fixed number of decimal places.
|
|
35
|
+
*
|
|
36
|
+
* - If the input is a valid number, it rounds it to the specified number of decimals.
|
|
37
|
+
* - If the input is not a number, it returns 0.
|
|
38
|
+
*
|
|
39
|
+
* @param int - The input number to format
|
|
40
|
+
* @param i - The number of decimal places to keep
|
|
41
|
+
* @returns The formatted number with the given decimal places
|
|
42
|
+
*
|
|
43
|
+
* Example:
|
|
44
|
+
* dp(12.3456, 2); // → 12.35
|
|
45
|
+
* dp(99.999, 0); // → 100
|
|
46
|
+
* dp(NaN as any, 2); // → 0
|
|
47
|
+
*/
|
|
3
48
|
export declare const dp: (int: number, i: number) => number;
|
|
49
|
+
/**
|
|
50
|
+
* Extract the Cloudinary public ID from a given Cloudinary image URL.
|
|
51
|
+
*
|
|
52
|
+
* A Cloudinary URL typically looks like:
|
|
53
|
+
* https://res.cloudinary.com/<cloud_name>/image/upload/v<version>/<folder>/<fileName>.<ext>
|
|
54
|
+
*
|
|
55
|
+
* This function:
|
|
56
|
+
* 1. Removes the Cloudinary prefix (protocol, domain, resource type, and version).
|
|
57
|
+
* 2. Strips the file extension (e.g. ".jpg").
|
|
58
|
+
* 3. Decodes any URL-encoded characters (e.g. "%20" → " ").
|
|
59
|
+
*
|
|
60
|
+
* @param url - The full Cloudinary image URL
|
|
61
|
+
* @returns The extracted public ID (without extension), or an empty string on failure
|
|
62
|
+
*
|
|
63
|
+
* Example:
|
|
64
|
+
* getCloudinaryPublicId("https://res.cloudinary.com/demo/image/upload/v12345/folder/my%20image.jpg")
|
|
65
|
+
* // → "folder/my image"
|
|
66
|
+
*/
|
|
4
67
|
export declare const getCloudinaryPublicId: (url: string) => string;
|
|
68
|
+
/**
|
|
69
|
+
* Build a query string from a key-value object.
|
|
70
|
+
*
|
|
71
|
+
* - Filters out keys/values that are empty or invalid (e.g. "", null, undefined, "null", "undefined").
|
|
72
|
+
* - Returns a string starting with "?" if there are valid params, otherwise returns an empty string.
|
|
73
|
+
*
|
|
74
|
+
* @param q - An object of query parameters
|
|
75
|
+
* @returns A properly formatted query string
|
|
76
|
+
*
|
|
77
|
+
* Example:
|
|
78
|
+
* query({ limit: 10, skip: 20, sortBy: 'createdAt:desc', empty: '' });
|
|
79
|
+
* // → "?limit=10&skip=20&sortBy=createdAt%3Adesc"
|
|
80
|
+
*/
|
|
5
81
|
export declare const query: (q: Record<string, any>) => string;
|
|
82
|
+
/**
|
|
83
|
+
* Build a comma-separated string from a list of object keys.
|
|
84
|
+
*
|
|
85
|
+
* Useful when you need to select specific fields (e.g., for APIs, databases, or queries).
|
|
86
|
+
*
|
|
87
|
+
* @typeParam T - The type of the object whose keys are being selected
|
|
88
|
+
* @param keys - An array of keys from the object type T
|
|
89
|
+
* @returns A comma-separated string of the given keys
|
|
90
|
+
*
|
|
91
|
+
* Example:
|
|
92
|
+
* type User = { id: string; name: string; email: string };
|
|
93
|
+
* select<User>(['id', 'email']); // → "id,email"
|
|
94
|
+
*/
|
|
6
95
|
export declare const select: <T>(keys: (keyof T)[]) => string;
|
|
7
|
-
|
|
96
|
+
/**
|
|
97
|
+
* Extract all image `src` attribute values from an HTML string.
|
|
98
|
+
*
|
|
99
|
+
* Uses a regex to find <img> tags and capture the value of the `src` attribute.
|
|
100
|
+
*
|
|
101
|
+
* @param htmlString - The HTML string to search for image tags
|
|
102
|
+
* @returns An array of image source URLs
|
|
103
|
+
*
|
|
104
|
+
* Example:
|
|
105
|
+
* extractImageSrcs('<img src="a.png"><div><img src="b.jpg"></div>');
|
|
106
|
+
* // → ["a.png", "b.jpg"]
|
|
107
|
+
*/
|
|
108
|
+
export declare const extractImageSrcs: (htmlString: string) => string[];
|
|
109
|
+
/**
|
|
110
|
+
* Generate a random alphanumeric string (uppercase letters + digits).
|
|
111
|
+
*
|
|
112
|
+
* @param length - The desired length of the generated string
|
|
113
|
+
* @returns A randomly generated string of the given length
|
|
114
|
+
*
|
|
115
|
+
* Example:
|
|
116
|
+
* getRandomString(6) → "A9X2KQ"
|
|
117
|
+
*/
|
|
118
|
+
export declare const getRandomString: (length: number) => string;
|
|
119
|
+
/**
|
|
120
|
+
* Check if a given URL points to a video file.
|
|
121
|
+
*
|
|
122
|
+
* Rules:
|
|
123
|
+
* 1. If the URL contains Cloudinary's `video/upload` path → treat as video.
|
|
124
|
+
* 2. Otherwise, check common video file extensions (mp4, webm, mov, avi, mkv).
|
|
125
|
+
*
|
|
126
|
+
* @param url - The URL string to check
|
|
127
|
+
* @returns true if the URL is a video, false otherwise
|
|
128
|
+
*/
|
|
129
|
+
export declare const isVideoUrl: (url: string) => boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,29 +1,111 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractImageSrcs = exports.select = exports.query = exports.getCloudinaryPublicId = exports.dp = exports.megaTrim = exports.superTrim = void 0;
|
|
3
|
+
exports.isVideoUrl = exports.getRandomString = exports.extractImageSrcs = exports.select = exports.query = exports.getCloudinaryPublicId = exports.dp = exports.megaTrim = exports.superTrim = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Clean up extra whitespace in a string.
|
|
6
|
+
*
|
|
7
|
+
* - Collapses multiple consecutive whitespace characters (spaces, tabs, newlines)
|
|
8
|
+
* into a single space.
|
|
9
|
+
* - Trims leading and trailing whitespace.
|
|
10
|
+
*
|
|
11
|
+
* @param stringData - The input string to clean
|
|
12
|
+
* @returns The cleaned string with normalized spacing
|
|
13
|
+
*
|
|
14
|
+
* Example:
|
|
15
|
+
* superTrim(" Hello World ");
|
|
16
|
+
* // → "Hello World"
|
|
17
|
+
*
|
|
18
|
+
* superTrim("Line1\n\nLine2");
|
|
19
|
+
* // → "Line1 Line2"
|
|
20
|
+
*/
|
|
4
21
|
const superTrim = (stringData) => stringData.replace(/\s\s+/g, ' ').trim();
|
|
5
22
|
exports.superTrim = superTrim;
|
|
23
|
+
/**
|
|
24
|
+
* Remove extra whitespace from a string.
|
|
25
|
+
*
|
|
26
|
+
* - Collapses multiple consecutive whitespace characters into a single empty string (removes them completely).
|
|
27
|
+
* - Useful for cleaning up text where multiple spaces, tabs, or line breaks appear.
|
|
28
|
+
*
|
|
29
|
+
* @param stringData - The input string to clean
|
|
30
|
+
* @returns The string with extra whitespace removed
|
|
31
|
+
*
|
|
32
|
+
* Example:
|
|
33
|
+
* megaTrim("Hello World"); // → "HelloWorld"
|
|
34
|
+
* megaTrim("Line1\n\n\nLine2"); // → "Line1Line2"
|
|
35
|
+
*/
|
|
6
36
|
const megaTrim = (stringData) => stringData.replace(/\s\s+/g, '');
|
|
7
37
|
exports.megaTrim = megaTrim;
|
|
38
|
+
/**
|
|
39
|
+
* Format a number to a fixed number of decimal places.
|
|
40
|
+
*
|
|
41
|
+
* - If the input is a valid number, it rounds it to the specified number of decimals.
|
|
42
|
+
* - If the input is not a number, it returns 0.
|
|
43
|
+
*
|
|
44
|
+
* @param int - The input number to format
|
|
45
|
+
* @param i - The number of decimal places to keep
|
|
46
|
+
* @returns The formatted number with the given decimal places
|
|
47
|
+
*
|
|
48
|
+
* Example:
|
|
49
|
+
* dp(12.3456, 2); // → 12.35
|
|
50
|
+
* dp(99.999, 0); // → 100
|
|
51
|
+
* dp(NaN as any, 2); // → 0
|
|
52
|
+
*/
|
|
8
53
|
const dp = (int, i) => (typeof int === 'number' ? +int.toFixed(i) : 0);
|
|
9
54
|
exports.dp = dp;
|
|
55
|
+
/**
|
|
56
|
+
* Extract the Cloudinary public ID from a given Cloudinary image URL.
|
|
57
|
+
*
|
|
58
|
+
* A Cloudinary URL typically looks like:
|
|
59
|
+
* https://res.cloudinary.com/<cloud_name>/image/upload/v<version>/<folder>/<fileName>.<ext>
|
|
60
|
+
*
|
|
61
|
+
* This function:
|
|
62
|
+
* 1. Removes the Cloudinary prefix (protocol, domain, resource type, and version).
|
|
63
|
+
* 2. Strips the file extension (e.g. ".jpg").
|
|
64
|
+
* 3. Decodes any URL-encoded characters (e.g. "%20" → " ").
|
|
65
|
+
*
|
|
66
|
+
* @param url - The full Cloudinary image URL
|
|
67
|
+
* @returns The extracted public ID (without extension), or an empty string on failure
|
|
68
|
+
*
|
|
69
|
+
* Example:
|
|
70
|
+
* getCloudinaryPublicId("https://res.cloudinary.com/demo/image/upload/v12345/folder/my%20image.jpg")
|
|
71
|
+
* // → "folder/my image"
|
|
72
|
+
*/
|
|
10
73
|
const getCloudinaryPublicId = (url) => {
|
|
11
74
|
try {
|
|
75
|
+
// Remove Cloudinary domain + "image/upload/v{version}/"
|
|
12
76
|
const public_id_with_extension = url.replace(/^https?:\/\/res\.cloudinary\.com\/[^/]+\/image\/upload\/v\d+\//, '');
|
|
13
|
-
// Decode URL encoding (
|
|
77
|
+
// Decode URL encoding and strip extension (everything after the last ".")
|
|
14
78
|
const public_id = decodeURIComponent(public_id_with_extension.replace(/\.[^.]+$/, ''));
|
|
15
79
|
return public_id;
|
|
16
80
|
}
|
|
17
|
-
catch
|
|
81
|
+
catch {
|
|
82
|
+
// In case of invalid URL or regex failure
|
|
18
83
|
return '';
|
|
19
84
|
}
|
|
20
85
|
};
|
|
21
86
|
exports.getCloudinaryPublicId = getCloudinaryPublicId;
|
|
87
|
+
/**
|
|
88
|
+
* Build a query string from a key-value object.
|
|
89
|
+
*
|
|
90
|
+
* - Filters out keys/values that are empty or invalid (e.g. "", null, undefined, "null", "undefined").
|
|
91
|
+
* - Returns a string starting with "?" if there are valid params, otherwise returns an empty string.
|
|
92
|
+
*
|
|
93
|
+
* @param q - An object of query parameters
|
|
94
|
+
* @returns A properly formatted query string
|
|
95
|
+
*
|
|
96
|
+
* Example:
|
|
97
|
+
* query({ limit: 10, skip: 20, sortBy: 'createdAt:desc', empty: '' });
|
|
98
|
+
* // → "?limit=10&skip=20&sortBy=createdAt%3Adesc"
|
|
99
|
+
*/
|
|
22
100
|
const query = (q) => {
|
|
23
101
|
try {
|
|
102
|
+
// Values considered "invalid" and should be filtered out
|
|
24
103
|
const filter = ['', null, undefined, 'null', 'undefined'];
|
|
104
|
+
// Convert object to entries, filter out invalid keys/values
|
|
25
105
|
const filtered = Object.entries(q).filter(([key, value]) => !filter.includes(key) && !filter.includes(value));
|
|
106
|
+
// Build query string using URLSearchParams
|
|
26
107
|
const query = new URLSearchParams(filtered).toString();
|
|
108
|
+
// Prefix with "?" if there are any params
|
|
27
109
|
return query ? `?${query}` : '';
|
|
28
110
|
}
|
|
29
111
|
catch (e) {
|
|
@@ -32,12 +114,88 @@ const query = (q) => {
|
|
|
32
114
|
}
|
|
33
115
|
};
|
|
34
116
|
exports.query = query;
|
|
117
|
+
/**
|
|
118
|
+
* Build a comma-separated string from a list of object keys.
|
|
119
|
+
*
|
|
120
|
+
* Useful when you need to select specific fields (e.g., for APIs, databases, or queries).
|
|
121
|
+
*
|
|
122
|
+
* @typeParam T - The type of the object whose keys are being selected
|
|
123
|
+
* @param keys - An array of keys from the object type T
|
|
124
|
+
* @returns A comma-separated string of the given keys
|
|
125
|
+
*
|
|
126
|
+
* Example:
|
|
127
|
+
* type User = { id: string; name: string; email: string };
|
|
128
|
+
* select<User>(['id', 'email']); // → "id,email"
|
|
129
|
+
*/
|
|
35
130
|
const select = (keys) => {
|
|
131
|
+
// Join all keys into a single comma-separated string
|
|
36
132
|
return keys.join(',');
|
|
37
133
|
};
|
|
38
134
|
exports.select = select;
|
|
135
|
+
/**
|
|
136
|
+
* Extract all image `src` attribute values from an HTML string.
|
|
137
|
+
*
|
|
138
|
+
* Uses a regex to find <img> tags and capture the value of the `src` attribute.
|
|
139
|
+
*
|
|
140
|
+
* @param htmlString - The HTML string to search for image tags
|
|
141
|
+
* @returns An array of image source URLs
|
|
142
|
+
*
|
|
143
|
+
* Example:
|
|
144
|
+
* extractImageSrcs('<img src="a.png"><div><img src="b.jpg"></div>');
|
|
145
|
+
* // → ["a.png", "b.jpg"]
|
|
146
|
+
*/
|
|
39
147
|
const extractImageSrcs = (htmlString) => {
|
|
148
|
+
// Find all <img> tags with a src attribute
|
|
40
149
|
const imgTags = [...htmlString.matchAll(/<img\s+[^>]*src=["']([^"']+)["'][^>]*>/gi)];
|
|
150
|
+
// Map over regex matches and extract the first capture group (the src value)
|
|
41
151
|
return imgTags.map(match => match[1]);
|
|
42
152
|
};
|
|
43
153
|
exports.extractImageSrcs = extractImageSrcs;
|
|
154
|
+
/**
|
|
155
|
+
* Generate a random alphanumeric string (uppercase letters + digits).
|
|
156
|
+
*
|
|
157
|
+
* @param length - The desired length of the generated string
|
|
158
|
+
* @returns A randomly generated string of the given length
|
|
159
|
+
*
|
|
160
|
+
* Example:
|
|
161
|
+
* getRandomString(6) → "A9X2KQ"
|
|
162
|
+
*/
|
|
163
|
+
const getRandomString = (length) => {
|
|
164
|
+
// Allowed characters: A–Z and 0–9
|
|
165
|
+
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
166
|
+
let result = '';
|
|
167
|
+
// Loop for the requested length
|
|
168
|
+
for (let i = 0; i < length; i++) {
|
|
169
|
+
// Pick a random index and append the corresponding character
|
|
170
|
+
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
};
|
|
174
|
+
exports.getRandomString = getRandomString;
|
|
175
|
+
/**
|
|
176
|
+
* Check if a given URL points to a video file.
|
|
177
|
+
*
|
|
178
|
+
* Rules:
|
|
179
|
+
* 1. If the URL contains Cloudinary's `video/upload` path → treat as video.
|
|
180
|
+
* 2. Otherwise, check common video file extensions (mp4, webm, mov, avi, mkv).
|
|
181
|
+
*
|
|
182
|
+
* @param url - The URL string to check
|
|
183
|
+
* @returns true if the URL is a video, false otherwise
|
|
184
|
+
*/
|
|
185
|
+
const isVideoUrl = (url) => {
|
|
186
|
+
try {
|
|
187
|
+
const parsed = new URL(url);
|
|
188
|
+
// ✅ Rule 1: Cloudinary-specific pattern
|
|
189
|
+
if (parsed.pathname.includes('/video/upload/'))
|
|
190
|
+
return true;
|
|
191
|
+
// ✅ Rule 2: Check file extension
|
|
192
|
+
const videoExtensions = ['.mp4', '.webm', '.mov', '.avi', '.mkv'];
|
|
193
|
+
const lowerPath = parsed.pathname.toLowerCase();
|
|
194
|
+
return videoExtensions.some(ext => lowerPath.endsWith(ext));
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// ❌ If URL parsing fails, assume it's not a valid video URL
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
exports.isVideoUrl = isVideoUrl;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibiliaze/stringman",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"pub": "npm publish --access public",
|
|
10
|
-
"git": "git add .; git commit -m 'changes'; git tag -a v3.
|
|
10
|
+
"git": "git add .; git commit -m 'changes'; git tag -a v3.2.0 -m 'v3.2.0'; git push origin v3.2.0; git push",
|
|
11
11
|
"push": "npm run build; npm run git; npm run pub"
|
|
12
12
|
},
|
|
13
13
|
"author": "Ibi Hasanli",
|
package/src/index.ts
CHANGED
|
@@ -1,26 +1,112 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Clean up extra whitespace in a string.
|
|
3
|
+
*
|
|
4
|
+
* - Collapses multiple consecutive whitespace characters (spaces, tabs, newlines)
|
|
5
|
+
* into a single space.
|
|
6
|
+
* - Trims leading and trailing whitespace.
|
|
7
|
+
*
|
|
8
|
+
* @param stringData - The input string to clean
|
|
9
|
+
* @returns The cleaned string with normalized spacing
|
|
10
|
+
*
|
|
11
|
+
* Example:
|
|
12
|
+
* superTrim(" Hello World ");
|
|
13
|
+
* // → "Hello World"
|
|
14
|
+
*
|
|
15
|
+
* superTrim("Line1\n\nLine2");
|
|
16
|
+
* // → "Line1 Line2"
|
|
17
|
+
*/
|
|
18
|
+
export const superTrim = (stringData: string): string => stringData.replace(/\s\s+/g, ' ').trim();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Remove extra whitespace from a string.
|
|
22
|
+
*
|
|
23
|
+
* - Collapses multiple consecutive whitespace characters into a single empty string (removes them completely).
|
|
24
|
+
* - Useful for cleaning up text where multiple spaces, tabs, or line breaks appear.
|
|
25
|
+
*
|
|
26
|
+
* @param stringData - The input string to clean
|
|
27
|
+
* @returns The string with extra whitespace removed
|
|
28
|
+
*
|
|
29
|
+
* Example:
|
|
30
|
+
* megaTrim("Hello World"); // → "HelloWorld"
|
|
31
|
+
* megaTrim("Line1\n\n\nLine2"); // → "Line1Line2"
|
|
32
|
+
*/
|
|
33
|
+
export const megaTrim = (stringData: string): string => stringData.replace(/\s\s+/g, '');
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Format a number to a fixed number of decimal places.
|
|
37
|
+
*
|
|
38
|
+
* - If the input is a valid number, it rounds it to the specified number of decimals.
|
|
39
|
+
* - If the input is not a number, it returns 0.
|
|
40
|
+
*
|
|
41
|
+
* @param int - The input number to format
|
|
42
|
+
* @param i - The number of decimal places to keep
|
|
43
|
+
* @returns The formatted number with the given decimal places
|
|
44
|
+
*
|
|
45
|
+
* Example:
|
|
46
|
+
* dp(12.3456, 2); // → 12.35
|
|
47
|
+
* dp(99.999, 0); // → 100
|
|
48
|
+
* dp(NaN as any, 2); // → 0
|
|
49
|
+
*/
|
|
50
|
+
export const dp = (int: number, i: number): number => (typeof int === 'number' ? +int.toFixed(i) : 0);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Extract the Cloudinary public ID from a given Cloudinary image URL.
|
|
54
|
+
*
|
|
55
|
+
* A Cloudinary URL typically looks like:
|
|
56
|
+
* https://res.cloudinary.com/<cloud_name>/image/upload/v<version>/<folder>/<fileName>.<ext>
|
|
57
|
+
*
|
|
58
|
+
* This function:
|
|
59
|
+
* 1. Removes the Cloudinary prefix (protocol, domain, resource type, and version).
|
|
60
|
+
* 2. Strips the file extension (e.g. ".jpg").
|
|
61
|
+
* 3. Decodes any URL-encoded characters (e.g. "%20" → " ").
|
|
62
|
+
*
|
|
63
|
+
* @param url - The full Cloudinary image URL
|
|
64
|
+
* @returns The extracted public ID (without extension), or an empty string on failure
|
|
65
|
+
*
|
|
66
|
+
* Example:
|
|
67
|
+
* getCloudinaryPublicId("https://res.cloudinary.com/demo/image/upload/v12345/folder/my%20image.jpg")
|
|
68
|
+
* // → "folder/my image"
|
|
69
|
+
*/
|
|
4
70
|
export const getCloudinaryPublicId = (url: string): string => {
|
|
5
71
|
try {
|
|
72
|
+
// Remove Cloudinary domain + "image/upload/v{version}/"
|
|
6
73
|
const public_id_with_extension = url.replace(/^https?:\/\/res\.cloudinary\.com\/[^/]+\/image\/upload\/v\d+\//, '');
|
|
7
74
|
|
|
8
|
-
// Decode URL encoding (
|
|
75
|
+
// Decode URL encoding and strip extension (everything after the last ".")
|
|
9
76
|
const public_id = decodeURIComponent(public_id_with_extension.replace(/\.[^.]+$/, ''));
|
|
10
77
|
|
|
11
78
|
return public_id;
|
|
12
|
-
} catch
|
|
79
|
+
} catch {
|
|
80
|
+
// In case of invalid URL or regex failure
|
|
13
81
|
return '';
|
|
14
82
|
}
|
|
15
83
|
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Build a query string from a key-value object.
|
|
87
|
+
*
|
|
88
|
+
* - Filters out keys/values that are empty or invalid (e.g. "", null, undefined, "null", "undefined").
|
|
89
|
+
* - Returns a string starting with "?" if there are valid params, otherwise returns an empty string.
|
|
90
|
+
*
|
|
91
|
+
* @param q - An object of query parameters
|
|
92
|
+
* @returns A properly formatted query string
|
|
93
|
+
*
|
|
94
|
+
* Example:
|
|
95
|
+
* query({ limit: 10, skip: 20, sortBy: 'createdAt:desc', empty: '' });
|
|
96
|
+
* // → "?limit=10&skip=20&sortBy=createdAt%3Adesc"
|
|
97
|
+
*/
|
|
16
98
|
export const query = (q: Record<string, any>): string => {
|
|
17
99
|
try {
|
|
100
|
+
// Values considered "invalid" and should be filtered out
|
|
18
101
|
const filter = ['', null, undefined, 'null', 'undefined'];
|
|
19
102
|
|
|
103
|
+
// Convert object to entries, filter out invalid keys/values
|
|
20
104
|
const filtered = Object.entries(q).filter(([key, value]) => !filter.includes(key) && !filter.includes(value));
|
|
21
105
|
|
|
106
|
+
// Build query string using URLSearchParams
|
|
22
107
|
const query = new URLSearchParams(filtered as [string, string][]).toString();
|
|
23
108
|
|
|
109
|
+
// Prefix with "?" if there are any params
|
|
24
110
|
return query ? `?${query}` : '';
|
|
25
111
|
} catch (e) {
|
|
26
112
|
console.error(e);
|
|
@@ -28,11 +114,90 @@ export const query = (q: Record<string, any>): string => {
|
|
|
28
114
|
}
|
|
29
115
|
};
|
|
30
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Build a comma-separated string from a list of object keys.
|
|
119
|
+
*
|
|
120
|
+
* Useful when you need to select specific fields (e.g., for APIs, databases, or queries).
|
|
121
|
+
*
|
|
122
|
+
* @typeParam T - The type of the object whose keys are being selected
|
|
123
|
+
* @param keys - An array of keys from the object type T
|
|
124
|
+
* @returns A comma-separated string of the given keys
|
|
125
|
+
*
|
|
126
|
+
* Example:
|
|
127
|
+
* type User = { id: string; name: string; email: string };
|
|
128
|
+
* select<User>(['id', 'email']); // → "id,email"
|
|
129
|
+
*/
|
|
31
130
|
export const select = <T>(keys: (keyof T)[]): string => {
|
|
131
|
+
// Join all keys into a single comma-separated string
|
|
32
132
|
return keys.join(',');
|
|
33
133
|
};
|
|
34
134
|
|
|
35
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Extract all image `src` attribute values from an HTML string.
|
|
137
|
+
*
|
|
138
|
+
* Uses a regex to find <img> tags and capture the value of the `src` attribute.
|
|
139
|
+
*
|
|
140
|
+
* @param htmlString - The HTML string to search for image tags
|
|
141
|
+
* @returns An array of image source URLs
|
|
142
|
+
*
|
|
143
|
+
* Example:
|
|
144
|
+
* extractImageSrcs('<img src="a.png"><div><img src="b.jpg"></div>');
|
|
145
|
+
* // → ["a.png", "b.jpg"]
|
|
146
|
+
*/
|
|
147
|
+
export const extractImageSrcs = (htmlString: string): string[] => {
|
|
148
|
+
// Find all <img> tags with a src attribute
|
|
36
149
|
const imgTags = [...htmlString.matchAll(/<img\s+[^>]*src=["']([^"']+)["'][^>]*>/gi)];
|
|
150
|
+
|
|
151
|
+
// Map over regex matches and extract the first capture group (the src value)
|
|
37
152
|
return imgTags.map(match => match[1]);
|
|
38
153
|
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generate a random alphanumeric string (uppercase letters + digits).
|
|
157
|
+
*
|
|
158
|
+
* @param length - The desired length of the generated string
|
|
159
|
+
* @returns A randomly generated string of the given length
|
|
160
|
+
*
|
|
161
|
+
* Example:
|
|
162
|
+
* getRandomString(6) → "A9X2KQ"
|
|
163
|
+
*/
|
|
164
|
+
export const getRandomString = (length: number): string => {
|
|
165
|
+
// Allowed characters: A–Z and 0–9
|
|
166
|
+
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
167
|
+
let result = '';
|
|
168
|
+
|
|
169
|
+
// Loop for the requested length
|
|
170
|
+
for (let i = 0; i < length; i++) {
|
|
171
|
+
// Pick a random index and append the corresponding character
|
|
172
|
+
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return result;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Check if a given URL points to a video file.
|
|
180
|
+
*
|
|
181
|
+
* Rules:
|
|
182
|
+
* 1. If the URL contains Cloudinary's `video/upload` path → treat as video.
|
|
183
|
+
* 2. Otherwise, check common video file extensions (mp4, webm, mov, avi, mkv).
|
|
184
|
+
*
|
|
185
|
+
* @param url - The URL string to check
|
|
186
|
+
* @returns true if the URL is a video, false otherwise
|
|
187
|
+
*/
|
|
188
|
+
export const isVideoUrl = (url: string): boolean => {
|
|
189
|
+
try {
|
|
190
|
+
const parsed = new URL(url);
|
|
191
|
+
|
|
192
|
+
// ✅ Rule 1: Cloudinary-specific pattern
|
|
193
|
+
if (parsed.pathname.includes('/video/upload/')) return true;
|
|
194
|
+
|
|
195
|
+
// ✅ Rule 2: Check file extension
|
|
196
|
+
const videoExtensions = ['.mp4', '.webm', '.mov', '.avi', '.mkv'];
|
|
197
|
+
const lowerPath = parsed.pathname.toLowerCase();
|
|
198
|
+
return videoExtensions.some(ext => lowerPath.endsWith(ext));
|
|
199
|
+
} catch {
|
|
200
|
+
// ❌ If URL parsing fails, assume it's not a valid video URL
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
};
|