@cyberskill/shared 3.5.0 → 3.7.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/config/vitest/vitest.e2e.js +1 -1
- package/dist/config/vitest/vitest.e2e.js.map +1 -1
- package/dist/config/vitest/vitest.unit.js +1 -1
- package/dist/config/vitest/vitest.unit.js.map +1 -1
- package/dist/constant/common.d.ts +3 -2
- package/dist/constant/common.js +1 -1
- package/dist/constant/common.js.map +1 -1
- package/dist/node/apollo-server/apollo-server.util.js +15 -13
- package/dist/node/apollo-server/apollo-server.util.js.map +1 -1
- package/dist/node/cli/index.js +1 -1
- package/dist/node/cli/index.js.map +1 -1
- package/dist/node/command/command.util.js +29 -29
- package/dist/node/command/command.util.js.map +1 -1
- package/dist/node/express/express.util.d.ts +4 -0
- package/dist/node/express/express.util.js +7 -6
- package/dist/node/express/express.util.js.map +1 -1
- package/dist/node/mongo/mongo.controller.mongoose.d.ts +6 -1
- package/dist/node/mongo/mongo.controller.mongoose.js +10 -11
- package/dist/node/mongo/mongo.controller.mongoose.js.map +1 -1
- package/dist/node/mongo/mongo.controller.native.d.ts +1 -1
- package/dist/node/mongo/mongo.controller.native.js +5 -4
- package/dist/node/mongo/mongo.controller.native.js.map +1 -1
- package/dist/node/mongo/mongo.controller.type.d.ts +15 -0
- package/dist/node/mongo/mongo.dynamic-populate.js +12 -12
- package/dist/node/mongo/mongo.dynamic-populate.js.map +1 -1
- package/dist/node/mongo/mongo.util.d.ts +3 -3
- package/dist/node/mongo/mongo.util.js.map +1 -1
- package/dist/node/path/index.js +2 -2
- package/dist/node/path/path.constant.d.ts +21 -7
- package/dist/node/path/path.constant.js +49 -30
- package/dist/node/path/path.constant.js.map +1 -1
- package/dist/node/storage/storage.util.js +2 -6
- package/dist/node/storage/storage.util.js.map +1 -1
- package/dist/node/ws/ws.util.js +2 -0
- package/dist/node/ws/ws.util.js.map +1 -1
- package/dist/react/apollo-client/apollo-client.util.js +42 -41
- package/dist/react/apollo-client/apollo-client.util.js.map +1 -1
- package/dist/react/log/log.util.d.ts +5 -0
- package/dist/react/log/log.util.js.map +1 -1
- package/dist/typescript/common.type.d.ts +18 -0
- package/dist/typescript/common.type.js +9 -2
- package/dist/typescript/common.type.js.map +1 -1
- package/dist/typescript/index.js +2 -2
- package/dist/util/object/object.util.js +43 -37
- package/dist/util/object/object.util.js.map +1 -1
- package/dist/util/serializer/serializer.util.d.ts +13 -0
- package/dist/util/serializer/serializer.util.js.map +1 -1
- package/dist/util/string/string.util.js +45 -13
- package/dist/util/string/string.util.js.map +1 -1
- package/package.json +10 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string.util.js","names":[],"sources":["../../../src/util/string/string.util.ts"],"sourcesContent":["import type { T_Object } from '#typescript/index.js';\n\nimport type { I_SlugifyOptions } from './string.type.js';\n\nimport { removeAccent } from '../common/common.util.js';\n\nconst RE_NON_ALNUM = /[^a-z0-9\\s-]/gi;\nconst RE_MULTI_SPACE_DASH = /[\\s-]+/g;\nconst RE_LEADING_TRAILING_DASH = /^-+|-+$/g;\nconst RE_HYPHEN = /-/g;\nconst RE_QUERY_FRAGMENT = /[?#]/;\n\n/**\n * Generates a slug from a string.\n * The slug is a URL-friendly version of the string, removing special characters\n * and converting spaces to hyphens.\n *\n * @param input - The string to be slugified.\n * @param options - Options for slugification.\n * @returns The slugified string.\n */\nfunction slugify(input: string, options?: I_SlugifyOptions): string {\n let slug = input.trim();\n\n // 1. Remove accents\n slug = removeAccent(slug);\n\n // 2. To lower case if requested (default true)\n if (options?.lower !== false) {\n slug = slug.toLowerCase();\n }\n\n // 3. Replace invalid characters with space (keeping alphanumeric, hyphens, and spaces)\n slug = slug.replace(RE_NON_ALNUM, ' ');\n\n // 4. Replace multiple spaces or hyphens with a single hyphen\n slug = slug.replace(RE_MULTI_SPACE_DASH, '-');\n\n // 5. Remove leading/trailing hyphens\n slug = slug.replace(RE_LEADING_TRAILING_DASH, '');\n\n return slug;\n}\n\n/**\n * Generates a slug from a string or an object containing strings.\n * The slug is a URL-friendly version of the string, removing special characters\n * and converting spaces to hyphens. This function can handle both single strings\n * and objects with string values.\n *\n * @param input - The string or object to be slugified.\n * @param options - Options for slugification including replacement character, case sensitivity, locale, etc.\n * @returns The slugified string or object with the same structure as the input.\n */\nexport function generateSlug<T = string>(\n input: T,\n options?: I_SlugifyOptions,\n): T {\n const slugifyWithOptions = (value: string) =>\n slugify(value ?? '', options);\n\n if (typeof input === 'object' && input !== null) {\n const result: T_Object = {};\n\n for (const [key, value] of Object.entries(input)) {\n result[key] = slugifyWithOptions(value as string);\n }\n\n return result as T;\n }\n\n return slugifyWithOptions(input as string) as T;\n}\n\n/**\n * Generates a short ID from a UUID.\n * The ID is a substring of the UUID, providing a shorter identifier.\n * Note: This is NOT cryptographically secure and collisions are possible,\n * but suitable for display purposes where uniqueness is handled elsewhere.\n *\n * @param uuid - The UUID to be converted to a short ID.\n * @param length - The desired length of the short ID (default: 4 characters).\n * @returns A short ID string of the specified length derived from the UUID.\n */\nexport function generateShortId(uuid: string, length = 4): string {\n // Simple hash function (FNV-1a variant) to generate a hex string from the UUID\n let hash = 0x811C9DC5;\n for (let i = 0; i < uuid.length; i++) {\n hash ^= uuid.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n // Convert to unsigned 32-bit integer hex string\n const hex = (hash >>> 0).toString(16).padStart(8, '0');\n\n // If we need more than 8 chars, we can just append part of the original UUID (stripped of dashes)\n // or use a different strategy. For short IDs (usually < 8), the hash is fine.\n // If length > 8, we fallback to just slicing the clean UUID.\n if (length > 8) {\n return uuid.replace(RE_HYPHEN, '').slice(0, length);\n }\n\n return hex.slice(0, length);\n}\n\n/**\n * Internal helper that fills `length` characters from `charset` using\n * rejection-sampling over `crypto.getRandomValues` to avoid modulo bias.\n * Random values are requested in bounded chunks to keep allocations small.\n *\n * @param length - Number of characters to generate.\n * @param charset - The pool of characters to draw from.\n * @returns A randomly generated string of the requested length.\n */\nfunction generateRandomFromCharset(length: number, charset: string): string {\n const limit = Math.floor(2 ** 32 / charset.length) * charset.length;\n const result: string[] = [];\n const MAX_UINT32_VALUES_PER_CALL = 16384;\n\n while (result.length < length) {\n const remaining = length - result.length;\n const chunkSize = remaining > MAX_UINT32_VALUES_PER_CALL ? MAX_UINT32_VALUES_PER_CALL : remaining;\n const values = new Uint32Array(chunkSize);\n crypto.getRandomValues(values);\n\n for (const value of values) {\n if (result.length >= length) {\n break;\n }\n if (value < limit) {\n result.push(charset[value % charset.length] as string);\n }\n }\n }\n\n return result.join('');\n}\n\n/**\n * Generates a random password of a given length.\n * The password contains a mix of letters (both cases), numbers, and special characters\n * to ensure complexity and security.\n *\n * @param length - The desired length of the password (default: 8 characters).\n * @returns A randomly generated password string with the specified length.\n * @throws {RangeError} If `length` is not a non-negative safe integer.\n */\nexport function generateRandomPassword(length = 8): string {\n if (!Number.isSafeInteger(length) || length < 0) {\n throw new RangeError('length must be a non-negative safe integer');\n }\n\n const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+[]{}|;:,.<>?';\n\n return generateRandomFromCharset(length, charset);\n}\n\n/**\n * Generates a random string of a given length using a secure random number generator.\n * This function is a cryptographically secure alternative to Math.random().toString(36).\n *\n * @param length - The desired length of the string (default: 8 characters).\n * @param charset - The characters to use (default: lowercase alphanumeric).\n * @returns A randomly generated string.\n * @throws {RangeError} If `length` is not a non-negative safe integer.\n * @throws {RangeError} If `charset` is empty or exceeds 2^32 characters.\n */\nexport function generateRandomString(\n length = 8,\n charset = 'abcdefghijklmnopqrstuvwxyz0123456789',\n): string {\n if (!Number.isSafeInteger(length) || length < 0) {\n throw new RangeError('length must be a non-negative safe integer');\n }\n\n if (charset.length === 0 || charset.length > 2 ** 32) {\n throw new RangeError('charset.length must be between 1 and 2^32');\n }\n\n return generateRandomFromCharset(length, charset);\n}\n\n/**\n * Get the file name from a URL.\n * This function extracts the file name from a URL, optionally including or excluding\n * the file extension. It handles URLs with query parameters and fragments.\n *\n * @param url - The URL to extract the file name from (default: empty string).\n * @param getExtension - Whether to include the file extension in the result (default: false).\n * @returns The file name extracted from the URL, with or without the extension.\n */\nexport function getFileName(url = '', getExtension = false): string {\n const withoutQuery = url.split(RE_QUERY_FRAGMENT)[0] || '';\n const fileName = withoutQuery.substring(withoutQuery.lastIndexOf('/') + 1);\n\n if (getExtension) {\n return fileName;\n }\n\n const dotIndex = fileName.lastIndexOf('.');\n\n return dotIndex > 0 ? fileName.slice(0, dotIndex) : fileName;\n}\n\n/**\n * Extracts a substring between two strings.\n * This function finds the first occurrence of the starting string, then finds the first\n * occurrence of the ending string after the starting string, and returns the content between them.\n *\n * @param s - The original string to search within.\n * @param a - The starting string that marks the beginning of the desired substring.\n * @param b - The ending string that marks the end of the desired substring.\n * @returns The substring between the two specified strings, or an empty string if either string is not found.\n */\nexport function substringBetween(s: string, a: string, b: string): string {\n const start = s.indexOf(a);\n\n if (start === -1) {\n return '';\n }\n\n const from = start + a.length;\n const end = s.indexOf(b, from);\n\n if (end === -1) {\n return '';\n }\n\n return s.slice(from, end);\n}\n"],"mappings":";;AAMA,IAAM,IAAe,kBACf,IAAsB,WACtB,IAA2B,YAC3B,IAAY,MACZ,IAAoB;AAW1B,SAAS,EAAQ,GAAe,GAAoC;CAChE,IAAI,IAAO,EAAM,MAAM;AAmBvB,QAhBA,IAAO,EAAa,EAAK,EAGrB,GAAS,UAAU,OACnB,IAAO,EAAK,aAAa,GAI7B,IAAO,EAAK,QAAQ,GAAc,IAAI,EAGtC,IAAO,EAAK,QAAQ,GAAqB,IAAI,EAG7C,IAAO,EAAK,QAAQ,GAA0B,GAAG,EAE1C;;AAaX,SAAgB,EACZ,GACA,GACC;CACD,IAAM,KAAsB,MACxB,EAAQ,KAAS,IAAI,EAAQ;AAEjC,KAAI,OAAO,KAAU,YAAY,GAAgB;EAC7C,IAAM,IAAmB,EAAE;AAE3B,OAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,EAAM,CAC5C,GAAO,KAAO,EAAmB,EAAgB;AAGrD,SAAO;;AAGX,QAAO,EAAmB,EAAgB;;AAa9C,SAAgB,EAAgB,GAAc,IAAS,GAAW;CAE9D,IAAI,IAAO;AACX,MAAK,IAAI,IAAI,GAAG,IAAI,EAAK,QAAQ,IAE7B,CADA,KAAQ,EAAK,WAAW,EAAE,EAC1B,IAAO,KAAK,KAAK,GAAM,SAAW;CAGtC,IAAM,KAAO,MAAS,GAAG,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;AAStD,QAJI,IAAS,IACF,EAAK,QAAQ,GAAW,GAAG,CAAC,MAAM,GAAG,EAAO,GAGhD,EAAI,MAAM,GAAG,EAAO;;AAY/B,SAAS,EAA0B,GAAgB,GAAyB;CACxE,IAAM,IAAQ,KAAK,MAAM,KAAK,KAAK,EAAQ,OAAO,GAAG,EAAQ,QACvD,IAAmB,EAAE,EACrB,IAA6B;AAEnC,QAAO,EAAO,SAAS,IAAQ;EAC3B,IAAM,IAAY,IAAS,EAAO,QAE5B,IAAS,IAAI,YADD,IAAY,IAA6B,IAA6B,EAC/C;AACzC,SAAO,gBAAgB,EAAO;AAE9B,OAAK,IAAM,KAAS,GAAQ;AACxB,OAAI,EAAO,UAAU,EACjB;AAEJ,GAAI,IAAQ,KACR,EAAO,KAAK,EAAQ,IAAQ,EAAQ,QAAkB;;;AAKlE,QAAO,EAAO,KAAK,GAAG;;AAY1B,SAAgB,EAAuB,IAAS,GAAW;AACvD,KAAI,CAAC,OAAO,cAAc,EAAO,IAAI,IAAS,EAC1C,OAAU,WAAW,6CAA6C;AAKtE,QAAO,EAA0B,GAFjB,yFAEiC;;AAarD,SAAgB,EACZ,IAAS,GACT,IAAU,wCACJ;AACN,KAAI,CAAC,OAAO,cAAc,EAAO,IAAI,IAAS,EAC1C,OAAU,WAAW,6CAA6C;AAGtE,KAAI,EAAQ,WAAW,KAAK,EAAQ,SAAS,KAAK,GAC9C,OAAU,WAAW,4CAA4C;AAGrE,QAAO,EAA0B,GAAQ,EAAQ;;AAYrD,SAAgB,EAAY,IAAM,IAAI,IAAe,IAAe;CAChE,IAAM,IAAe,EAAI,MAAM,EAAkB,CAAC,MAAM,IAClD,IAAW,EAAa,UAAU,EAAa,YAAY,IAAI,GAAG,EAAE;AAE1E,KAAI,EACA,QAAO;CAGX,IAAM,IAAW,EAAS,YAAY,IAAI;AAE1C,QAAO,IAAW,IAAI,EAAS,MAAM,GAAG,EAAS,GAAG;;AAaxD,SAAgB,EAAiB,GAAW,GAAW,GAAmB;CACtE,IAAM,IAAQ,EAAE,QAAQ,EAAE;AAE1B,KAAI,MAAU,GACV,QAAO;CAGX,IAAM,IAAO,IAAQ,EAAE,QACjB,IAAM,EAAE,QAAQ,GAAG,EAAK;AAM9B,QAJI,MAAQ,KACD,KAGJ,EAAE,MAAM,GAAM,EAAI"}
|
|
1
|
+
{"version":3,"file":"string.util.js","names":[],"sources":["../../../src/util/string/string.util.ts"],"sourcesContent":["import type { T_Object } from '#typescript/index.js';\n\nimport type { I_SlugifyOptions } from './string.type.js';\n\nimport { removeAccent } from '../common/common.util.js';\n\nconst RE_NON_ALNUM = /[^a-z0-9\\s-]/gi;\nconst RE_MULTI_SPACE_DASH = /[\\s-]+/g;\nconst RE_LEADING_TRAILING_DASH = /^-+|-+$/g;\nconst RE_HYPHEN = /-/g;\nconst RE_QUERY_FRAGMENT = /[?#]/;\nconst RE_HAS_LOWER = /[a-z]/;\nconst RE_HAS_UPPER = /[A-Z]/;\nconst RE_HAS_DIGIT = /\\d/;\nconst RE_HAS_SPECIAL = /[!@#$%^&*()_+[\\]{}|;:,.<>?]/;\n\n/**\n * Generates a slug from a string.\n * The slug is a URL-friendly version of the string, removing special characters\n * and converting spaces to hyphens.\n *\n * @param input - The string to be slugified.\n * @param options - Options for slugification.\n * @returns The slugified string.\n */\nfunction slugify(input: string, options?: I_SlugifyOptions): string {\n let slug = input.trim();\n\n // 1. Remove accents\n slug = removeAccent(slug);\n\n // 2. To lower case if requested (default true)\n if (options?.lower !== false) {\n slug = slug.toLowerCase();\n }\n\n // 3. Replace invalid characters with space (keeping alphanumeric, hyphens, and spaces)\n slug = slug.replace(RE_NON_ALNUM, ' ');\n\n // 4. Replace multiple spaces or hyphens with a single hyphen\n slug = slug.replace(RE_MULTI_SPACE_DASH, '-');\n\n // 5. Remove leading/trailing hyphens\n slug = slug.replace(RE_LEADING_TRAILING_DASH, '');\n\n return slug;\n}\n\n/**\n * Generates a slug from a string or an object containing strings.\n * The slug is a URL-friendly version of the string, removing special characters\n * and converting spaces to hyphens. This function can handle both single strings\n * and objects with string values.\n *\n * @param input - The string or object to be slugified.\n * @param options - Options for slugification including replacement character, case sensitivity, locale, etc.\n * @returns The slugified string or object with the same structure as the input.\n */\nexport function generateSlug<T = string>(\n input: T,\n options?: I_SlugifyOptions,\n): T {\n const slugifyWithOptions = (value: string) =>\n slugify(value ?? '', options);\n\n if (typeof input === 'object' && input !== null) {\n const result: T_Object = {};\n\n for (const [key, value] of Object.entries(input)) {\n result[key] = slugifyWithOptions(value as string);\n }\n\n return result as T;\n }\n\n return slugifyWithOptions(input as string) as T;\n}\n\n/**\n * Generates a short ID from a UUID.\n * The ID is a substring of the UUID, providing a shorter identifier.\n * Note: This is NOT cryptographically secure and collisions are possible,\n * but suitable for display purposes where uniqueness is handled elsewhere.\n *\n * @param uuid - The UUID to be converted to a short ID.\n * @param length - The desired length of the short ID (default: 4 characters).\n * @returns A short ID string of the specified length derived from the UUID.\n */\nexport function generateShortId(uuid: string, length = 4): string {\n // Simple hash function (FNV-1a variant) to generate a hex string from the UUID\n let hash = 0x811C9DC5;\n for (let i = 0; i < uuid.length; i++) {\n hash ^= uuid.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n // Convert to unsigned 32-bit integer hex string\n const hex = (hash >>> 0).toString(16).padStart(8, '0');\n\n // If we need more than 8 chars, we can just append part of the original UUID (stripped of dashes)\n // or use a different strategy. For short IDs (usually < 8), the hash is fine.\n // If length > 8, we fallback to just slicing the clean UUID.\n if (length > 8) {\n return uuid.replace(RE_HYPHEN, '').slice(0, length);\n }\n\n return hex.slice(0, length);\n}\n\n/**\n * Internal helper that fills `length` characters from `charset` using\n * rejection-sampling over `crypto.getRandomValues` to avoid modulo bias.\n * Random values are requested in bounded chunks to keep allocations small.\n *\n * @param length - Number of characters to generate.\n * @param charset - The pool of characters to draw from.\n * @returns A randomly generated string of the requested length.\n */\nfunction generateRandomFromCharset(length: number, charset: string): string {\n const limit = Math.floor(2 ** 32 / charset.length) * charset.length;\n const result: string[] = [];\n const MAX_UINT32_VALUES_PER_CALL = 16384;\n\n while (result.length < length) {\n const remaining = length - result.length;\n const chunkSize = remaining > MAX_UINT32_VALUES_PER_CALL ? MAX_UINT32_VALUES_PER_CALL : remaining;\n const values = new Uint32Array(chunkSize);\n crypto.getRandomValues(values);\n\n for (const value of values) {\n if (result.length >= length) {\n break;\n }\n if (value < limit) {\n result.push(charset[value % charset.length] as string);\n }\n }\n }\n\n return result.join('');\n}\n\n/**\n * Generates a random password of a given length.\n * The password contains a mix of letters (both cases), numbers, and special characters\n * to ensure complexity and security.\n *\n * @param length - The desired length of the password (default: 8 characters).\n * @returns A randomly generated password string with the specified length.\n * @throws {RangeError} If `length` is not a non-negative safe integer.\n */\nexport function generateRandomPassword(length = 8): string {\n if (!Number.isSafeInteger(length) || length < 0) {\n throw new RangeError('length must be a non-negative safe integer');\n }\n\n const lower = 'abcdefghijklmnopqrstuvwxyz';\n const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n const digits = '0123456789';\n const special = '!@#$%^&*()_+[]{}|;:,.<>?';\n const charset = lower + upper + digits + special;\n\n const password = generateRandomFromCharset(length, charset);\n\n // Ensure at least one char from each class when length >= 4\n if (length >= 4) {\n const hasLower = RE_HAS_LOWER.test(password);\n const hasUpper = RE_HAS_UPPER.test(password);\n const hasDigit = RE_HAS_DIGIT.test(password);\n const hasSpecial = RE_HAS_SPECIAL.test(password);\n\n if (hasLower && hasUpper && hasDigit && hasSpecial) {\n return password;\n }\n\n // Replace random positions with missing classes to avoid predictable placement\n const chars = [...password];\n const missing: { test: boolean; pool: string }[] = [\n { test: hasLower, pool: lower },\n { test: hasUpper, pool: upper },\n { test: hasDigit, pool: digits },\n { test: hasSpecial, pool: special },\n ];\n\n // Collect random, unique indices via Fisher-Yates partial shuffle\n const indices = Array.from({ length }, (_, i) => i);\n for (let i = indices.length - 1; i > 0; i--) {\n const buf = new Uint32Array(1);\n crypto.getRandomValues(buf);\n const j = buf[0]! % (i + 1);\n [indices[i], indices[j]] = [indices[j]!, indices[i]!];\n }\n\n let pos = 0;\n for (const { test, pool } of missing) {\n if (!test) {\n chars[indices[pos]!] = generateRandomFromCharset(1, pool);\n pos++;\n }\n }\n\n return chars.join('');\n }\n\n return password;\n}\n\n/**\n * Generates a random string of a given length using a secure random number generator.\n * This function is a cryptographically secure alternative to Math.random().toString(36).\n *\n * @param length - The desired length of the string (default: 8 characters).\n * @param charset - The characters to use (default: lowercase alphanumeric).\n * @returns A randomly generated string.\n * @throws {RangeError} If `length` is not a non-negative safe integer.\n * @throws {RangeError} If `charset` is empty or exceeds 2^32 characters.\n */\nexport function generateRandomString(\n length = 8,\n charset = 'abcdefghijklmnopqrstuvwxyz0123456789',\n): string {\n if (!Number.isSafeInteger(length) || length < 0) {\n throw new RangeError('length must be a non-negative safe integer');\n }\n\n if (charset.length === 0 || charset.length > 2 ** 32) {\n throw new RangeError('charset.length must be between 1 and 2^32');\n }\n\n return generateRandomFromCharset(length, charset);\n}\n\n/**\n * Get the file name from a URL.\n * This function extracts the file name from a URL, optionally including or excluding\n * the file extension. It handles URLs with query parameters and fragments.\n *\n * @param url - The URL to extract the file name from (default: empty string).\n * @param getExtension - Whether to include the file extension in the result (default: false).\n * @returns The file name extracted from the URL, with or without the extension.\n */\nexport function getFileName(url = '', getExtension = false): string {\n const withoutQuery = url.split(RE_QUERY_FRAGMENT)[0] || '';\n const fileName = withoutQuery.substring(withoutQuery.lastIndexOf('/') + 1);\n\n if (getExtension) {\n return fileName;\n }\n\n const dotIndex = fileName.lastIndexOf('.');\n\n return dotIndex > 0 ? fileName.slice(0, dotIndex) : fileName;\n}\n\n/**\n * Extracts a substring between two strings.\n * This function finds the first occurrence of the starting string, then finds the first\n * occurrence of the ending string after the starting string, and returns the content between them.\n *\n * @param s - The original string to search within.\n * @param a - The starting string that marks the beginning of the desired substring.\n * @param b - The ending string that marks the end of the desired substring.\n * @returns The substring between the two specified strings, or an empty string if either string is not found.\n */\nexport function substringBetween(s: string, a: string, b: string): string {\n const start = s.indexOf(a);\n\n if (start === -1) {\n return '';\n }\n\n const from = start + a.length;\n const end = s.indexOf(b, from);\n\n if (end === -1) {\n return '';\n }\n\n return s.slice(from, end);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyberskill/shared",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.7.0",
|
|
5
5
|
"description": "CyberSkill Shared",
|
|
6
6
|
"author": "Stephen Cheng",
|
|
7
7
|
"license": "MIT",
|
|
@@ -236,14 +236,12 @@
|
|
|
236
236
|
"@as-integrations/express5": "1.1.2",
|
|
237
237
|
"@dotenvx/dotenvx": "1.55.1",
|
|
238
238
|
"@eddeee888/gcg-typescript-resolver-files": "0.15.0",
|
|
239
|
-
"@eslint-react/eslint-plugin": "2.13.0",
|
|
240
239
|
"@graphql-codegen/cli": "6.2.1",
|
|
241
240
|
"@graphql-codegen/client-preset": "5.2.4",
|
|
242
241
|
"@nestjs/common": "11.1.17",
|
|
243
242
|
"@nestjs/core": "11.1.17",
|
|
244
|
-
"@testing-library/dom": "10.4.1",
|
|
245
243
|
"@userback/widget": "0.3.12",
|
|
246
|
-
"@vitejs/plugin-react
|
|
244
|
+
"@vitejs/plugin-react": "6.0.1",
|
|
247
245
|
"body-parser": "2.2.2",
|
|
248
246
|
"chalk": "5.6.2",
|
|
249
247
|
"clsx": "2.1.1",
|
|
@@ -253,9 +251,6 @@
|
|
|
253
251
|
"cors": "2.8.6",
|
|
254
252
|
"date-fns": "4.1.0",
|
|
255
253
|
"envalid": "8.1.1",
|
|
256
|
-
"eslint-plugin-format": "2.0.1",
|
|
257
|
-
"eslint-plugin-react-hooks": "7.0.1",
|
|
258
|
-
"eslint-plugin-react-refresh": "0.5.2",
|
|
259
254
|
"express": "5.2.1",
|
|
260
255
|
"express-rate-limit": "8.3.1",
|
|
261
256
|
"express-session": "1.19.0",
|
|
@@ -287,13 +282,15 @@
|
|
|
287
282
|
"devDependencies": {
|
|
288
283
|
"@commitlint/cli": "20.5.0",
|
|
289
284
|
"@commitlint/config-conventional": "20.5.0",
|
|
285
|
+
"@eslint-react/eslint-plugin": "2.13.0",
|
|
290
286
|
"@eslint/config-inspector": "1.5.0",
|
|
291
287
|
"@next/eslint-plugin-next": "16.1.7",
|
|
292
288
|
"@semantic-release/changelog": "6.0.3",
|
|
293
289
|
"@semantic-release/git": "10.0.1",
|
|
294
290
|
"@semantic-release/github": "12.0.6",
|
|
295
|
-
"@storybook/react": "10.
|
|
296
|
-
"@storybook/react-vite": "10.
|
|
291
|
+
"@storybook/react": "10.3.0",
|
|
292
|
+
"@storybook/react-vite": "10.3.0",
|
|
293
|
+
"@testing-library/dom": "10.4.1",
|
|
297
294
|
"@testing-library/jest-dom": "6.9.1",
|
|
298
295
|
"@testing-library/react": "16.3.2",
|
|
299
296
|
"@types/body-parser": "1.19.6",
|
|
@@ -314,8 +311,12 @@
|
|
|
314
311
|
"@types/yargs": "17.0.35",
|
|
315
312
|
"@vitest/browser": "4.1.0",
|
|
316
313
|
"@vitest/coverage-istanbul": "4.1.0",
|
|
314
|
+
"conventional-changelog-conventionalcommits": "9.3.0",
|
|
317
315
|
"eslint": "10.0.3",
|
|
318
316
|
"eslint-config-next": "16.1.7",
|
|
317
|
+
"eslint-plugin-format": "2.0.1",
|
|
318
|
+
"eslint-plugin-react-hooks": "7.0.1",
|
|
319
|
+
"eslint-plugin-react-refresh": "0.5.2",
|
|
319
320
|
"glob": "13.0.6",
|
|
320
321
|
"jsdom": "29.0.0",
|
|
321
322
|
"lint-staged": "16.4.0",
|