@baseplate-dev/utils 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fs/index.d.ts +1 -0
- package/dist/fs/index.d.ts.map +1 -1
- package/dist/fs/index.js +1 -0
- package/dist/fs/index.js.map +1 -1
- package/dist/fs/read-json-with-schema.d.ts +1 -1
- package/dist/fs/read-json-with-schema.d.ts.map +1 -1
- package/dist/fs/read-json-with-schema.js.map +1 -1
- package/dist/fs/remove-empty-directories.d.ts +5 -0
- package/dist/fs/remove-empty-directories.d.ts.map +1 -0
- package/dist/fs/remove-empty-directories.js +21 -0
- package/dist/fs/remove-empty-directories.js.map +1 -0
- package/dist/objects/index.d.ts +1 -0
- package/dist/objects/index.d.ts.map +1 -1
- package/dist/objects/index.js +1 -0
- package/dist/objects/index.js.map +1 -1
- package/dist/objects/sort-keys-recursive.d.ts +8 -0
- package/dist/objects/sort-keys-recursive.d.ts.map +1 -0
- package/dist/objects/sort-keys-recursive.js +18 -0
- package/dist/objects/sort-keys-recursive.js.map +1 -0
- package/dist/paths/index.d.ts +2 -0
- package/dist/paths/index.d.ts.map +1 -1
- package/dist/paths/index.js +2 -0
- package/dist/paths/index.js.map +1 -1
- package/dist/paths/normalize-path-separators.d.ts +7 -0
- package/dist/paths/normalize-path-separators.d.ts.map +1 -0
- package/dist/paths/normalize-path-separators.js +10 -0
- package/dist/paths/normalize-path-separators.js.map +1 -0
- package/dist/paths/safe-path-join.d.ts +27 -0
- package/dist/paths/safe-path-join.d.ts.map +1 -0
- package/dist/paths/safe-path-join.js +64 -0
- package/dist/paths/safe-path-join.js.map +1 -0
- package/dist/string/index.d.ts +1 -1
- package/dist/string/index.js +1 -1
- package/dist/string/random-key.d.ts +6 -0
- package/dist/string/random-key.d.ts.map +1 -0
- package/dist/string/{random-uid.js → random-key.js} +4 -4
- package/dist/string/{random-uid.js.map → random-key.js.map} +1 -1
- package/dist/validators/case-validators.d.ts.map +1 -1
- package/dist/validators/case-validators.js +12 -4
- package/dist/validators/case-validators.js.map +1 -1
- package/dist/validators/transform-with-dynamic-schema.d.ts +1 -1
- package/dist/validators/transform-with-dynamic-schema.d.ts.map +1 -1
- package/dist/validators/transform-with-dynamic-schema.js.map +1 -1
- package/package.json +11 -2
- package/dist/string/random-uid.d.ts +0 -6
- package/dist/string/random-uid.d.ts.map +0 -1
package/dist/fs/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from './file-exists.js';
|
|
|
4
4
|
export * from './find-nearest-package-json.js';
|
|
5
5
|
export * from './handle-not-found-error.js';
|
|
6
6
|
export * from './read-json-with-schema.js';
|
|
7
|
+
export * from './remove-empty-directories.js';
|
|
7
8
|
export * from './write-json.js';
|
|
8
9
|
export * from './write-stable-pretty-json.js';
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/fs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fs/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fs/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iBAAiB,CAAC;AAChC,cAAc,+BAA+B,CAAC"}
|
package/dist/fs/index.js
CHANGED
|
@@ -4,6 +4,7 @@ export * from './file-exists.js';
|
|
|
4
4
|
export * from './find-nearest-package-json.js';
|
|
5
5
|
export * from './handle-not-found-error.js';
|
|
6
6
|
export * from './read-json-with-schema.js';
|
|
7
|
+
export * from './remove-empty-directories.js';
|
|
7
8
|
export * from './write-json.js';
|
|
8
9
|
export * from './write-stable-pretty-json.js';
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/fs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fs/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,cAAc,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fs/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iBAAiB,CAAC;AAChC,cAAc,+BAA+B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-json-with-schema.d.ts","sourceRoot":"","sources":["../../src/fs/read-json-with-schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"read-json-with-schema.d.ts","sourceRoot":"","sources":["../../src/fs/read-json-with-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAK7B;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAC1D,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,CAAC,GACR,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAoBtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-json-with-schema.js","sourceRoot":"","sources":["../../src/fs/read-json-with-schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"read-json-with-schema.js","sourceRoot":"","sources":["../../src/fs/read-json-with-schema.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAE/B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAgB,EAChB,MAAS;IAET,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACxD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAY,CAAC;QACtD,yFAAyF;QACzF,OAAO,MAAO,MAAM,CAAC,UAAU,CAAC,UAAU,CAA0B,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;YAC9B,MAAM,IAAI,SAAS,CACjB,yBAAyB,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,EACrD,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,MAAM,IAAI,SAAS,CAAC,yBAAyB,QAAQ,EAAE,EAAE;gBACvD,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-empty-directories.d.ts","sourceRoot":"","sources":["../../src/fs/remove-empty-directories.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Recursively removes empty directories.
|
|
5
|
+
*/
|
|
6
|
+
export async function removeEmptyDirectories(directory) {
|
|
7
|
+
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
8
|
+
// Process subdirectories first
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
if (entry.isDirectory()) {
|
|
11
|
+
const subdirectory = path.join(directory, entry.name);
|
|
12
|
+
await removeEmptyDirectories(subdirectory);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Check if directory is now empty
|
|
16
|
+
const remainingEntries = await fs.readdir(directory);
|
|
17
|
+
if (remainingEntries.length === 0) {
|
|
18
|
+
await fs.rmdir(directory);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=remove-empty-directories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-empty-directories.js","sourceRoot":"","sources":["../../src/fs/remove-empty-directories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,SAAiB;IAC5D,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAErE,+BAA+B;IAC/B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACtD,MAAM,sBAAsB,CAAC,YAAY,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,MAAM,gBAAgB,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACrD,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC"}
|
package/dist/objects/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/objects/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/objects/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC"}
|
package/dist/objects/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/objects/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/objects/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively sorts all keys in an object, including nested objects and arrays.
|
|
3
|
+
*
|
|
4
|
+
* @param obj - The object to sort recursively.
|
|
5
|
+
* @returns A new object with all keys sorted recursively.
|
|
6
|
+
*/
|
|
7
|
+
export declare function sortKeysRecursive<T>(obj: T): T;
|
|
8
|
+
//# sourceMappingURL=sort-keys-recursive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort-keys-recursive.d.ts","sourceRoot":"","sources":["../../src/objects/sort-keys-recursive.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAc9C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively sorts all keys in an object, including nested objects and arrays.
|
|
3
|
+
*
|
|
4
|
+
* @param obj - The object to sort recursively.
|
|
5
|
+
* @returns A new object with all keys sorted recursively.
|
|
6
|
+
*/
|
|
7
|
+
export function sortKeysRecursive(obj) {
|
|
8
|
+
if (obj === null || typeof obj !== 'object') {
|
|
9
|
+
return obj;
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(obj)) {
|
|
12
|
+
return obj.map(sortKeysRecursive);
|
|
13
|
+
}
|
|
14
|
+
return Object.fromEntries(Object.entries(obj)
|
|
15
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
16
|
+
.map(([key, value]) => [key, sortKeysRecursive(value)]));
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=sort-keys-recursive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sort-keys-recursive.js","sourceRoot":"","sources":["../../src/objects/sort-keys-recursive.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAI,GAAM;IACzC,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,GAAG,CAAC;IACb,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAM,CAAC;IACzC,CAAC;IAED,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;SAChB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CACrD,CAAC;AACT,CAAC"}
|
package/dist/paths/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
|
package/dist/paths/index.js
CHANGED
package/dist/paths/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/paths/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes path separators from Windows (\) to Unix (/) format.
|
|
3
|
+
* @param filePath The path to normalize
|
|
4
|
+
* @returns The path with Unix separators
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizePathSeparators(filePath: string): string;
|
|
7
|
+
//# sourceMappingURL=normalize-path-separators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize-path-separators.d.ts","sourceRoot":"","sources":["../../src/paths/normalize-path-separators.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes path separators from Windows (\) to Unix (/) format.
|
|
4
|
+
* @param filePath The path to normalize
|
|
5
|
+
* @returns The path with Unix separators
|
|
6
|
+
*/
|
|
7
|
+
export function normalizePathSeparators(filePath) {
|
|
8
|
+
return filePath.replaceAll(path.win32.sep, path.posix.sep);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=normalize-path-separators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize-path-separators.js","sourceRoot":"","sources":["../../src/paths/normalize-path-separators.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safely joins paths ensuring the result is always within the parent directory.
|
|
3
|
+
* This prevents directory traversal attacks by resolving the path and checking
|
|
4
|
+
* that it remains within the parent directory boundaries.
|
|
5
|
+
*
|
|
6
|
+
* @param parentDir - The parent directory that the result must be within
|
|
7
|
+
* @param ...segments - Path segments to join to the parent directory
|
|
8
|
+
* @returns The joined path that is guaranteed to be within the parent directory
|
|
9
|
+
* @throws Error if the resulting path would be outside the parent directory
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Valid paths
|
|
14
|
+
* safePathJoin('/home/user', 'documents', 'file.txt')
|
|
15
|
+
* // Returns: '/home/user/documents/file.txt'
|
|
16
|
+
*
|
|
17
|
+
* // Throws error - attempts to escape parent directory
|
|
18
|
+
* safePathJoin('/home/user', '../../../etc/passwd')
|
|
19
|
+
* // Throws: Error: Path traversal detected
|
|
20
|
+
*
|
|
21
|
+
* // Handles complex paths safely
|
|
22
|
+
* safePathJoin('/home/user', 'docs/../documents/./file.txt')
|
|
23
|
+
* // Returns: '/home/user/documents/file.txt'
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function safePathJoin(parentDir: string, ...segments: string[]): string;
|
|
27
|
+
//# sourceMappingURL=safe-path-join.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-path-join.d.ts","sourceRoot":"","sources":["../../src/paths/safe-path-join.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAoD7E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Safely joins paths ensuring the result is always within the parent directory.
|
|
4
|
+
* This prevents directory traversal attacks by resolving the path and checking
|
|
5
|
+
* that it remains within the parent directory boundaries.
|
|
6
|
+
*
|
|
7
|
+
* @param parentDir - The parent directory that the result must be within
|
|
8
|
+
* @param ...segments - Path segments to join to the parent directory
|
|
9
|
+
* @returns The joined path that is guaranteed to be within the parent directory
|
|
10
|
+
* @throws Error if the resulting path would be outside the parent directory
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* // Valid paths
|
|
15
|
+
* safePathJoin('/home/user', 'documents', 'file.txt')
|
|
16
|
+
* // Returns: '/home/user/documents/file.txt'
|
|
17
|
+
*
|
|
18
|
+
* // Throws error - attempts to escape parent directory
|
|
19
|
+
* safePathJoin('/home/user', '../../../etc/passwd')
|
|
20
|
+
* // Throws: Error: Path traversal detected
|
|
21
|
+
*
|
|
22
|
+
* // Handles complex paths safely
|
|
23
|
+
* safePathJoin('/home/user', 'docs/../documents/./file.txt')
|
|
24
|
+
* // Returns: '/home/user/documents/file.txt'
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function safePathJoin(parentDir, ...segments) {
|
|
28
|
+
// Normalize the parent directory to handle any . or .. in it
|
|
29
|
+
const normalizedParent = path.resolve(parentDir);
|
|
30
|
+
// Check for absolute paths in segments (which would escape the parent)
|
|
31
|
+
for (const segment of segments) {
|
|
32
|
+
if (path.isAbsolute(segment)) {
|
|
33
|
+
throw new Error(`Path traversal detected: Absolute path segment "${segment}" is not allowed`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Join all segments together
|
|
37
|
+
const joined = path.join(normalizedParent, ...segments);
|
|
38
|
+
// Resolve to get the absolute path
|
|
39
|
+
const resolved = path.resolve(joined);
|
|
40
|
+
// Special case for root directory
|
|
41
|
+
if (normalizedParent === path.sep || normalizedParent === path.resolve('/')) {
|
|
42
|
+
// When parent is root, we need to check if we're trying to go above root
|
|
43
|
+
if (resolved !== normalizedParent &&
|
|
44
|
+
!resolved.startsWith(normalizedParent)) {
|
|
45
|
+
throw new Error(`Path traversal detected: Cannot navigate outside root directory`);
|
|
46
|
+
}
|
|
47
|
+
return resolved;
|
|
48
|
+
}
|
|
49
|
+
// Check if the resolved path is within the parent directory
|
|
50
|
+
// Add path separator to ensure exact directory match (not just prefix match)
|
|
51
|
+
const parentWithSep = normalizedParent.endsWith(path.sep)
|
|
52
|
+
? normalizedParent
|
|
53
|
+
: normalizedParent + path.sep;
|
|
54
|
+
// Special case: if resolved is exactly the parent directory
|
|
55
|
+
if (resolved === normalizedParent) {
|
|
56
|
+
return resolved;
|
|
57
|
+
}
|
|
58
|
+
// Check if resolved path starts with parent directory
|
|
59
|
+
if (!resolved.startsWith(parentWithSep)) {
|
|
60
|
+
throw new Error(`Path traversal detected: Resolved path "${resolved}" is outside parent directory "${normalizedParent}"`);
|
|
61
|
+
}
|
|
62
|
+
return resolved;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=safe-path-join.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-path-join.js","sourceRoot":"","sources":["../../src/paths/safe-path-join.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,GAAG,QAAkB;IACnE,6DAA6D;IAC7D,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEjD,uEAAuE;IACvE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,mDAAmD,OAAO,kBAAkB,CAC7E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,QAAQ,CAAC,CAAC;IAExD,mCAAmC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtC,kCAAkC;IAClC,IAAI,gBAAgB,KAAK,IAAI,CAAC,GAAG,IAAI,gBAAgB,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5E,yEAAyE;QACzE,IACE,QAAQ,KAAK,gBAAgB;YAC7B,CAAC,QAAQ,CAAC,UAAU,CAAC,gBAAgB,CAAC,EACtC,CAAC;YACD,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,4DAA4D;IAC5D,6EAA6E;IAC7E,MAAM,aAAa,GAAG,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;QACvD,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC;IAEhC,4DAA4D;IAC5D,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;QAClC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,sDAAsD;IACtD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,2CAA2C,QAAQ,kCAAkC,gBAAgB,GAAG,CACzG,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/string/index.d.ts
CHANGED
package/dist/string/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random-key.d.ts","sourceRoot":"","sources":["../../src/string/random-key.ts"],"names":[],"mappings":"AAWA;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAK,GAAG,MAAM,CAE7C"}
|
|
@@ -7,10 +7,10 @@ const UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
|
7
7
|
*/
|
|
8
8
|
const customNanoid = customAlphabet(`${NUMBERS}${LOWERCASE}${UPPERCASE}_`, 12);
|
|
9
9
|
/**
|
|
10
|
-
* Generate a random
|
|
11
|
-
* @returns A random
|
|
10
|
+
* Generate a random key string made up of numbers, lowercase, and uppercase letters
|
|
11
|
+
* @returns A random key string
|
|
12
12
|
*/
|
|
13
|
-
export function
|
|
13
|
+
export function randomKey(length = 12) {
|
|
14
14
|
return customNanoid(length);
|
|
15
15
|
}
|
|
16
|
-
//# sourceMappingURL=random-
|
|
16
|
+
//# sourceMappingURL=random-key.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"random-
|
|
1
|
+
{"version":3,"file":"random-key.js","sourceRoot":"","sources":["../../src/string/random-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,OAAO,GAAG,YAAY,CAAC;AAC7B,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAC/C,MAAM,SAAS,GAAG,4BAA4B,CAAC;AAE/C;;GAEG;AACH,MAAM,YAAY,GAAG,cAAc,CAAC,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,EAAE,EAAE,CAAC,CAAC;AAE/E;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,MAAM,GAAG,EAAE;IACnC,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"case-validators.d.ts","sourceRoot":"","sources":["../../src/validators/case-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAiB,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAwB,CAAC;AAEvD;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAwB,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAsB,CAAC;AAEvD,eAAO,MAAM,eAAe;IAC1B;;OAEG;;
|
|
1
|
+
{"version":3,"file":"case-validators.d.ts","sourceRoot":"","sources":["../../src/validators/case-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAiB,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAwB,CAAC;AAEvD;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAwB,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAsB,CAAC;AAEvD,eAAO,MAAM,eAAe;IAC1B;;OAEG;;IAIH;;OAEG;;IAIH;;OAEG;;IAIH;;OAEG;;CAIK,CAAC"}
|
|
@@ -19,18 +19,26 @@ export const CASE_VALIDATORS = {
|
|
|
19
19
|
/**
|
|
20
20
|
* Zod validator for validating kebab case, e.g. "my-project".
|
|
21
21
|
*/
|
|
22
|
-
KEBAB_CASE: z.string().regex(KEBAB_CASE_REGEX
|
|
22
|
+
KEBAB_CASE: z.string().regex(KEBAB_CASE_REGEX, {
|
|
23
|
+
message: 'Must be kebab case (e.g. "my-project")',
|
|
24
|
+
}),
|
|
23
25
|
/**
|
|
24
26
|
* Zod validator for validating pascal case, e.g. "MyProject".
|
|
25
27
|
*/
|
|
26
|
-
PASCAL_CASE: z.string().regex(PASCAL_CASE_REGEX
|
|
28
|
+
PASCAL_CASE: z.string().regex(PASCAL_CASE_REGEX, {
|
|
29
|
+
message: 'Must be pascal case (e.g. "MyProject")',
|
|
30
|
+
}),
|
|
27
31
|
/**
|
|
28
32
|
* Zod validator for validating camel case, e.g. "myProject".
|
|
29
33
|
*/
|
|
30
|
-
CAMEL_CASE: z.string().regex(CAMEL_CASE_REGEX
|
|
34
|
+
CAMEL_CASE: z.string().regex(CAMEL_CASE_REGEX, {
|
|
35
|
+
message: 'Must be camel case (e.g. "myProject")',
|
|
36
|
+
}),
|
|
31
37
|
/**
|
|
32
38
|
* Zod validator for validating constant case, e.g. "MY_PROJECT".
|
|
33
39
|
*/
|
|
34
|
-
CONSTANT_CASE: z.string().regex(CONSTANT_CASE_REGEX
|
|
40
|
+
CONSTANT_CASE: z.string().regex(CONSTANT_CASE_REGEX, {
|
|
41
|
+
message: 'Must be constant case (e.g. "MY_PROJECT")',
|
|
42
|
+
}),
|
|
35
43
|
};
|
|
36
44
|
//# sourceMappingURL=case-validators.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"case-validators.js","sourceRoot":"","sources":["../../src/validators/case-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAE/C;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;AAEvD;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAEvD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"case-validators.js","sourceRoot":"","sources":["../../src/validators/case-validators.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAE/C;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;AAEvD;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAEvD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE;QAC7C,OAAO,EAAE,wCAAwC;KAClD,CAAC;IACF;;OAEG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,iBAAiB,EAAE;QAC/C,OAAO,EAAE,wCAAwC;KAClD,CAAC;IACF;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE;QAC7C,OAAO,EAAE,uCAAuC;KACjD,CAAC;IACF;;OAEG;IACH,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,EAAE;QACnD,OAAO,EAAE,2CAA2C;KACrD,CAAC;CACM,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform-with-dynamic-schema.d.ts","sourceRoot":"","sources":["../../src/validators/transform-with-dynamic-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"transform-with-dynamic-schema.d.ts","sourceRoot":"","sources":["../../src/validators/transform-with-dynamic-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAIrD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,SAAS,MAAM,EAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,EACjD,SAAS,CAAC,EAAE,MAAM,KAAK,GACtB,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,aAAa,KAAK,KAAK,CA6B5C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform-with-dynamic-schema.js","sourceRoot":"","sources":["../../src/validators/transform-with-dynamic-schema.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transform-with-dynamic-schema.js","sourceRoot":"","sources":["../../src/validators/transform-with-dynamic-schema.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAiD,EACjD,SAAuB;IAEvB,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAC7B,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAClD,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxC,GAAG,CAAC,QAAQ,CAAC;oBACX,GAAG,KAAK;oBACR,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAmB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;iBACnE,CAAC,CAAC;YACL,CAAC;YACD,OAAO,CAAC,CAAC,KAAK,CAAC;QACjB,CAAC;QAED,OAAO,SAAS;YACd,CAAC,CAAC;gBACE,GAAG,IAAI;gBACP,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,IAA+B;aACpD;YACH,CAAC,CAAE,MAAM,CAAC,IAAc,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baseplate-dev/utils",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Shared utility functions for Baseplate",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"utilities",
|
|
7
|
+
"typescript",
|
|
8
|
+
"helpers",
|
|
9
|
+
"common",
|
|
10
|
+
"baseplate",
|
|
11
|
+
"full-stack",
|
|
12
|
+
"code-generation"
|
|
13
|
+
],
|
|
5
14
|
"homepage": "https://www.baseplate.dev",
|
|
6
15
|
"repository": {
|
|
7
16
|
"type": "git",
|
|
@@ -42,7 +51,7 @@
|
|
|
42
51
|
"prettier": "3.5.3",
|
|
43
52
|
"typescript": "5.7.3",
|
|
44
53
|
"vitest": "3.0.7",
|
|
45
|
-
"@baseplate-dev/tools": "0.1
|
|
54
|
+
"@baseplate-dev/tools": "0.2.1"
|
|
46
55
|
},
|
|
47
56
|
"engines": {
|
|
48
57
|
"node": "^22.0.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"random-uid.d.ts","sourceRoot":"","sources":["../../src/string/random-uid.ts"],"names":[],"mappings":"AAWA;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,SAAK,GAAG,MAAM,CAE7C"}
|