@gesslar/toolkit 0.0.7 → 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/README.md +1 -1
- package/package.json +14 -3
- package/src/lib/File.js +3 -3
- package/src/lib/Glog.js +13 -0
- package/src/types/Data.d.ts +152 -4
- package/src/types/File.d.ts +2 -2
- package/src/types/FileObject.d.ts +250 -17
- package/src/types/Glog.d.ts +27 -7
- package/src/types/Util.d.ts +68 -2
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gesslar/toolkit",
|
|
3
|
-
"version": "0.0.
|
|
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 {
|
|
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) {
|
package/src/types/Data.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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 */
|
package/src/types/File.d.ts
CHANGED
|
@@ -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:
|
|
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,
|
|
8
|
-
* resolution and
|
|
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
|
-
*
|
|
14
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
257
|
+
/** Type discriminator - always true for FileObject instances */
|
|
37
258
|
readonly isFile: true
|
|
38
259
|
|
|
39
|
-
/**
|
|
260
|
+
/** Type discriminator - always false for FileObject instances */
|
|
40
261
|
readonly isDirectory: false
|
|
41
262
|
|
|
42
|
-
/**
|
|
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
|
-
/**
|
|
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
|
+
}
|
package/src/types/Glog.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
17
|
+
* import { Glog } from '@gesslar/toolkit'
|
|
18
|
+
*
|
|
19
|
+
* // Configure logging once at startup
|
|
15
20
|
* Glog.setLogLevel(3).setLogPrefix('[MyApp]')
|
|
16
21
|
*
|
|
17
|
-
* //
|
|
18
|
-
* Glog(0, 'Critical error') // Always shown
|
|
19
|
-
* Glog(
|
|
20
|
-
* Glog('
|
|
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
|
package/src/types/Util.d.ts
CHANGED
|
@@ -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
|