typeshi 2.2.1 → 2.2.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.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ Copy/paste into your project if you find something useful.
@@ -5,4 +5,5 @@ export * from "./io";
5
5
  export * from "./regex";
6
6
  export * from "./argumentValidation";
7
7
  export * from "./typeValidation";
8
+ export * from "./utilityTypes";
8
9
  export * from "./object";
@@ -21,4 +21,5 @@ __exportStar(require("./io"), exports);
21
21
  __exportStar(require("./regex"), exports);
22
22
  __exportStar(require("./argumentValidation"), exports);
23
23
  __exportStar(require("./typeValidation"), exports);
24
+ __exportStar(require("./utilityTypes"), exports);
24
25
  __exportStar(require("./object"), exports);
@@ -1,22 +1,23 @@
1
1
  import { ILogObj, ILogObjMeta } from "tslog";
2
2
  /**
3
- * @param fileName `string` passed into `extractFileName()`
3
+ * @param base `string` - e.g. name of file or class
4
+ * - passed into `extractFileName()` if `/\\|\//.test(filename)`
4
5
  * @param func `Function` - to get Function.name
5
6
  * @param funcInfo `any` `(optional)` - context or params of func (converted to string)
6
7
  * @param startLine `number` `(optional)`
7
8
  * @param endLine `number` `(optional)`
8
9
  * @returns **`sourceString`** `string` to use in log statements or argumentValidation calls
9
10
  */
10
- export declare function getSourceString(fileName: string, func: string | Function, funcInfo?: any, startLine?: number, endLine?: number): string;
11
+ export declare function getSourceString(base: string, func: string | Function, funcInfo?: any, startLine?: number, endLine?: number): string;
11
12
  /**
12
13
  * @deprecated
13
14
  * Auto-formats debug logs at the end of application execution.
14
15
  * Call this function when your main application is finishing.
15
- * @param filePaths `string[]` - optional, specific file paths to format.
16
+ * @param filepaths `string[]` - optional, specific file paths to format.
16
17
  * If not provided, will format all .txt files in the log directory.
17
18
  * @returns `void`
18
19
  */
19
- export declare function autoFormatLogsOnExit(filePaths?: string[]): void;
20
+ export declare function autoFormatLogsOnExit(filepaths?: string[]): void;
20
21
  /**
21
22
  * @deprecated
22
23
  * Formats a debug log file from JSON format to a more readable text format.
@@ -31,11 +32,11 @@ export declare function formatDebugLogFile(inputPath: string, outputPath?: strin
31
32
  * @deprecated
32
33
  * Formats all debug log files in the log directory.
33
34
  * Looks for .txt files and creates .FORMATTED.txt versions.
34
- * @param logDirectory `string` - optional, path to the log directory.
35
+ * @param logDir `string` - optional, path to the log directory.
35
36
  * If not provided, uses LOCAL_LOG_DIR from setupLog.ts
36
37
  * @returns `void`
37
38
  */
38
- export declare function formatAllDebugLogs(logDirectory: string): void;
39
+ export declare function formatAllDebugLogs(logDir: string): void;
39
40
  /**
40
41
  * @deprecated
41
42
  * reduce metadata to two entries, then return stringified `logObj`
@@ -44,22 +44,24 @@ exports.formatLogObj = formatLogObj;
44
44
  /**
45
45
  * @file src/utils/io/logging.ts
46
46
  */
47
- const fs = __importStar(require("fs"));
47
+ const node_fs_1 = __importDefault(require("node:fs"));
48
48
  const setupLog_1 = require("../../config/setupLog");
49
49
  const typeValidation_1 = require("../typeValidation");
50
50
  const regex_1 = require("../regex");
51
51
  const validate = __importStar(require("../argumentValidation"));
52
52
  const node_path_1 = __importDefault(require("node:path"));
53
53
  /**
54
- * @param fileName `string` passed into `extractFileName()`
54
+ * @param base `string` - e.g. name of file or class
55
+ * - passed into `extractFileName()` if `/\\|\//.test(filename)`
55
56
  * @param func `Function` - to get Function.name
56
57
  * @param funcInfo `any` `(optional)` - context or params of func (converted to string)
57
58
  * @param startLine `number` `(optional)`
58
59
  * @param endLine `number` `(optional)`
59
60
  * @returns **`sourceString`** `string` to use in log statements or argumentValidation calls
60
61
  */
