@gesslar/toolkit 0.0.8 → 0.0.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gesslar/toolkit",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "Get in, bitches, we're going toolkitting.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -21,9 +21,18 @@
21
21
  },
22
22
  "scripts": {
23
23
  "lint": "eslint src/",
24
+ "lint:docs": "cd docs && npm run lint",
25
+ "lint:fix": "eslint src/ --fix",
26
+ "lint:fix:docs": "cd docs && npm run lint:fix",
24
27
  "submit": "npm publish --access public",
25
28
  "update": "npx npm-check-updates -u && npm install",
26
- "test": "node examples/FileSystem/index.js"
29
+ "test": "node examples/FileSystem/index.js",
30
+ "docs:dev": "npm run docs:build && cd docs && npm run start",
31
+ "docs:build": "npm run docs:clean && npm run docs:generate && cd docs && npm run build",
32
+ "docs:serve": "cd docs && npm run serve",
33
+ "docs:clean": "cd docs && npm run docs:clean",
34
+ "docs:generate": "npx typedoc src/types/index.d.ts --out docs/docs/api --plugin typedoc-plugin-markdown --readme none --excludePrivate --excludeProtected --excludeInternal --includeVersion",
35
+ "docs:install": "cd docs && npm install"
27
36
  },
28
37
  "repository": {
29
38
  "type": "git",
@@ -57,6 +66,8 @@
57
66
  "@typescript-eslint/eslint-plugin": "^8.44.0",
58
67
  "@typescript-eslint/parser": "^8.44.0",
59
68
  "eslint": "^9.36.0",
60
- "eslint-plugin-jsdoc": "^60.1.0"
69
+ "eslint-plugin-jsdoc": "^60.1.0",
70
+ "typedoc": "^0.28.13",
71
+ "typedoc-plugin-markdown": "^4.9.0"
61
72
  }
62
73
  }
