@creopse/utils 0.0.2 → 0.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.
@@ -179,19 +179,6 @@ export declare function downloadObjectAsJson(exportObj: object, exportName: stri
179
179
  export declare function parseINIString(iniString: string): {
180
180
  [key: string]: string;
181
181
  };
182
- /**
183
- * Compresses an image file.
184
- *
185
- * @param {File} file - The image file to compress.
186
- * @param {Object} options - Optional parameters for compression.
187
- * @param {number} options.maxSizeMB - The maximum size of the compressed image file in megabytes (default is 1MB).
188
- * @param {number} options.maxWidthOrHeight - The maximum width or height of the compressed image file in pixels (default is 1920).
189
- * @return {Promise<File>} The compressed image file.
190
- */
191
- export declare function compressImage(file: File, { maxSizeMB, maxWidthOrHeight }?: {
192
- maxSizeMB?: number | undefined;
193
- maxWidthOrHeight?: number | undefined;
194
- }): Promise<File>;
195
182
  /**
196
183
  * Returns the base URL of the current window location.
197
184
  *
@@ -310,3 +297,23 @@ export declare function shuffleArray<T>(array: T[]): T[];
310
297
  * @param {string} id - The ID of the element to scroll to.
311
298
  */
312
299
  export declare function slideToId(id: string): void;
300
+ /**
301
+ * Checks if the given string is a valid SVG document.
302
+ *
303
+ * @param {string} input - The string to be checked.
304
+ * @return {boolean} Returns true if the string is a valid SVG document, false otherwise.
305
+ */
306
+ export declare function isSVG(input: string): boolean;
307
+ /**
308
+ * Checks if the given string is a valid URL.
309
+ *
310
+ * This function verifies whether a string is formatted as a valid URL. It adds
311
+ * a default 'http' protocol if missing, parses the URL, and checks for valid
312
+ * protocol, hostname, and optional port. It supports 'http', 'https', and 'ftp'
313
+ * protocols, disallows underscores in hostnames, and ensures the presence of a
314
+ * top-level domain (TLD) unless the hostname is 'localhost' or an IP address.
315
+ *
316
+ * @param {string} str - The string to be checked.
317
+ * @return {boolean} Returns true if the string is a valid URL, false otherwise.
318
+ */
319
+ export declare function isURL(str: string): boolean;
@@ -1,5 +1,3 @@
1
- import imageCompression from 'browser-image-compression';
2
- import _ from 'lodash';
3
1
  /**
4
2
  * Generates the initials of a given name.
5
3
  *
@@ -142,22 +140,38 @@ export function capitalizeFirstLetter(string) {
142
140
  export function genPassword(length = 10, { letters = true, numbers = true, symbols = false } = {}) {
143
141
  if (!letters && !numbers && !symbols)
144
142
  return '';
145
- let base = [], password = '';
146
- const numbersBase = '0123456789'.split(''), symbolsBase = '!@#$%^&*()'.split(''), lettersBase = 'abcdefghijklmnopqrstuvwxyz'.split('');
143
+ const numbersBase = '0123456789';
144
+ const symbolsBase = '!@#$%^&*()';
145
+ const lowercaseLetters = 'abcdefghijklmnopqrstuvwxyz';
146
+ const uppercaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
147
+ let charPool = '';
147
148
  if (letters)
148
- base.push(...lettersBase);
149
+ charPool += lowercaseLetters + uppercaseLetters;
149
150
  if (numbers)
150
- base.push(...numbersBase);
151
+ charPool += numbersBase;
151
152
  if (symbols)
152
- base.push(...symbolsBase);
153
- base = _.shuffle(base);
154
- for (let i = 0; i < length; i++) {
155
- const randomNumber = Math.floor(Math.random() * base.length);
156
- const char = lettersBase.includes(base[randomNumber]) &&
157
- Math.floor(Math.random() * 2) === 0
158
- ? base[randomNumber].toUpperCase()
159
- : base[randomNumber];
160
- password += char;
153
+ charPool += symbolsBase;
154
+ let password = '';
155
+ const poolLength = charPool.length;
156
+ // Use crypto.getRandomValues for better randomness if available
157
+ const crypto = window.crypto || window.msCrypto;
158
+ const hasCrypto = crypto && crypto.getRandomValues;
159
+ // @ts-ignore
160
+ if (hasCrypto) {
161
+ // More secure version using crypto API
162
+ const values = new Uint32Array(length);
163
+ crypto.getRandomValues(values);
164
+ for (let i = 0; i < length; i++) {
165
+ const randomIndex = values[i] % poolLength;
166
+ password += charPool[randomIndex];
167
+ }
168
+ }
169
+ else {
170
+ // Fallback to Math.random (less secure)
171
+ for (let i = 0; i < length; i++) {
172
+ const randomIndex = Math.floor(Math.random() * poolLength);
173
+ password += charPool[randomIndex];
174
+ }
161
175
  }
162
176
  return password;
163
177
  }
@@ -331,35 +345,6 @@ export function parseINIString(iniString) {
331
345
  }
332
346
  return result;
333
347
  }
334
- /**
335
- * Compresses an image file.
336
- *
337
- * @param {File} file - The image file to compress.
338
- * @param {Object} options - Optional parameters for compression.
339
- * @param {number} options.maxSizeMB - The maximum size of the compressed image file in megabytes (default is 1MB).
340
- * @param {number} options.maxWidthOrHeight - The maximum width or height of the compressed image file in pixels (default is 1920).
341
- * @return {Promise<File>} The compressed image file.
342
- */
343
- export async function compressImage(file, { maxSizeMB = 1, maxWidthOrHeight = 1920 } = {}) {
344
- const extensions = ['jpeg', 'jpg', 'png', 'gif', 'webp', 'svg'];
345
- const fileExt = file.name.split('.').pop();
346
- const options = {
347
- maxSizeMB: maxSizeMB,
348
- maxWidthOrHeight: maxWidthOrHeight,
349
- };
350
- let result = file;
351
- if (fileExt != null && extensions.includes(fileExt.toLowerCase())) {
352
- try {
353
- result = await imageCompression(file, options);
354
- }
355
- catch (error) {
356
- console.log(error);
357
- }
358
- }
359
- if (result instanceof Blob)
360
- return new File([result], file.name);
361
- return result;
362
- }
363
348
  /**
364
349
  * Returns the base URL of the current window location.
365
350
  *
@@ -572,3 +557,98 @@ export function slideToId(id) {
572
557
  console.error(`Element with ID "${id}" not found.`);
573
558
  }
574
559
  }
560
+ /**
561
+ * Checks if the given string is a valid SVG document.
562
+ *
563
+ * @param {string} input - The string to be checked.
564
+ * @return {boolean} Returns true if the string is a valid SVG document, false otherwise.
565
+ */
566
+ export function isSVG(input) {
567
+ const svgRegex = /^\s*<svg\b[^>]*>.*<\/svg>\s*$/is;
568
+ try {
569
+ if (svgRegex.test(input)) {
570
+ const parser = new DOMParser();
571
+ const doc = parser.parseFromString(input, 'image/svg+xml');
572
+ const parserErrors = doc.getElementsByTagName('parsererror');
573
+ if (parserErrors.length > 0) {
574
+ return false;
575
+ }
576
+ const svgElements = doc.getElementsByTagName('svg');
577
+ return svgElements.length > 0 && svgElements[0].parentNode === doc;
578
+ }
579
+ return false;
580
+ }
581
+ catch (e) {
582
+ return false;
583
+ }
584
+ }
585
+ /**
586
+ * Checks if the given string is a valid URL.
587
+ *
588
+ * This function verifies whether a string is formatted as a valid URL. It adds
589
+ * a default 'http' protocol if missing, parses the URL, and checks for valid
590
+ * protocol, hostname, and optional port. It supports 'http', 'https', and 'ftp'
591
+ * protocols, disallows underscores in hostnames, and ensures the presence of a
592
+ * top-level domain (TLD) unless the hostname is 'localhost' or an IP address.
593
+ *
594
+ * @param {string} str - The string to be checked.
595
+ * @return {boolean} Returns true if the string is a valid URL, false otherwise.
596
+ */
597
+ export function isURL(str) {
598
+ if (!str || typeof str !== 'string') {
599
+ return false;
600
+ }
601
+ let url = str.trim();
602
+ // Add default protocol if missing
603
+ if (!url.includes('://')) {
604
+ url = 'http://' + url;
605
+ }
606
+ let urlParts;
607
+ try {
608
+ urlParts = new URL(url);
609
+ }
610
+ catch {
611
+ return false;
612
+ }
613
+ // Check protocol (allow http, https, ftp)
614
+ const protocol = urlParts.protocol.replace(':', '');
615
+ if (!['http', 'https', 'ftp'].includes(protocol)) {
616
+ return false;
617
+ }
618
+ // Require hostname
619
+ if (!urlParts.hostname) {
620
+ return false;
621
+ }
622
+ const hostname = urlParts.hostname.toLowerCase();
623
+ // Don't allow underscores in hostname (standard domains)
624
+ if (hostname.includes('_')) {
625
+ return false;
626
+ }
627
+ // Check for valid port (if present)
628
+ if (urlParts.port) {
629
+ const port = parseInt(urlParts.port, 10);
630
+ if (isNaN(port) || port < 1 || port > 65535) {
631
+ return false;
632
+ }
633
+ }
634
+ // Check for TLD requirement (except localhost and IP addresses)
635
+ const isLocalhost = hostname === 'localhost';
636
+ const isIPv4 = /^(?:(?:\d{1,3}\.){3}\d{1,3})$/i.test(hostname);
637
+ const isIPv6 = /^\[([0-9a-f:]+)\]$/i.test(hostname) || /^([0-9a-f:]+)$/i.test(hostname);
638
+ if (!isLocalhost && !isIPv4 && !isIPv6) {
639
+ const parts = hostname.split('.');
640
+ if (parts.length < 2 || parts.some((part) => !part)) {
641
+ return false; // No empty parts (e.g., "example..com")
642
+ }
643
+ // Allow single-letter TLDs (e.g., "example.io", "example.a")
644
+ if (parts[parts.length - 1].length < 1) {
645
+ return false;
646
+ }
647
+ }
648
+ // Hostname validation (allows internationalized domains if needed)
649
+ const hostnameRegex = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i;
650
+ if (!hostnameRegex.test(hostname) && !isLocalhost && !isIPv4 && !isIPv6) {
651
+ return false;
652
+ }
653
+ return true;
654
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@creopse/utils",
3
3
  "description": "Creopse Utils Toolkit",
4
- "version": "0.0.2",
4
+ "version": "0.0.3",
5
5
  "private": false,
6
6
  "author": "Noé Gnanih <noegnanih@gmail.com>",
7
7
  "license": "MIT",
@@ -23,7 +23,6 @@
23
23
  "build": "tsc -b && tsc-alias"
24
24
  },
25
25
  "devDependencies": {
26
- "@types/lodash": "^4.17.20",
27
26
  "tsc-alias": "^1.8.16",
28
27
  "typescript": "~5.8.3"
29
28
  },
@@ -41,8 +40,6 @@
41
40
  },
42
41
  "dependencies": {
43
42
  "@inertiajs/core": "^1.0.15",
44
- "browser-image-compression": "^2.0.2",
45
- "lodash": "^4.17.21",
46
43
  "moment": "^2.30.1"
47
44
  }
48
45
  }