61
- function getSourceString(fileName, func, funcInfo, startLine, endLine) {
62
- fileName = (0, regex_1.extractFileName)(fileName);
62
+ function getSourceString(base, func, funcInfo, startLine, endLine) {
63
+ if (/\\|\//.test(base))
64
+ base = (0, regex_1.extractFileName)(base);
63
65
  let lineNumberText = ((0, typeValidation_1.isInteger)(startLine)
64
66
  ? `:${startLine}`
65
67
  : '');
@@ -68,30 +70,23 @@ function getSourceString(fileName, func, funcInfo, startLine, endLine) {
68
70
  ? lineNumberText + `-${endLine}`
69
71
  : '');
70
72
  let funcName = typeof func === 'string' ? func : func.name;
71
- return `[${fileName}.${funcName}(${(0, typeValidation_1.isNonEmptyString)(funcInfo) ? ` ${funcInfo} ` : ''})${lineNumberText}]`;
73
+ return `[${base}.${funcName}(${(0, typeValidation_1.isNonEmptyString)(funcInfo) ? ` ${funcInfo} ` : ''})${lineNumberText}]`;
72
74
  }
73
75
  /**
74
76
  * @deprecated
75
77
  * Auto-formats debug logs at the end of application execution.
76
78
  * Call this function when your main application is finishing.
77
- * @param filePaths `string[]` - optional, specific file paths to format.
79
+ * @param filepaths `string[]` - optional, specific file paths to format.
78
80
  * If not provided, will format all .txt files in the log directory.
79
81
  * @returns `void`
80
82
  */
81
- function autoFormatLogsOnExit(filePaths) {
82
- const source = getSourceString(__filename, autoFormatLogsOnExit.name, `Array<string>(${(filePaths ?? []).length})`);
83
- if (!(0, typeValidation_1.isStringArray)(filePaths)) {
84
- setupLog_1.typeshiLogger.warn([`${source} Invalid param 'filePaths'`,
85
- `Expected: string[] (array of filePaths)`,
86
- `Received: ${typeof filePaths} = '${JSON.stringify(filePaths)}'`
87
- ].join(setupLog_1.INDENT_LOG_LINE));
88
- return;
89
- }
83
+ function autoFormatLogsOnExit(filepaths) {
84
+ const source = getSourceString(__filename, autoFormatLogsOnExit.name, `Array<string>(${(filepaths ?? []).length})`);
90
85
  try {
91
- for (const filePath of filePaths) {
92
- if (fs.existsSync(filePath)) {
86
+ validate.arrayArgument(source, { filepaths, isStringArray: typeValidation_1.isStringArray });
87
+ for (const filePath of filepaths ?? []) {
88
+ if (node_fs_1.default.existsSync(filePath))
93
89
  formatDebugLogFile(filePath);
94
- }
95
90
  }
96
91
  }
97
92
  catch (error) {
@@ -116,10 +111,10 @@ function formatDebugLogFile(inputPath, outputPath) {
116
111
  const parsedPath = node_path_1.default.parse(inputPath);
117
112
  outputPath = node_path_1.default.join(parsedPath.dir, `${parsedPath.name}.FORMATTED${parsedPath.ext}`);
118
113
  }
119
- const fileContent = fs.readFileSync(inputPath, 'utf-8');
114
+ const fileContent = node_fs_1.default.readFileSync(inputPath, 'utf-8');
120
115
  const formattedContent = formatLogContent(fileContent);
121
- fs.writeFileSync(outputPath, formattedContent, { encoding: 'utf-8' });
122
- // mlog.info(`[formatDebugLogFile()] Formatted log file saved to '${outputPath}'`);
116
+ node_fs_1.default.writeFileSync(outputPath, formattedContent, { encoding: 'utf-8' });
117
+ setupLog_1.typeshiHiddenLogger.info(`[formatDebugLogFile()] Formatted log file saved to '${outputPath}'`);
123
118
  }
124
119
  catch (error) {
125
120
  setupLog_1.typeshiLogger.error(`${source} Error formatting log file:'`, error);
@@ -216,18 +211,17 @@ function formatSingleLogEntry(logObj) {
216
211
  * @deprecated
217
212
  * Formats all debug log files in the log directory.
218
213
  * Looks for .txt files and creates .FORMATTED.txt versions.
219
- * @param logDirectory `string` - optional, path to the log directory.
214
+ * @param logDir `string` - optional, path to the log directory.
220
215
  * If not provided, uses LOCAL_LOG_DIR from setupLog.ts
221
216
  * @returns `void`
222
217
  */
223
- function formatAllDebugLogs(logDirectory) {
224
- let logDir = logDirectory;
225
- if (!fs.existsSync(logDir)) {
218
+ function formatAllDebugLogs(logDir) {
219
+ if (!node_fs_1.default.existsSync(logDir)) {
226
220
  setupLog_1.typeshiLogger.warn(`[formatAllDebugLogs()] Log directory does not exist: ${logDir}`);
227
221
  return;
228
222
  }
229
223
  try {
230
- const files = fs.readdirSync(logDir);
224
+ const files = node_fs_1.default.readdirSync(logDir);
231
225
  const txtFiles = files.filter(file => file.endsWith('.txt') && !file.includes('.FORMATTED.'));
232
226
  if (txtFiles.length === 0) {
233
227
  setupLog_1.typeshiLogger.warn(`[formatAllDebugLogs()] No .txt log files found in ${logDir}`);
@@ -237,7 +231,7 @@ function formatAllDebugLogs(logDirectory) {
237
231
  const inputPath = node_path_1.default.join(logDir, txtFile);
238
232
  try {
239
233
  formatDebugLogFile(inputPath);
240
- // mlog.info(`[formatAllDebugLogs()] Formatted: ${txtFile}`);
234
+ setupLog_1.typeshiHiddenLogger.info(`[formatAllDebugLogs()] Formatted: ${txtFile}`);
241
235
  }
242
236
  catch (error) {
243
237
  setupLog_1.typeshiLogger.error(`[formatAllDebugLogs()] Failed to format ${txtFile}:`, error);
@@ -2,9 +2,9 @@ import { StringCleanOptions } from "../regex";
2
2
  import { DirectoryFileOptions, FileData, FileExtension } from "./types/Io";
3
3
  import { DelimiterCharacterEnum } from "./types";
4
4
  /** checks if `pathString (value)` points to an existing directory */
5
- export declare function isDirectory(value: any): value is string;
5
+ export declare function isDirectory(value: any): boolean;
6
6
  /** checks if `pathString (value)` points to an existing file */
7
- export declare function isFile(value: string): value is string;
7
+ export declare function isFile(value: string): boolean;
8
8
  /**
9
9
  * Determines the proper delimiter based on file type or extension
10
10
  * @param filePath `string` Path to the file
@@ -472,8 +472,8 @@ async function getOneToOneDictionary(arg1, keyColumn, valueColumn, keyOptions, v
472
472
  */
473
473
  async function getColumnValues(arg1, columnName, cleaner, allowDuplicates = false) {
474
474
  const source = (0, logging_1.getSourceString)(__filename, getColumnValues.name);
475
- validate.stringArgument(source, { columnName });
476
- validate.booleanArgument(source, { allowDuplicates });
475
+ // validate.stringArgument(source, {columnName});
476
+ // validate.booleanArgument(source, {allowDuplicates});
477
477
  if (cleaner)
478
478
  validate.functionArgument(source, { cleaner });
479
479
  let rows = await handleFileArgument(arg1, getColumnValues.name, [columnName]);
@@ -497,7 +497,7 @@ async function getColumnValues(arg1, columnName, cleaner, allowDuplicates = fals
497
497
  */
498
498
  async function getIndexedColumnValues(arg1, columnName, cleaner) {
499
499
  const source = `[reading.getIndexedColumnValues()]`;
500
- validate.stringArgument(source, { columnName });
500
+ // validate.stringArgument(source, {columnName});
501
501
  if (cleaner)
502
502
  validate.functionArgument(source, { cleaner });
503
503
  let rows = await handleFileArgument(arg1, getIndexedColumnValues.name, [columnName]);
@@ -100,3 +100,12 @@ export declare function hasDefinedEntry<T extends object>(obj: any, key: keyof T
100
100
  export declare function containsKey<T extends object, K extends (keyof T | (keyof any & {})) = any>(obj: T, ...keys: K[]): obj is {
101
101
  [K in keyof T]: T[K];
102
102
  };
103
+ /**
104
+ * @deprecated
105
+ * @param objA `Record<string, any>`
106
+ * @param objB `Record<string, any>`
107
+ * @returns **`areEquivalentObjects`** `boolean`
108
+ * - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
109
+ * - `false` `otherwise`.
110
+ */
111
+ export declare function areEquivalentObjects(objA: Record<string, any>, objB: Record<string, any>): boolean;
@@ -11,7 +11,9 @@ exports.picked = picked;
11
11
  exports.enforceMaxLength = enforceMaxLength;
12
12
  exports.hasDefinedEntry = hasDefinedEntry;
13
13
  exports.containsKey = containsKey;
14
+ exports.areEquivalentObjects = areEquivalentObjects;
14
15
  const typeValidation_1 = require("./typeValidation");
16
+ const index_1 = require("./regex/index");
15
17
  /**
16
18
  * @param obj `S` - source object (e.g., Request Body)
17
19
  * @param schema {@link TransformationSchema}`<T, S>` - map of keys to transformation functions.
@@ -177,3 +179,33 @@ function containsKey(obj, ...keys) {
177
179
  }
178
180
  return true;
179
181
  }
182
+ /**
183
+ * @deprecated
184
+ * @param objA `Record<string, any>`
185
+ * @param objB `Record<string, any>`
186
+ * @returns **`areEquivalentObjects`** `boolean`
187
+ * - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
188
+ * - `false` `otherwise`.
189
+ */
190
+ function areEquivalentObjects(objA, objB) {
191
+ if (!(0, typeValidation_1.isObject)(objA) || !(0, typeValidation_1.isObject)(objB))
192
+ return false;
193
+ const keysA = Object.keys(objA);
194
+ const keysB = Object.keys(objB);
195
+ if (keysA.length !== keysB.length)
196
+ return false;
197
+ return keysA.every(key => {
198
+ if (!containsKey(objB, key))
199
+ return false; // key not in both objects
200
+ const valA = objA[key];
201
+ const valB = objB[key];
202
+ if (Array.isArray(valA) && Array.isArray(valB)) {
203
+ return valA.length === valB.length
204
+ && valA.every((item) => valB.includes(item));
205
+ }
206
+ else if (typeof valA === "object" && valA && typeof valB === "object" && valB) {
207
+ return areEquivalentObjects(valA, valB);
208
+ }
209
+ return (0, index_1.equivalentAlphanumericStrings)(valA, valB);
210
+ });
211
+ }
@@ -1,6 +1,29 @@
1
- /** `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
1
+ export interface ParsedEmailAddress {
2
+ /** the whole email address */
3
+ address: string;
4
+ /** `localPart` the part before the @ sign */
5
+ local: string;
6
+ /** the part after the @ sign */
7
+ domain: string;
8
+ /** sender's display name if present in source string */
9
+ displayName?: string;
10
+ }
11
+ /**
12
+ * @param s `string`
13
+ * - e.g. `"{local}@{domain}"`, `"{displayName} <{local}@{domain}>"`
14
+ * @returns **`result`** {@link ParsedEmailAddress}` | null`
15
+ * @note `ParsedEmail.displayName` will be `undefined` if not present in `s`
16
+ * - prefix `/^no(-)?reply\s*(?=\w)/i` is removed from `displayName`
17
+ */
18
+ export declare function parseEmailAddress(s: string): ParsedEmailAddress | null;
19
+ /** @deprecated
20
+ * `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
2
21
  export declare const EMAIL_REGEX: RegExp;
3
- /**return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
4
- export declare function isValidEmail(email: string, excludeSubstrings?: string | RegExp | string[]): boolean;
5
- /** @returns **`email`**: `string` - the first email that matches {@link EMAIL_REGEX} or an empty string `''`*/
22
+ /**
23
+ * @deprecated
24
+ * return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
25
+ export declare function isValidEmail(email: string, excludeSubstrings?: string | string[] | RegExp): boolean;
26
+ /**
27
+ * @deprecated
28
+ * @returns `RegExpMatchArray` {@link EMAIL_REGEX} */
6
29
  export declare function extractEmail(email: string): RegExpMatchArray | null;
@@ -1,24 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.EMAIL_REGEX = void 0;
4
+ exports.parseEmailAddress = parseEmailAddress;
4
5
  exports.isValidEmail = isValidEmail;
5
6
  exports.extractEmail = extractEmail;
6
7
  /**
7
8
  * @file src/utils/regex/email.ts
8
9
  */
9
- const stringOperations_1 = require("./stringOperations");
10
- const StringOptions_1 = require("./types/StringOptions");
11
- /** `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
12
- exports.EMAIL_REGEX = new RegExp(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/, StringOptions_1.RegExpFlagsEnum.GLOBAL);
13
- /**return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
10
+ const Str_1 = require("./Str");
11
+ // @TODO parameterize replacements in parsed displayName
12
+ /**
13
+ * @param s `string`
14
+ * - e.g. `"{local}@{domain}"`, `"{displayName} <{local}@{domain}>"`
15
+ * @returns **`result`** {@link ParsedEmailAddress}` | null`
16
+ * @note `ParsedEmail.displayName` will be `undefined` if not present in `s`
17
+ * - prefix `/^no(-)?reply\s*(?=\w)/i` is removed from `displayName`
18
+ */
19
+ function parseEmailAddress(s) {
20
+ const emailRegex = /([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g;
21
+ const matchArrays = Array.from(s.matchAll(emailRegex));
22
+ if (matchArrays.length === 0)
23
+ return null;
24
+ const match = matchArrays[0];
25
+ const [address, local, domain] = match;
26
+ const displayName = (s
27
+ .slice(0, match.index ?? 0)
28
+ .trim()
29
+ .replace(/^no(-)?reply\s*(?=\w)/i, '')
30
+ .replace(/<$/, '')
31
+ .trim());
32
+ const result = { address, local, domain };
33
+ if (displayName)
34
+ result.displayName = displayName;
35
+ return result;
36
+ }
37
+ /** @deprecated
38
+ * `re` = `/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/` */
39
+ exports.EMAIL_REGEX = new RegExp(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
40
+ /**
41
+ * @deprecated
42
+ * return true if matches {@link EMAIL_REGEX} and does not include pattern/string specified in `excludeSubstrings` */
14
43
  function isValidEmail(email, excludeSubstrings) {
15
44
  if (!email)
16
45
  return false;
17
46
  email = email.trim();
18
- return exports.EMAIL_REGEX.test(email)
19
- && (excludeSubstrings ? !(0, stringOperations_1.stringContainsAnyOf)(email, excludeSubstrings) : true);
47
+ return (excludeSubstrings
48
+ ? exports.EMAIL_REGEX.test(email) && !Str_1.Str.contains(email, excludeSubstrings)
49
+ : exports.EMAIL_REGEX.test(email));
20
50
  }
21
- /** @returns **`email`**: `string` - the first email that matches {@link EMAIL_REGEX} or an empty string `''`*/
51
+ /**
52
+ * @deprecated
53
+ * @returns `RegExpMatchArray` {@link EMAIL_REGEX} */
22
54
  function extractEmail(email) {
23
55
  if (!email)
24
56
  return null;
@@ -4,12 +4,12 @@
4
4
  /**
5
5
  * `extractFileNameFromPath`
6
6
  * essentially a wrapper for path.basename() for short-hand convenience
7
- * @param filePath `string` e.g. pass in the node module variable `__filename`
7
+ * @param filepath `string` e.g. pass in the node module variable `__filename`
8
8
  * @param removeExtension `boolean` `optional, default = true` - flag indicating
9
- * whether or not to remove the file extension from the fileName
10
- * @returns **`fileName`** `string`
9
+ * whether or not to remove the file extension from the filename
10
+ * @returns **`filename`** `string`
11
11
  */
12
- export declare function extractFileName(filePath: string, removeExtension?: boolean): string;
12
+ export declare function extractFileName(filepath: string, removeExtension?: boolean): string;
13
13
  /**
14
14
  * = `= /^[^/\\:*?"<>|]+(\.[^/\\:*?"<>|]+)$/`
15
15
  */
@@ -33,3 +33,17 @@ export declare const KOREA_ADDRESS_LATIN_TEXT_PATTERN: RegExp;
33
33
  * @returns **`leaf`**: `string` - the extracted `leaf` or the original value if no extraction performed
34
34
  */
35
35
  export declare function extractLeaf(value: string, classDelimiter: string): string;
36
+ /**
37
+ * @param keepParentheses `boolean (optional)` `default = false`
38
+ * @returns **new RegExp** with same flags as `re`
39
+ * - returns `re` if does not have `groupName`
40
+ * @example
41
+ * const re = /(?<name>)\s*abcdefg/;
42
+ * let groupName = 'name';
43
+ * let value = 'Bob';
44
+ * let result1 = replaceGroupWithLiteral(re, groupName, value, false);
45
+ * // result1.source === 'Bob\\s*abcdefg'
46
+ * let result2 = replaceGroupWithLiteral(re, groupName, value, true);
47
+ * // result2.source === '(Bob)\\s*abcdefg'
48
+ */
49
+ export declare function replaceGroupWithLiteral(re: RegExp, groupName: string, value: string, keepParentheses?: boolean): RegExp;
@@ -9,25 +9,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.KOREA_ADDRESS_LATIN_TEXT_PATTERN = exports.DATE_STRING_PATTERN = exports.FILE_NAME_WITH_EXTENSION_PATTERN = void 0;
10
10
  exports.extractFileName = extractFileName;
11
11
  exports.extractLeaf = extractLeaf;
12
+ exports.replaceGroupWithLiteral = replaceGroupWithLiteral;
12
13
  const typeValidation_1 = require("../typeValidation");
13
14
  const node_path_1 = __importDefault(require("node:path"));
14
15
  /**
15
16
  * `extractFileNameFromPath`
16
17
  * essentially a wrapper for path.basename() for short-hand convenience
17
- * @param filePath `string` e.g. pass in the node module variable `__filename`
18
+ * @param filepath `string` e.g. pass in the node module variable `__filename`
18
19
  * @param removeExtension `boolean` `optional, default = true` - flag indicating
19
- * whether or not to remove the file extension from the fileName
20
- * @returns **`fileName`** `string`
20
+ * whether or not to remove the file extension from the filename
21
+ * @returns **`filename`** `string`
21
22
  */
22
- function extractFileName(filePath, removeExtension = true) {
23
- if (!(0, typeValidation_1.isNonEmptyString)(filePath)) {
23
+ function extractFileName(filepath, removeExtension = true) {
24
+ if (!(0, typeValidation_1.isNonEmptyString)(filepath)) {
24
25
  return 'undefined';
25
26
  }
26
- let fileName = node_path_1.default.basename(filePath);
27
+ let filename = node_path_1.default.basename(filepath);
27
28
  if (removeExtension) {
28
- fileName = fileName.replace(/(?<=.+)\.[a-z0-9]{1,}$/i, '');
29
+ filename = filename.replace(/(?<=.+)\.[a-z0-9]{1,}$/i, '');
29
30
  }
30
- return fileName;
31
+ return filename;
31
32
  }
32
33
  /**
33
34
  * = `= /^[^/\\:*?"<>|]+(\.[^/\\:*?"<>|]+)$/`
@@ -59,3 +60,29 @@ function extractLeaf(value, classDelimiter) {
59
60
  }
60
61
  return result || value;
61
62
  }
63
+ // @consideration rename keepParentheses to keepGroup or keepGrouping or keepGroupParentheses ?
64
+ /**
65
+ * @param keepParentheses `boolean (optional)` `default = false`
66
+ * @returns **new RegExp** with same flags as `re`
67
+ * - returns `re` if does not have `groupName`
68
+ * @example
69
+ * const re = /(?<name>)\s*abcdefg/;
70
+ * let groupName = 'name';
71
+ * let value = 'Bob';
72
+ * let result1 = replaceGroupWithLiteral(re, groupName, value, false);
73
+ * // result1.source === 'Bob\\s*abcdefg'
74
+ * let result2 = replaceGroupWithLiteral(re, groupName, value, true);
75
+ * // result2.source === '(Bob)\\s*abcdefg'
76
+ */
77
+ function replaceGroupWithLiteral(re, groupName, value, keepParentheses = false) {
78
+ let pat = (keepParentheses
79
+ ? `(?<=\\\()` + `\\\?<${groupName}>` + `(?=\\\))`
80
+ : `\\\(` + `\\\?<${groupName}>` + `\\\)`);
81
+ let groupPattern = new RegExp(pat);
82
+ if (!groupPattern.test(re.source)) { // re does not contain group
83
+ console.warn(`[regex.misc.replaceGroupWithLiteral()] re does not contain group '${groupName}'`);
84
+ return re;
85
+ }
86
+ let newSource = re.source.replace(groupPattern, value);
87
+ return new RegExp(newSource, re.flags);
88
+ }
@@ -40,6 +40,9 @@ export declare function stringContainsAnyOf(s: string, substrings: string | stri
40
40
  * - **`false`** `otherwise`.
41
41
  */
42
42
  export declare function equivalentAlphanumericStrings(s1: string, s2: string, tolerance?: number): boolean;
43
- /** for simple regular expressions...
44
- * so like not ones that have parentheses, pipes, or curly braced numbers */
43
+ /**
44
+ * @deprecated
45
+ * for simple regular expressions...
46
+ * so like not ones that have parentheses, pipes, or curly braced numbers
47
+ * */
45
48
  export declare function extractSource(regex: RegExp): string;
@@ -128,7 +128,7 @@ function stringContainsAnyOf(s, substrings, ...flags) {
128
128
  regex = new RegExp(substrings, flagString);
129
129
  }
130
130
  if (!regex) {
131
- config_1.typeshiLogger.warn('containsAnyOf() Invalid substrings type. returning false.', config_1.INDENT_LOG_LINE + `Expected string, array of strings, or RegExp, but received: ${typeof substrings}, ${substrings}`);
131
+ config_1.typeshiLogger.warn('[containsAnyOf()] Invalid substrings type. returning false.', config_1.INDENT_LOG_LINE + `Expected string, array of strings, or RegExp, but received: ${typeof substrings}, ${substrings}`);
132
132
  return false; // Invalid substrings type
133
133
  }
134
134
  return regex.test(s);
@@ -178,8 +178,11 @@ function equivalentAlphanumericStrings(s1, s2, tolerance = 0.90) {
178
178
  }
179
179
  return false;
180
180
  }
181
- /** for simple regular expressions...
182
- * so like not ones that have parentheses, pipes, or curly braced numbers */
181
+ /**
182
+ * @deprecated
183
+ * for simple regular expressions...
184
+ * so like not ones that have parentheses, pipes, or curly braced numbers
185
+ * */
183
186
  function extractSource(regex) {
184
187
  if (!regex)
185
188
  return '';
@@ -7,7 +7,7 @@
7
7
  * - **`true`** if `value` is an array and has at least one element,
8
8
  * - **`false`** otherwise.
9
9
  */
10
- export declare function isNonEmptyArray<T>(value: any): value is Array<T> & {
10
+ export declare function isNonEmptyArray<T>(value: unknown): value is Array<T> & {
11
11
  length: number;
12
12
  };
13
13
  /**
@@ -16,7 +16,7 @@ export declare function isNonEmptyArray<T>(value: any): value is Array<T> & {
16
16
  * - **`true`** if `value` is an array and has no elements,
17
17
  * - **`false`** `otherwise`
18
18
  */
19
- export declare function isEmptyArray<T>(value: any): value is Array<T> & {
19
+ export declare function isEmptyArray<T>(value: unknown): value is Array<T> & {
20
20
  length: 0;
21
21
  };
22
22
  /**
@@ -27,13 +27,12 @@ export declare function isEmptyArray<T>(value: any): value is Array<T> & {
27
27
  * - `if` `false` then `value` can be empty array
28
28
  * @returns **`isIntegerArray`** `boolean` = `value is number[] & { length: number }`
29
29
  */
30
- export declare function isIntegerArray(value: any, requireNonNegative?: boolean, requireNonEmpty?: boolean): value is number[] & {
30
+ export declare function isIntegerArray(value: unknown, requireNonNegative?: boolean, requireNonEmpty?: boolean): value is number[] & {
31
31
  length: number;
32
32
  };
33
33
  /**
34
- * @consideration add param to allow for empty strings?
35
34
  * @param value `any`
36
- * @param requireNonEmpty `boolean` `default = true`
35
+ * @param requireNonEmpty `boolean` `aka "requireNonEmptyArray"` `default = true`
37
36
  * - `if` `true` then `value` must be array with at least 1 element and every element `isNonEmptyString`
38
37
  * - `if` `false` then `value` can be empty array
39
38
  * @returns **`isStringArray`** `boolean` = `value is string[] & { length: number }`
@@ -41,40 +40,6 @@ export declare function isIntegerArray(value: any, requireNonNegative?: boolean,
41
40
  export declare function isStringArray(value: any, requireNonEmpty?: boolean): value is string[] & {
42
41
  length: number;
43
42
  };
44
- /**
45
- * `fka hasNonTrivialKeys`
46
- * @note **passing in an array will return `false`.**
47
- * @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
48
- * @param obj `any` The object to check.
49
- * @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
50
- * @returns **`hasNonTrivialEntries`** `boolean`
51
- * - **`true`** `if` the `obj` has non-empty keys,
52
- * - **`false`** `otherwise`
53
- */
54
- export declare function hasNonTrivialEntries<T extends object>(obj: T, requireAll?: boolean): obj is T;
55
- /**
56
- * @note uses `key in obj` for each element of param `keys`
57
- * @param obj `T extends Object` the object to check
58
- * @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
59
- * @param requireAll `boolean` defaults to `true`
60
- * - `if` `true`, all keys must be present in the object;
61
- * - `if` `false`, at least one key must be present
62
- * @param restrictKeys `boolean` defaults to `false`
63
- * - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
64
- * - `if` `false`, the object can keys not included in the `keys` param.
65
- * @returns **`hasKeys`** `boolean`
66
- * - **`true`** `if` `obj` is of type 'object' and has the required key(s),
67
- * - **`false`** `otherwise`
68
- */
69
- export declare function hasKeys<T extends object>(obj: T, keys: Array<keyof T> | string[] | string, requireAll?: boolean, restrictKeys?: boolean): boolean;
70
- /**
71
- * @param objA `Record<string, any>`
72
- * @param objB `Record<string, any>`
73
- * @returns **`areEquivalentObjects`** `boolean`
74
- * - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
75
- * - `false` `otherwise`.
76
- */
77
- export declare function areEquivalentObjects(objA: Record<string, any>, objB: Record<string, any>): boolean;
78
43
  /**
79
44
  * @param value `any`
80
45
  * @param requireInteger `boolean` `default = false`
@@ -116,7 +81,7 @@ export declare function isInteger(value: unknown, requireNonNegative?: boolean):
116
81
  * - `if` `false` then `value` is allowed to be an array
117
82
  * @returns **`isObject`** `boolean` `value is T`
118
83
  */
119
- export declare function isObject<T extends object = Record<string, any>>(value: unknown, requireNonEmpty?: boolean, requireNonArray?: boolean): value is T;
84
+ export declare function isObject<T extends object = Record<keyof any, any>>(value: unknown, requireNonEmpty?: boolean, requireNonArray?: boolean): value is T;
120
85
  export declare function isPositveInteger(value: unknown): value is number;
121
86
  export declare const isType: <T>(value: any, guard: (v: any, ...args: any[]) => v is T, ...args: any[]) => value is T;
122
87
  /**
@@ -243,30 +208,31 @@ export declare function isNull(value: unknown): value is null;
243
208
  */
244
209
  export declare function isUndefined(value: any): value is undefined;
245
210
  export declare function isUndefinedOrNull(value: unknown): value is undefined | null;
246
- export type NumberKeys<T, Required extends boolean = false> = {
247
- [K in keyof T]: Required extends true ? (T[K] extends number ? K : never) : (T[K] extends number | undefined ? K : never);
248
- }[keyof T][];
249
- export type ArrayKeys<T, Required extends boolean = false> = {
250
- [K in keyof T]: Required extends true ? (T[K] extends Array<any> ? K : never) : (T[K] extends Array<any> | undefined ? K : never);
251
- }[keyof T][];
252
- export type ArrayOfTypeKeys<T, U, Required extends boolean = false> = {
253
- [K in keyof T]: Required extends true ? (T[K] extends Array<U> ? K : never) : (T[K] extends Array<U> | undefined ? K : never);
254
- }[keyof T][];
255
- export type StringKeys<T, Required extends boolean = false> = {
256
- [K in keyof T]: Required extends true ? (T[K] extends string ? K : never) : (T[K] extends string | undefined ? K : never);
257
- }[keyof T][];
258
- export type PrimitiveKeys<T, Required extends boolean = false> = {
259
- [K in keyof T]: Required extends true ? (T[K] extends string | number | boolean | null ? K : never) : (T[K] extends string | number | boolean | null | undefined ? K : never);
260
- }[keyof T][];
261
- export type Primitive = string | number | boolean | null | undefined;
262
- /** Get the union of all values of `T` (like `valueof T`) */
263
- export type ValueOf<T> = T[keyof T];
264
211
  /**
265
- * Keys of `T` whose values extend a given type `U`
266
- * @template T - The object type
267
- * @template U - The type to check each `T[K]` against
268
- * @template Required - Whether the key is required (allows for `undefined` values if `false`) `default = false`
212
+ * @deprecated
213
+ * `fka hasNonTrivialKeys`
214
+ * @note **passing in an array will return `false`.**
215
+ * @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
216
+ * @param obj `any` The object to check.
217
+ * @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
218
+ * @returns **`hasNonTrivialEntries`** `boolean`
219
+ * - **`true`** `if` the `obj` has non-empty keys,
220
+ * - **`false`** `otherwise`
221
+ */
222
+ export declare function hasNonTrivialEntries<T extends object>(obj: T, requireAll?: boolean): obj is T;
223
+ /**
224
+ * @deprecated
225
+ * @note uses `key in obj` for each element of param `keys`
226
+ * @param obj `T extends Object` the object to check
227
+ * @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
228
+ * @param requireAll `boolean` defaults to `true`
229
+ * - `if` `true`, all keys must be present in the object;
230
+ * - `if` `false`, at least one key must be present
231
+ * @param restrictKeys `boolean` defaults to `false`
232
+ * - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
233
+ * - `if` `false`, the object can keys not included in the `keys` param.
234
+ * @returns **`hasKeys`** `boolean`
235
+ * - **`true`** `if` `obj` is of type 'object' and has the required key(s),
236
+ * - **`false`** `otherwise`
269
237
  */
270
- export type KeysOfType<T, U, Required extends boolean = false> = {
271
- [K in keyof T]: Required extends true ? (T[K] extends U ? K : never) : (T[K] extends U | undefined ? K : never);
272
- }[keyof T][];
238
+ export declare function hasKeys<T extends object = any>(obj: T, keys: Array<keyof T> | string[] | string, requireAll?: boolean, restrictKeys?: boolean): boolean;
@@ -8,9 +8,6 @@ exports.isNonEmptyArray = isNonEmptyArray;
8
8
  exports.isEmptyArray = isEmptyArray;
9
9
  exports.isIntegerArray = isIntegerArray;
10
10
  exports.isStringArray = isStringArray;
11
- exports.hasNonTrivialEntries = hasNonTrivialEntries;
12
- exports.hasKeys = hasKeys;
13
- exports.areEquivalentObjects = areEquivalentObjects;
14
11
  exports.isNumeric = isNumeric;
15
12
  exports.isNonEmptyString = isNonEmptyString;
16
13
  exports.isPrimitiveValue = isPrimitiveValue;
@@ -23,7 +20,8 @@ exports.isFunction = isFunction;
23
20
  exports.isNull = isNull;
24
21
  exports.isUndefined = isUndefined;
25
22
  exports.isUndefinedOrNull = isUndefinedOrNull;
26
- const index_1 = require("./regex/index");
23
+ exports.hasNonTrivialEntries = hasNonTrivialEntries;
24
+ exports.hasKeys = hasKeys;
27
25
  /**
28
26
  * @param value
29
27
  * @returns **`isNonEmptyArray`** `boolean` = `value is Array<T> & { length: number }`
@@ -55,10 +53,10 @@ function isIntegerArray(value, requireNonNegative = false, requireNonEmpty = tru
55
53
  ? isNonEmptyArray(value) && value.every(el => isInteger(el, requireNonNegative))
56
54
  : isEmptyArray(value));
57
55
  }
56
+ // * @consideration add param to allow for empty strings?
58
57
  /**
59
- * @consideration add param to allow for empty strings?
60
58
  * @param value `any`
61
- * @param requireNonEmpty `boolean` `default = true`
59
+ * @param requireNonEmpty `boolean` `aka "requireNonEmptyArray"` `default = true`
62
60
  * - `if` `true` then `value` must be array with at least 1 element and every element `isNonEmptyString`
63
61
  * - `if` `false` then `value` can be empty array
64
62
  * @returns **`isStringArray`** `boolean` = `value is string[] & { length: number }`
@@ -68,103 +66,6 @@ function isStringArray(value, requireNonEmpty = true) {
68
66
  ? isNonEmptyArray(value) && value.every(el => isNonEmptyString(el))
69
67
  : isEmptyArray(value));
70
68
  }
71
- // maybe deprecate this
72
- /**
73
- * `fka hasNonTrivialKeys`
74
- * @note **passing in an array will return `false`.**
75
- * @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
76
- * @param obj `any` The object to check.
77
- * @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
78
- * @returns **`hasNonTrivialEntries`** `boolean`
79
- * - **`true`** `if` the `obj` has non-empty keys,
80
- * - **`false`** `otherwise`
81
- */
82
- function hasNonTrivialEntries(obj, requireAll = false) {
83
- if (!isObject(obj)) {
84
- return false;
85
- }
86
- return (requireAll
87
- ? Object.values(obj).every(v => !isEmpty(v))
88
- : Object.values(obj).some(v => !isEmpty(v)));
89
- }
90
- // @TODO add overload on param `keys` where keys = `{ required: string[], optional: string[] }`
91
- // maybe deprecate this
92
- /**
93
- * @note uses `key in obj` for each element of param `keys`
94
- * @param obj `T extends Object` the object to check
95
- * @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
96
- * @param requireAll `boolean` defaults to `true`
97
- * - `if` `true`, all keys must be present in the object;
98
- * - `if` `false`, at least one key must be present
99
- * @param restrictKeys `boolean` defaults to `false`
100
- * - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
101
- * - `if` `false`, the object can keys not included in the `keys` param.
102
- * @returns **`hasKeys`** `boolean`
103
- * - **`true`** `if` `obj` is of type 'object' and has the required key(s),
104
- * - **`false`** `otherwise`
105
- */
106
- function hasKeys(obj, keys, requireAll = true, restrictKeys = false) {
107
- if (!obj || typeof obj !== 'object') {
108
- return false;
109
- }
110
- if (keys === null || keys === undefined) {
111
- return false;
112
- }
113
- if (!isNonEmptyArray(keys)) {
114
- keys = [keys]; // Convert string (assumed to be single key) to array of keys
115
- }
116
- let numKeysFound = 0;
117
- for (const key of keys) {
118
- if (key in obj) {
119
- numKeysFound++;
120
- if (!requireAll && !restrictKeys) {
121
- return true;
122
- }
123
- }
124
- else if (requireAll) { // and a key is not found
125
- return false;
126
- }
127
- }
128
- if (restrictKeys) {
129
- // If restrictKeys is true, check that no other keys are present in the object
130
- const objKeys = Object.keys(obj);
131
- const extraKeys = objKeys.filter(k => !keys.includes(k));
132
- if (extraKeys.length > 0) {
133
- return false; // Found keys not in the allowed list
134
- }
135
- }
136
- return requireAll ? numKeysFound === keys.length : numKeysFound > 0;
137
- }
138
- /**
139
- * @param objA `Record<string, any>`
140
- * @param objB `Record<string, any>`
141
- * @returns **`areEquivalentObjects`** `boolean`
142
- * - `true` `if` `objA` and `objB` are equivalent objects (same keys and values, including nested objects and arrays),
143
- * - `false` `otherwise`.
144
- */
145
- function areEquivalentObjects(objA, objB) {
146
- if (!objA || typeof objA !== 'object' || !objB || typeof objB !== 'object') {
147
- return false;
148
- }
149
- const keysA = Object.keys(objA);
150
- const keysB = Object.keys(objB);
151
- if (keysA.length !== keysB.length)
152
- return false;
153
- return keysA.every(key => {
154
- if (!hasKeys(objB, key))
155
- return false; // key not in both objects
156
- const valA = objA[key];
157
- const valB = objB[key];
158
- if (Array.isArray(valA) && Array.isArray(valB)) {
159
- return valA.length === valB.length
160
- && valA.every((item) => valB.includes(item));
161
- }
162
- else if (typeof valA === "object" && valA && typeof valB === "object" && valB) {
163
- return areEquivalentObjects(valA, valB);
164
- }
165
- return (0, index_1.equivalentAlphanumericStrings)(valA, valB);
166
- });
167
- }
168
69
  /**
169
70
  * @param value `any`
170
71
  * @param requireInteger `boolean` `default = false`
@@ -209,7 +110,7 @@ function isNumeric(value, requireInteger = false, requireNonNegative = false) {
209
110
  function isNonEmptyString(value, requireNonSpace = false) {
210
111
  return (typeof value === 'string'
211
112
  && (requireNonSpace
212
- ? value.trim() !== ''
113
+ ? value.trim() !== '' // Boolean(value.trim())
213
114
  : value.length > 0));
214
115
  }
215
116
  function isPrimitiveValue(value) {
@@ -456,3 +357,69 @@ function isUndefined(value) {
456
357
  function isUndefinedOrNull(value) {
457
358
  return value === undefined || value === null;
458
359
  }
360
+ /**
361
+ * @deprecated
362
+ * `fka hasNonTrivialKeys`
363
+ * @note **passing in an array will return `false`.**
364
+ * @note a value is considered trivial if {@link isEmpty}`(value)` returns `true` and vice versa
365
+ * @param obj `any` The object to check.
366
+ * @param requireAll `boolean` - flag indicating whether all values must be nontrivial or not
367
+ * @returns **`hasNonTrivialEntries`** `boolean`
368
+ * - **`true`** `if` the `obj` has non-empty keys,
369
+ * - **`false`** `otherwise`
370
+ */
371
+ function hasNonTrivialEntries(obj, requireAll = false) {
372
+ if (!isObject(obj)) {
373
+ return false;
374
+ }
375
+ return (requireAll
376
+ ? Object.values(obj).every(v => !isEmpty(v))
377
+ : Object.values(obj).some(v => !isEmpty(v)));
378
+ }
379
+ /**
380
+ * @deprecated
381
+ * @note uses `key in obj` for each element of param `keys`
382
+ * @param obj `T extends Object` the object to check
383
+ * @param keys `Array<keyof T> | string[] | string` the list of keys that obj must have
384
+ * @param requireAll `boolean` defaults to `true`
385
+ * - `if` `true`, all keys must be present in the object;
386
+ * - `if` `false`, at least one key must be present
387
+ * @param restrictKeys `boolean` defaults to `false`
388
+ * - `if` `true`, only the keys provided in the `keys` param are allowed in the object;
389
+ * - `if` `false`, the object can keys not included in the `keys` param.
390
+ * @returns **`hasKeys`** `boolean`
391
+ * - **`true`** `if` `obj` is of type 'object' and has the required key(s),
392
+ * - **`false`** `otherwise`
393
+ */
394
+ function hasKeys(obj, keys, requireAll = true, restrictKeys = false) {
395
+ if (!obj || typeof obj !== 'object') {
396
+ return false;
397
+ }
398
+ if (keys === null || keys === undefined) {
399
+ return false;
400
+ }
401
+ if (!isNonEmptyArray(keys)) {
402
+ keys = [keys]; // Convert string (assumed to be single key) to array of keys
403
+ }
404
+ let numKeysFound = 0;
405
+ for (const key of keys) {
406
+ if (key in obj) {
407
+ numKeysFound++;
408
+ if (!requireAll && !restrictKeys) {
409
+ return true;
410
+ }
411
+ }
412
+ else if (requireAll) { // and a key is not found
413
+ return false;
414
+ }
415
+ }
416
+ if (restrictKeys) {
417
+ // If restrictKeys is true, check that no other keys are present in the object
418
+ const objKeys = Object.keys(obj);
419
+ const extraKeys = objKeys.filter(k => !keys.includes(k));
420
+ if (extraKeys.length > 0) {
421
+ return false; // Found keys not in the allowed list
422
+ }
423
+ }
424
+ return requireAll ? numKeysFound === keys.length : numKeysFound > 0;
425
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @file src/utils/utilityTypes.ts
3
+ */
4
+ /**
5
+ * @template Required - Whether the key is required
6
+ * (allows for `K` where `T[K]` can be `undefined` if `false`)
7
+ * - `default = false`
8
+ */
9
+ export type NumberKeys<T, Required extends boolean = false> = Exclude<{
10
+ [K in keyof T]: Required extends true ? (T[K] extends number ? K : never) : (T[K] extends number | undefined ? K : never);
11
+ }[keyof T], undefined>[];
12
+ /**
13
+ * @template Required - Whether the key is required
14
+ * (allows for `K` where `T[K]` can be `undefined` if `false`)
15
+ * - `default = false`
16
+ */
17
+ export type ArrayKeys<T, Required extends boolean = false> = Exclude<{
18
+ [K in keyof T]: Required extends true ? (T[K] extends Array<any> ? K : never) : (T[K] extends Array<any> | undefined ? K : never);
19
+ }[keyof T], undefined>[];
20
+ /**
21
+ * @template Required - Whether the key is required
22
+ * (allows for `K` where `T[K]` can be `undefined` if `false`)
23
+ * - `default = false`
24
+ */
25
+ export type ArrayOfTypeKeys<T, U, Required extends boolean = false> = Exclude<{
26
+ [K in keyof T]: Required extends true ? (T[K] extends Array<U> ? K : never) : (T[K] extends Array<U> | undefined ? K : never);
27
+ }[keyof T], undefined>[];
28
+ /**
29
+ * @template Required - Whether the key is required
30
+ * (allows for `K` where `T[K]` can be `undefined` if `false`)
31
+ * - `default = false`
32
+ */
33
+ export type StringKeys<T, Required extends boolean = false> = Exclude<{
34
+ [K in keyof T]: Required extends true ? (T[K] extends string ? K : never) : (T[K] extends string | undefined ? K : never);
35
+ }[keyof T], undefined>[];
36
+ /**
37
+ * @template Required - Whether the key is required
38
+ * (allows for `K` where `T[K]` can be `undefined` if `false`)
39
+ * - `default = false`
40
+ */
41
+ export type PrimitiveKeys<T, Required extends boolean = false> = Exclude<{
42
+ [K in keyof T]: Required extends true ? (T[K] extends string | number | boolean | null ? K : never) : (T[K] extends string | number | boolean | null | undefined ? K : never);
43
+ }[keyof T], undefined>[];
44
+ export type Primitive = string | number | boolean | null | undefined;
45
+ /** Get the union of all values of `T` (like `valueof T`) */
46
+ export type ValueOf<T> = T extends object ? T[keyof T] : T;
47
+ /**
48
+ * Keys of `T` whose values extend a given type `U`
49
+ * @template T - The object type
50
+ * @template U - The type to check each `T[K]` against
51
+ * @template Required - Whether the key is required
52
+ * (allows for `K` where `T[K]` can be `undefined` if `false`)
53
+ * - `default = false`
54
+ * */
55
+ export type KeysOfType<T, U, Required extends boolean = false> = Exclude<{
56
+ [K in keyof T]: Required extends true ? (T[K] extends U ? K : never) : (T[K] extends U | undefined ? K : never);
57
+ }[keyof T], undefined>[];
58
+ /**
59
+ * use for non-strict autocomplete of enum/literal value types
60
+ * @example
61
+ * JobPlatformEnum = { GREENHOUSE: 'GREENHOUSE', WORKDAY: 'WORKDAY' } as const;
62
+ * type JobPlatformEnum = (typeof JobPlatformEnum)[keyof typeof JobPlatformEnum]; // 'GREENHOUSE' | 'WORKDAY'
63
+ * let key: NonStrict<JobPlatformEnum>; // allows any string, but will have the enum values as suggested auto-complete values
64
+ * key = 'hello'; // ok
65
+ * key = 9; // Error: Type '9' is not assignable to type 'NonStrict<JobPlatformEnum>'
66
+ * */
67
+ export type NonStrict<T extends string | number> = T | (T extends string ? (string & {}) : (number & {}));
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ /**
3
+ * @file src/utils/utilityTypes.ts
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typeshi",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "description": "TypeScript utility modules",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",