package/src/lib/File.js CHANGED
@@ -225,15 +225,15 @@ export default class File {
225
225
  /**
226
226
  * Lists the contents of a directory.
227
227
  *
228
- * @param {string} directory - The directory to list.
228
+ * @param {DirectoryObject} directory - The directory to list.
229
229
  * @returns {Promise<{files: Array<FileObject>, directories: Array<DirectoryObject>}>} The files and
230
230
  * directories in the directory.
231
231
  */
232
232
  static async ls(directory) {
233
- const found = await fs.readdir(directory, {withFileTypes: true})
233
+ const found = await fs.readdir(directory.uri, {withFileTypes: true})
234
234
  const results = await Promise.all(
235
235
  found.map(async dirent => {
236
- const fullPath = path.join(directory, dirent.name)
236
+ const fullPath = path.join(directory.uri, dirent.name)
237
237
  const stat = await fs.stat(fullPath)
238
238
 
239
239
  return {dirent, stat, fullPath}
package/src/lib/Glog.js CHANGED
@@ -107,6 +107,19 @@ class Glog {
107
107
  }
108
108
  }
109
109
 
110
+ /**
111
+ * Global logging utility with proxy-based dual interface.
112
+ * Can be used as both a class and a function for maximum flexibility.
113
+ *
114
+ * @class Glog
115
+ * @example
116
+ * // Use as function
117
+ * Glog('Hello world')
118
+ * Glog(2, 'Debug message')
119
+ *
120
+ * // Use class methods
121
+ * Glog.setLogLevel(3).setLogPrefix('[App]')
122
+ */
110
123
  // Wrap the class in a proxy
111
124
  export default new Proxy(Glog, {
112
125
  apply(target, thisArg, argumentsList) {
@@ -19,16 +19,164 @@ export default class Data {
19
19
  /** Array of type names that can be checked for emptiness */
20
20
  static readonly emptyableTypes: ReadonlyArray<string>
21
21
 
22
- /** Append a string if it doesn't already end with it */
22
+ /**
23
+ * Append a suffix string to the end of a string if it doesn't already end with it.
24
+ *
25
+ * Useful for ensuring strings have consistent endings like file extensions,
26
+ * URL paths, or punctuation. Performs case-sensitive comparison and only appends
27
+ * if the string doesn't already end with the specified suffix.
28
+ *
29
+ * @param string - The base string to potentially append to. Can be empty string.
30
+ * @param append - The suffix to append if not already present. Cannot be empty.
31
+ * @returns The string with the suffix appended, or the original string if suffix already present
32
+ *
33
+ * @throws {Error} When append parameter is empty or undefined
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * import { Data } from '@gesslar/toolkit'
38
+ *
39
+ * // Basic usage with file extensions
40
+ * const filename = Data.appendString('config', '.json')
41
+ * console.log(filename) // 'config.json'
42
+ *
43
+ * // No double-appending
44
+ * const alreadyHasExt = Data.appendString('package.json', '.json')
45
+ * console.log(alreadyHasExt) // 'package.json' (unchanged)
46
+ *
47
+ * // URL path handling
48
+ * const apiPath = Data.appendString('/api/users', '/')
49
+ * console.log(apiPath) // '/api/users/'
50
+ *
51
+ * // Works with empty strings
52
+ * const fromEmpty = Data.appendString('', '.txt')
53
+ * console.log(fromEmpty) // '.txt'
54
+ * ```
55
+ */
23
56
  static appendString(string: string, append: string): string
24
57
 
25
- /** Prepend a string if it doesn't already start with it */
58
+ /**
59
+ * Prepend a prefix string to the beginning of a string if it doesn't already start with it.
60
+ *
61
+ * Useful for ensuring strings have consistent beginnings like protocol prefixes,
62
+ * path separators, or formatting markers. Performs case-sensitive comparison and
63
+ * only prepends if the string doesn't already start with the specified prefix.
64
+ *
65
+ * @param string - The base string to potentially prepend to. Can be empty string.
66
+ * @param prepend - The prefix to prepend if not already present. Cannot be empty.
67
+ * @returns The string with the prefix prepended, or the original string if prefix already present
68
+ *
69
+ * @throws {Error} When prepend parameter is empty or undefined
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { Data } from '@gesslar/toolkit'
74
+ *
75
+ * // Basic usage with protocols
76
+ * const url = Data.prependString('example.com', 'https://')
77
+ * console.log(url) // 'https://example.com'
78
+ *
79
+ * // No double-prepending
80
+ * const alreadyHasProtocol = Data.prependString('https://api.example.com', 'https://')
81
+ * console.log(alreadyHasProtocol) // 'https://api.example.com' (unchanged)
82
+ *
83
+ * // File path handling
84
+ * const absolutePath = Data.prependString('home/user/docs', '/')
85
+ * console.log(absolutePath) // '/home/user/docs'
86
+ *
87
+ * // CSS class prefixing
88
+ * const className = Data.prependString('button-primary', 'css-')
89
+ * console.log(className) // 'css-button-primary'
90
+ * ```
91
+ */
26
92
  static prependString(string: string, prepend: string): string
27
93
 
28
- /** Check if all elements in an array are of a specified type */
94
+ /**
95
+ * Check if all elements in an array are of a specified type or all the same type.
96
+ *
97
+ * Performs type checking on every element in the array using the toolkit's type
98
+ * system. If no type is specified, checks that all elements are of the same type.
99
+ * Useful for validating data structures and ensuring type consistency before processing.
100
+ *
101
+ * @param arr - The array to check for type uniformity. Can be empty (returns true).
102
+ * @param type - Optional type name to check against. If not provided, checks that all
103
+ * elements have the same type. Must be a valid type from Data.dataTypes.
104
+ * @returns True if all elements match the specified type or are all the same type,
105
+ * false if there's any type mismatch or if type parameter is invalid
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * import { Data } from '@gesslar/toolkit'
110
+ *
111
+ * // Check for specific type uniformity
112
+ * const numbers = [1, 2, 3, 4, 5]
113
+ * const strings = ['a', 'b', 'c']
114
+ * const mixed = [1, 'a', true]
115
+ *
116
+ * console.log(Data.isArrayUniform(numbers, 'number')) // true
117
+ * console.log(Data.isArrayUniform(strings, 'string')) // true
118
+ * console.log(Data.isArrayUniform(mixed, 'number')) // false
119
+ *
120
+ * // Check that all elements are the same type (any type)
121
+ * console.log(Data.isArrayUniform(numbers)) // true (all numbers)
122
+ * console.log(Data.isArrayUniform(strings)) // true (all strings)
123
+ * console.log(Data.isArrayUniform(mixed)) // false (mixed types)
124
+ * console.log(Data.isArrayUniform([])) // true (empty array)
125
+ *
126
+ * // Useful for validation before processing
127
+ * function processNumbers(data: unknown[]) {
128
+ * if (!Data.isArrayUniform(data, 'number')) {
129
+ * throw new Error('Array must contain only numbers')
130
+ * }
131
+ * return data.reduce((sum, num) => sum + num, 0)
132
+ * }
133
+ * ```
134
+ */
29
135
  static isArrayUniform(arr: Array<unknown>, type?: string): boolean
30
136
 
31
- /** Remove duplicates from an array */
137
+ /**
138
+ * Remove duplicate elements from an array, returning a new array with unique values.
139
+ *
140
+ * Creates a new array containing only the first occurrence of each unique value,
141
+ * preserving the original order of first appearances. Uses strict equality (===)
142
+ * for primitive comparisons and shallow comparison for objects.
143
+ *
144
+ * @param arr - The array to remove duplicates from. Can be empty or contain any types.
145
+ * @returns A new array with duplicate elements removed, preserving order of first occurrence
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * import { Data } from '@gesslar/toolkit'
150
+ *
151
+ * // Basic duplicate removal
152
+ * const numbers = [1, 2, 2, 3, 3, 4]
153
+ * const uniqueNumbers = Data.isArrayUnique(numbers)
154
+ * console.log(uniqueNumbers) // [1, 2, 3, 4]
155
+ *
156
+ * // Mixed types
157
+ * const mixed = ['a', 1, 'a', 2, 1, 'b']
158
+ * const uniqueMixed = Data.isArrayUnique(mixed)
159
+ * console.log(uniqueMixed) // ['a', 1, 2, 'b']
160
+ *
161
+ * // Object arrays (shallow comparison)
162
+ * const users = [
163
+ * { id: 1, name: 'Alice' },
164
+ * { id: 2, name: 'Bob' },
165
+ * { id: 1, name: 'Alice' } // Different object reference, not filtered
166
+ * ]
167
+ * const uniqueUsers = Data.isArrayUnique(users)
168
+ * console.log(uniqueUsers.length) // 3 (objects compared by reference)
169
+ *
170
+ * // Empty and single element arrays
171
+ * console.log(Data.isArrayUnique([])) // []
172
+ * console.log(Data.isArrayUnique(['single'])) // ['single']
173
+ *
174
+ * // String array deduplication
175
+ * const tags = ['javascript', 'node', 'javascript', 'typescript', 'node']
176
+ * const uniqueTags = Data.isArrayUnique(tags)
177
+ * console.log(uniqueTags) // ['javascript', 'node', 'typescript']
178
+ * ```
179
+ */
32
180
  static isArrayUnique<T>(arr: Array<T>): Array<T>
33
181
 
34
182
  /** Get the intersection of two arrays */
@@ -58,7 +58,7 @@ export default class File {
58
58
  static getFiles(glob: string | Array<string>): Promise<Array<FileObject>>
59
59
 
60
60
  /** List the contents of a directory */
61
- static ls(directory: string): Promise<DirectoryListing>
61
+ static ls(directory: DirectoryObject): Promise<DirectoryListing>
62
62
 
63
63
  /** Read the content of a file */
64
64
  static readFile(fileObject: FileObject): Promise<string>
@@ -74,4 +74,4 @@ export default class File {
74
74
 
75
75
  /** Compute relative path between two file system objects */
76
76
  static relativeOrAbsolutePath(from: FileObject | DirectoryObject, to: FileObject | DirectoryObject): string
77
- }
77
+ }
@@ -1,48 +1,281 @@
1
1
  // Implementation: ../lib/FileObject.js
2
- // Type definitions for FileObject
3
2
 
4
3
  import DirectoryObject from './DirectoryObject.js'
5
4
 
6
5
  /**
7
- * FileObject encapsulates metadata and operations for a file, including path
8
- * resolution and existence checks.
6
+ * FileObject encapsulates metadata and operations for a file, providing intelligent
7
+ * path resolution, metadata extraction, and file system operations. This class serves
8
+ * as the primary abstraction for file handling in the toolkit.
9
+ *
10
+ * FileObject automatically resolves relative paths, provides rich metadata without
11
+ * requiring file system access, and integrates seamlessly with DirectoryObject for
12
+ * hierarchical file operations. The class uses lazy evaluation for expensive operations
13
+ * and provides both synchronous metadata access and asynchronous file operations.
14
+ *
15
+ * Key features include automatic path normalization, extension parsing, URI generation,
16
+ * and parent directory integration. All path operations are cross-platform compatible.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { FileObject } from '@gesslar/toolkit'
21
+ *
22
+ * // Basic file creation and metadata access
23
+ * const config = new FileObject('./config.json')
24
+ * console.log('Name:', config.name) // 'config.json'
25
+ * console.log('Module:', config.module) // 'config' (without extension)
26
+ * console.log('Extension:', config.extension) // '.json'
27
+ * console.log('Path:', config.path) // '/absolute/path/to/config.json'
28
+ * console.log('URI:', config.uri) // 'file:///absolute/path/to/config.json'
29
+ *
30
+ * // Working with different directory contexts
31
+ * const srcDir = new DirectoryObject('./src')
32
+ * const indexFile = new FileObject('index.js', srcDir)
33
+ * const componentFile = new FileObject('components/Button.tsx', './src')
34
+ *
35
+ * // File existence and operations
36
+ * if (await config.exists) {
37
+ * console.log('Config file exists')
38
+ * // File operations would go here using File utility
39
+ * } else {
40
+ * console.log('Config file not found at:', config.path)
41
+ * }
42
+ *
43
+ * // Integration with parent directory
44
+ * console.log('Parent directory:', indexFile.directory.path)
45
+ * console.log('Is in src?', indexFile.directory.name === 'src')
46
+ * ```
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * // Advanced usage with different file types and paths
51
+ * import { FileObject, DirectoryObject } from '@gesslar/toolkit'
52
+ *
53
+ * // Handle various file extensions and types
54
+ * const files = [
55
+ * new FileObject('./docs/README.md'),
56
+ * new FileObject('package.json'),
57
+ * new FileObject('../lib/utils.ts'),
58
+ * new FileObject('/absolute/path/to/script.sh')
59
+ * ]
60
+ *
61
+ * for (const fileItem of files) {
62
+ * console.log(`${fileItem.module}${fileItem.extension} -> ${fileItem.path}`)
63
+ *
64
+ * // Type-based processing
65
+ * switch (fileItem.extension) {
66
+ * case '.json':
67
+ * console.log('JSON file detected')
68
+ * break
69
+ * case '.md':
70
+ * console.log('Markdown documentation')
71
+ * break
72
+ * case '.ts':
73
+ * case '.js':
74
+ * console.log('JavaScript/TypeScript source')
75
+ * break
76
+ * default:
77
+ * console.log('Other file type')
78
+ * }
79
+ * }
80
+ *
81
+ * // Error handling for invalid paths
82
+ * try {
83
+ * const badFile = new FileObject('') // Empty path
84
+ * } catch (error) {
85
+ * console.error('Invalid file path:', error.message)
86
+ * }
87
+ * ```
88
+ *
89
+ * @remarks
90
+ * FileObject is designed for metadata extraction and path operations. For actual
91
+ * file I/O operations (reading, writing, copying), use the File utility class
92
+ * which accepts FileObject instances as parameters.
93
+ *
94
+ * The `exists` property returns a Promise and should always be awaited. Path
95
+ * resolution happens synchronously during construction, making metadata access
96
+ * immediate and efficient.
97
+ *
98
+ * When working with DirectoryObject parents, the FileObject automatically
99
+ * inherits the directory's resolved path, ensuring consistency in hierarchical
100
+ * file operations.
9
101
  */
10
102
  export default class FileObject {
11
103
  /**
12
- * Create a new FileObject instance.
13
- * @param fileName - The file path
14
- * @param directory - The parent directory (object or string)
104
+ * Create a new FileObject instance with intelligent path resolution.
105
+ *
106
+ * Constructs a FileObject from the provided filename and optional directory context.
107
+ * Automatically resolves relative paths to absolute paths, normalizes path separators
108
+ * for cross-platform compatibility, and establishes parent-child relationships with
109
+ * DirectoryObject instances.
110
+ *
111
+ * @param fileName - The file path, which can be relative or absolute. Empty strings
112
+ * and invalid paths will throw an error during construction.
113
+ * @param directory - Optional parent directory context. Can be a DirectoryObject instance,
114
+ * a string path that will be converted to a DirectoryObject, or null
115
+ * to use the current working directory as the parent.
116
+ *
117
+ * @throws {Error} When fileName is empty or contains invalid path characters
118
+ * @throws {Error} When the directory parameter is invalid or cannot be resolved
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * // Simple file in current directory - most common usage
123
+ * const packageJson = new FileObject('package.json')
124
+ * const readme = new FileObject('./README.md') // Equivalent to above
125
+ *
126
+ * // File with string directory path
127
+ * const configFile = new FileObject('app.config.js', './config')
128
+ * const componentFile = new FileObject('Button.tsx', './src/components')
129
+ *
130
+ * // File with DirectoryObject parent for hierarchical operations
131
+ * const srcDir = new DirectoryObject('./src')
132
+ * const indexFile = new FileObject('index.js', srcDir)
133
+ * const utilsFile = new FileObject('utils/helpers.js', srcDir)
134
+ *
135
+ * // Absolute paths (directory parameter ignored)
136
+ * const systemFile = new FileObject('/etc/hosts')
137
+ * const winFile = new FileObject('C:\\Windows\\System32\\drivers\\etc\\hosts')
138
+ * ```
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * // Complex directory structures and nested files
143
+ * const projectRoot = new DirectoryObject('./my-project')
144
+ * const srcDir = new DirectoryObject('src', projectRoot)
145
+ *
146
+ * // Create files within nested directory structure
147
+ * const mainApp = new FileObject('App.tsx', srcDir)
148
+ * const stylesheet = new FileObject('styles/main.css', srcDir)
149
+ * const testFile = new FileObject('__tests__/App.test.tsx', srcDir)
150
+ *
151
+ * console.log('Main app:', mainApp.path) // /absolute/path/my-project/src/App.tsx
152
+ * console.log('Stylesheet:', stylesheet.path) // /absolute/path/my-project/src/styles/main.css
153
+ * console.log('Test file:', testFile.path) // /absolute/path/my-project/src/__tests__/App.test.tsx
154
+ *
155
+ * // All files share the same parent directory reference
156
+ * console.log('Same parent?', mainApp.directory === srcDir) // true
157
+ * ```
15
158
  */
16
159
  constructor(fileName: string, directory?: DirectoryObject | string | null)
17
160
 
18
- /** User-supplied path */
161
+ /**
162
+ * The original user-supplied path string used during construction.
163
+ *
164
+ * Preserves the exact path string passed to the constructor, including
165
+ * any relative path indicators (./, ../) or path separators. Useful
166
+ * for debugging, logging, or when you need to recreate the original
167
+ * user input.
168
+ *
169
+ * @example
170
+ * ```typescript
171
+ * const file1 = new FileObject('./config.json')
172
+ * const file2 = new FileObject('../package.json')
173
+ *
174
+ * console.log(file1.supplied) // './config.json'
175
+ * console.log(file2.supplied) // '../package.json'
176
+ * console.log(file1.path) // '/absolute/path/to/config.json'
177
+ * console.log(file2.path) // '/absolute/path/package.json'
178
+ * ```
179
+ */
19
180
  readonly supplied: string
20
181
 
21
- /** The absolute file path */
182
+ /**
183
+ * The fully resolved absolute file path with normalized separators.
184
+ *
185
+ * Automatically resolved during construction using Node.js path utilities.
186
+ * Always uses forward slashes on Unix systems and backslashes on Windows.
187
+ * This is the canonical path that should be used for all file operations.
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * // Different inputs, same resolved path
192
+ * const file1 = new FileObject('./src/../config.json')
193
+ * const file2 = new FileObject('config.json')
194
+ *
195
+ * console.log(file1.path) // '/absolute/path/config.json'
196
+ * console.log(file2.path) // '/absolute/path/config.json'
197
+ * console.log(file1.path === file2.path) // true
198
+ * ```
199
+ */
22
200
  readonly path: string
23
201
 
24
- /** The file URI */
202
+ /**
203
+ * The file URI representation following RFC 3986 standard.
204
+ *
205
+ * Converts the absolute file path to a proper file:// URI scheme,
206
+ * handling URL encoding for special characters and proper formatting
207
+ * for cross-platform file URI access.
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * const file = new FileObject('./my project/config file.json')
212
+ * console.log(file.uri)
213
+ * // 'file:///absolute/path/my%20project/config%20file.json'
214
+ *
215
+ * // Can be used with URL constructor or file:// handlers
216
+ * const url = new URL(file.uri)
217
+ * console.log(url.pathname) // '/absolute/path/my project/config file.json'
218
+ * ```
219
+ */
25
220
  readonly uri: string
26
221
 
27
- /** The file name */
222
+ /**
223
+ * The complete filename including extension.
224
+ *
225
+ * Extracted from the resolved path using Node.js path utilities.
226
+ * Includes the file extension but excludes any directory components.
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * const jsFile = new FileObject('./src/components/Button.tsx')
231
+ * const configFile = new FileObject('../.env.production')
232
+ *
233
+ * console.log(jsFile.name) // 'Button.tsx'
234
+ * console.log(configFile.name) // '.env.production'
235
+ * ```
236
+ */
28
237
  readonly name: string
29
238
 
30
- /** The file name without extension */
239
+ /**
240
+ * The filename without its extension, suitable for module identification.
241
+ *
242
+ * Useful for generating module names, import statements, or when you need
243
+ * the base name without file type information. Handles complex extensions
244
+ * and dotfiles appropriately.
245
+ */
31
246
  readonly module: string
32
247
 
33
- /** The file extension */
248
+ /**
249
+ * The file extension including the leading dot.
250
+ *
251
+ * Extracted using Node.js path utilities, always includes the dot prefix.
252
+ * Returns an empty string for files without extensions. Handles multiple
253
+ * extensions by returning only the last one.
254
+ */
34
255
  readonly extension: string
35
256
 
36
- /** Always true for files */
257
+ /** Type discriminator - always true for FileObject instances */
37
258
  readonly isFile: true
38
259
 
39
- /** Always false for files */
260
+ /** Type discriminator - always false for FileObject instances */
40
261
  readonly isDirectory: false
41
262
 
42
- /** The parent directory object */
263
+ /**
264
+ * The parent DirectoryObject containing this file.
265
+ *
266
+ * Automatically created during FileObject construction based on the resolved
267
+ * file path. Provides access to parent directory operations and maintains
268
+ * the hierarchical relationship between files and directories.
269
+ */
43
270
  readonly directory: DirectoryObject
44
271
 
45
- /** Whether the file exists (async) */
272
+ /**
273
+ * Promise that resolves to whether the file exists on the filesystem.
274
+ *
275
+ * Performs an asynchronous filesystem check to determine file existence.
276
+ * The Promise will resolve to true if the file exists and is accessible,
277
+ * false otherwise. Always await this property before using the result.
278
+ */
46
279
  readonly exists: Promise<boolean>
47
280
 
48
281
  /** Returns a JSON representation of the FileObject */
@@ -57,4 +290,4 @@ export default class FileObject {
57
290
  isDirectory: boolean
58
291
  directory: string | null
59
292
  }
60
- }
293
+ }
@@ -9,16 +9,36 @@
9
9
  * The Glog class uses a proxy to enable both class-style and function-style
10
10
  * usage patterns, making it convenient for different coding preferences.
11
11
  *
12
+ * Log levels range from 0 (critical/always shown) to 5 (verbose debug).
13
+ * Messages with levels higher than the configured threshold are filtered out.
14
+ *
12
15
  * @example
13
16
  * ```typescript
14
- * // Set up logging configuration
17
+ * import { Glog } from '@gesslar/toolkit'
18
+ *
19
+ * // Configure logging once at startup
15
20
  * Glog.setLogLevel(3).setLogPrefix('[MyApp]')
16
21
  *
17
- * // Log messages with different levels
18
- * Glog(0, 'Critical error') // Always shown
19
- * Glog(2, 'Debug info') // Shown if logLevel >= 2
20
- * Glog('Simple message') // Level 0 by default
22
+ * // Use as a function (most common)
23
+ * Glog(0, 'Critical error - system failure!') // Always shown
24
+ * Glog(1, 'Warning: deprecated API used') // Shown if level >= 1
25
+ * Glog(2, 'Info: processing user request') // Shown if level >= 2
26
+ * Glog(3, 'Debug: cache hit for key:', key) // Shown if level >= 3
27
+ * Glog('Simple message') // Level 0 by default
28
+ *
29
+ * // Method chaining for configuration
30
+ * Glog.setLogLevel(2)
31
+ * .setLogPrefix('[API]')
32
+ *
33
+ * // Different contexts can use different prefixes
34
+ * const dbLogger = Glog.setLogPrefix('[DB]')
35
+ * const apiLogger = Glog.setLogPrefix('[API]')
21
36
  * ```
37
+ *
38
+ * @remarks
39
+ * The proxy implementation allows Glog to be called directly as a function
40
+ * while still providing static methods for configuration. This makes it
41
+ * extremely convenient for quick logging without ceremony.
22
42
  */
23
43
  interface GlogInterface {
24
44
  /**
@@ -57,7 +77,7 @@ interface GlogInterface {
57
77
  interface GlogCallable {
58
78
  /**
59
79
  * Log a message with optional level specification.
60
- *
80
+ *
61
81
  * @param args - Either (level: number, ...messages) or (...messages)
62
82
  */
63
83
  (...args: any[]): void
@@ -69,4 +89,4 @@ interface GlogCallable {
69
89
  */
70
90
  declare const Glog: GlogInterface & GlogCallable
71
91
 
72
- export default Glog
92
+ export default Glog
@@ -10,15 +10,36 @@ declare class Util {
10
10
  *
11
11
  * @param text - The text to capitalize
12
12
  * @returns Text with first letter capitalized
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const result = Util.capitalize("hello world")
17
+ * console.log(result) // "Hello world"
18
+ *
19
+ * // Works with empty strings and single characters
20
+ * Util.capitalize("") // ""
21
+ * Util.capitalize("a") // "A"
22
+ * ```
13
23
  */
14
24
  static capitalize(text: string): string
15
25
 
16
26
  /**
17
27
  * Measure wall-clock time for an async function.
28
+ * Useful for performance monitoring and debugging async operations.
18
29
  *
19
30
  * @template T
20
31
  * @param fn - Thunk returning a promise.
21
32
  * @returns Object containing result and elapsed ms (number, 1 decimal).
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const {result, cost} = await Util.time(async () => {
37
+ * await new Promise(resolve => setTimeout(resolve, 100))
38
+ * return "completed"
39
+ * })
40
+ * console.log(`Operation took ${cost}ms`) // "Operation took 100.2ms"
41
+ * console.log(result) // "completed"
42
+ * ```
22
43
  */
23
44
  static time<T>(fn: () => Promise<T>): Promise<{result: T, cost: number}>
24
45
 
@@ -37,6 +58,12 @@ declare class Util {
37
58
  *
38
59
  * @param s - Input string.
39
60
  * @returns 64-char hexadecimal digest.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const hash = Util.hashOf("hello world")
65
+ * console.log(hash) // "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
66
+ * ```
40
67
  */
41
68
  static hashOf(s: string): string
42
69
 
@@ -52,6 +79,23 @@ declare class Util {
52
79
  *
53
80
  * @param object - Mapping of option strings to descriptions.
54
81
  * @returns Array of canonical option names (long preferred, short if no long present).
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * const options = {
86
+ * "-w, --watch": "Watch for changes",
87
+ * "-v": "Verbose output",
88
+ * "--config": "Config file path"
89
+ * }
90
+ * const names = Util.generateOptionNames(options)
91
+ * console.log(names) // ["watch", "v", "config"]
92
+ * ```
93
+ *
94
+ * @remarks
95
+ * Edge cases:
96
+ * - If a key contains only a short option ("-v"), that short name will be included
97
+ * - If multiple long options are present, only the first is used
98
+ * - Malformed option strings may return undefined (filtered out)
55
99
  */
56
100
  static generateOptionNames(object: Record<string, any>): Array<string>
57
101
 
@@ -84,9 +128,11 @@ declare class Util {
84
128
 
85
129
  /**
86
130
  * Emits an event asynchronously and waits for all listeners to complete.
131
+ *
87
132
  * Unlike the standard EventEmitter.emit() which is synchronous, this method
88
133
  * properly handles async event listeners by waiting for all of them to
89
- * resolve or reject using Promise.allSettled().
134
+ * resolve or reject using Promise.allSettled(). If any listener throws an
135
+ * error, the first error encountered will be re-thrown.
90
136
  *
91
137
  * Uses strict instanceof checking to ensure the emitter is a genuine EventEmitter.
92
138
  *
@@ -94,6 +140,26 @@ declare class Util {
94
140
  * @param event - The event name to emit
95
141
  * @param args - Arguments to pass to event listeners
96
142
  * @returns Resolves when all listeners have completed
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * import { EventEmitter } from 'events'
147
+ * import { Util } from '@gesslar/toolkit'
148
+ *
149
+ * const emitter = new EventEmitter()
150
+ *
151
+ * emitter.on('data', async (payload) => {
152
+ * console.log('Processing:', payload.id)
153
+ * await new Promise(resolve => setTimeout(resolve, 100))
154
+ * console.log('Completed:', payload.id)
155
+ * })
156
+ *
157
+ * // Wait for all async listeners to complete
158
+ * await Util.asyncEmit(emitter, 'data', { id: 'task-1' })
159
+ * console.log('All listeners finished')
160
+ * ```
161
+ *
162
+ * @throws Will throw an error if any listener rejects or throws
97
163
  */
98
164
  static asyncEmit(emitter: import('events').EventEmitter, event: string, ...args: unknown[]): Promise<void>
99
165
 
@@ -110,4 +176,4 @@ declare class Util {
110
176
  static asyncEmitAnon(emitter: { listeners(event: string): Function[], on(event: string, listener: Function): any, emit(event: string, ...args: unknown[]): any }, event: string, ...args: unknown[]): Promise<void>
111
177
  }
112
178
 
113
- export default Util
179
+ export default Util