@furystack/utils 8.1.3 → 8.1.5
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/esm/deep-merge.d.ts +2 -2
- package/esm/deep-merge.js +2 -2
- package/esm/is-async-disposable.d.ts +1 -2
- package/esm/is-async-disposable.d.ts.map +1 -1
- package/esm/is-async-disposable.js +1 -2
- package/esm/is-async-disposable.js.map +1 -1
- package/esm/is-disposable.d.ts +1 -2
- package/esm/is-disposable.d.ts.map +1 -1
- package/esm/is-disposable.js +1 -2
- package/esm/is-disposable.js.map +1 -1
- package/esm/observable-value.d.ts +2 -2
- package/esm/observable-value.js +1 -1
- package/esm/path-helper.d.ts +88 -0
- package/esm/path-helper.d.ts.map +1 -1
- package/esm/path-helper.js +136 -0
- package/esm/path-helper.js.map +1 -1
- package/esm/path-helper.spec.d.ts.map +1 -1
- package/esm/path-helper.spec.js +178 -0
- package/esm/path-helper.spec.js.map +1 -1
- package/esm/sort-by.d.ts +4 -1
- package/esm/sort-by.d.ts.map +1 -1
- package/esm/sort-by.js.map +1 -1
- package/esm/using-async.d.ts +2 -2
- package/esm/using-async.js +2 -2
- package/esm/using.d.ts +2 -2
- package/esm/using.js +2 -2
- package/esm/value-observer.d.ts +1 -1
- package/esm/value-observer.js +1 -1
- package/package.json +2 -2
- package/src/deep-merge.ts +2 -2
- package/src/is-async-disposable.ts +1 -2
- package/src/is-disposable.ts +1 -2
- package/src/observable-value.ts +2 -2
- package/src/path-helper.spec.ts +237 -0
- package/src/path-helper.ts +151 -0
- package/src/sort-by.ts +4 -1
- package/src/using-async.ts +2 -2
- package/src/using.ts +2 -2
- package/src/value-observer.ts +1 -1
package/esm/deep-merge.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ export type DeepPartial<T> = {
|
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
8
|
* Deep merge two objects.
|
|
9
|
-
* @param
|
|
10
|
-
* @param sources The source objects
|
|
9
|
+
* @param target The target object to be merged into
|
|
10
|
+
* @param sources The source objects to merge
|
|
11
11
|
* @returns A new instance with the merged values
|
|
12
12
|
*/
|
|
13
13
|
export declare const deepMerge: <T>(target: T, ...sources: Array<DeepPartial<T> | undefined>) => T;
|
package/esm/deep-merge.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Deep merge two objects.
|
|
3
|
-
* @param
|
|
4
|
-
* @param sources The source objects
|
|
3
|
+
* @param target The target object to be merged into
|
|
4
|
+
* @param sources The source objects to merge
|
|
5
5
|
* @returns A new instance with the merged values
|
|
6
6
|
*/
|
|
7
7
|
export const deepMerge = (target, ...sources) => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
2
|
* @param value The value to check
|
|
4
|
-
* @returns
|
|
3
|
+
* @returns whether the value is an instance of an async disposable object
|
|
5
4
|
*/
|
|
6
5
|
export declare const isAsyncDisposable: (value: unknown) => value is AsyncDisposable;
|
|
7
6
|
//# sourceMappingURL=is-async-disposable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-async-disposable.d.ts","sourceRoot":"","sources":["../src/is-async-disposable.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"is-async-disposable.d.ts","sourceRoot":"","sources":["../src/is-async-disposable.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,eAE3D,CAAA"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
2
|
* @param value The value to check
|
|
4
|
-
* @returns
|
|
3
|
+
* @returns whether the value is an instance of an async disposable object
|
|
5
4
|
*/
|
|
6
5
|
export const isAsyncDisposable = (value) => {
|
|
7
6
|
return value?.[Symbol.asyncDispose] instanceof Function;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-async-disposable.js","sourceRoot":"","sources":["../src/is-async-disposable.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"is-async-disposable.js","sourceRoot":"","sources":["../src/is-async-disposable.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAA4B,EAAE;IAC5E,OAAQ,KAAyB,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,YAAY,QAAQ,CAAA;AAC9E,CAAC,CAAA"}
|
package/esm/is-disposable.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
2
|
* @param value The value to check
|
|
4
|
-
* @returns
|
|
3
|
+
* @returns whether the value is an instance of a disposable object
|
|
5
4
|
*/
|
|
6
5
|
export declare const isDisposable: (value: unknown) => value is Disposable;
|
|
7
6
|
//# sourceMappingURL=is-disposable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-disposable.d.ts","sourceRoot":"","sources":["../src/is-disposable.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"is-disposable.d.ts","sourceRoot":"","sources":["../src/is-disposable.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,UAEtD,CAAA"}
|
package/esm/is-disposable.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
2
|
* @param value The value to check
|
|
4
|
-
* @returns
|
|
3
|
+
* @returns whether the value is an instance of a disposable object
|
|
5
4
|
*/
|
|
6
5
|
export const isDisposable = (value) => {
|
|
7
6
|
return value?.[Symbol.dispose] instanceof Function;
|
package/esm/is-disposable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-disposable.js","sourceRoot":"","sources":["../src/is-disposable.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"is-disposable.js","sourceRoot":"","sources":["../src/is-disposable.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAc,EAAuB,EAAE;IAClE,OAAQ,KAAoB,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,QAAQ,CAAA;AACpE,CAAC,CAAA"}
|
|
@@ -15,7 +15,7 @@ export type ObservableValueOptions<T> = {
|
|
|
15
15
|
* Defines a custom compare function to determine if the value should be updated and the observers should be notified
|
|
16
16
|
* @param lastValue the last value
|
|
17
17
|
* @param nextValue the next value
|
|
18
|
-
* @returns
|
|
18
|
+
* @returns whether the value should be updated and the observers should be notified
|
|
19
19
|
*/
|
|
20
20
|
compare: (lastValue: T, nextValue: T) => boolean;
|
|
21
21
|
};
|
|
@@ -58,7 +58,7 @@ export declare class ObservableValue<T> implements Disposable {
|
|
|
58
58
|
/**
|
|
59
59
|
* The observer will unsubscribe from the Observable
|
|
60
60
|
* @param observer The ValueObserver instance
|
|
61
|
-
* @returns
|
|
61
|
+
* @returns whether unsubscribing was successful
|
|
62
62
|
*/
|
|
63
63
|
unsubscribe(observer: ValueObserver<T>): boolean;
|
|
64
64
|
/**
|
package/esm/observable-value.js
CHANGED
|
@@ -61,7 +61,7 @@ export class ObservableValue {
|
|
|
61
61
|
/**
|
|
62
62
|
* The observer will unsubscribe from the Observable
|
|
63
63
|
* @param observer The ValueObserver instance
|
|
64
|
-
* @returns
|
|
64
|
+
* @returns whether unsubscribing was successful
|
|
65
65
|
*/
|
|
66
66
|
unsubscribe(observer) {
|
|
67
67
|
return this.observers.delete(observer);
|
package/esm/path-helper.d.ts
CHANGED
|
@@ -40,5 +40,93 @@ export declare class PathHelper {
|
|
|
40
40
|
*/
|
|
41
41
|
static getParentPath(path: string): string;
|
|
42
42
|
static normalize(path: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Trims only the trailing slash from a URL or path
|
|
45
|
+
* @param url The URL or path to trim
|
|
46
|
+
* @returns The URL/path without trailing slash
|
|
47
|
+
* @example
|
|
48
|
+
* PathHelper.trimTrailingSlash('/api/') // '/api'
|
|
49
|
+
* PathHelper.trimTrailingSlash('http://example.com/') // 'http://example.com'
|
|
50
|
+
*/
|
|
51
|
+
static trimTrailingSlash(url: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Trims only the leading slash from a path
|
|
54
|
+
* @param path The path to trim
|
|
55
|
+
* @returns The path without leading slash
|
|
56
|
+
* @example
|
|
57
|
+
* PathHelper.trimLeadingSlash('/api') // 'api'
|
|
58
|
+
* PathHelper.trimLeadingSlash('api') // 'api'
|
|
59
|
+
*/
|
|
60
|
+
static trimLeadingSlash(path: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* Ensures a path has a leading slash
|
|
63
|
+
* @param path The path to check
|
|
64
|
+
* @returns The path with a leading slash
|
|
65
|
+
* @example
|
|
66
|
+
* PathHelper.ensureLeadingSlash('api') // '/api'
|
|
67
|
+
* PathHelper.ensureLeadingSlash('/api') // '/api'
|
|
68
|
+
*/
|
|
69
|
+
static ensureLeadingSlash(path: string): string;
|
|
70
|
+
/**
|
|
71
|
+
* Normalizes a base URL by ensuring it has no trailing slash
|
|
72
|
+
* @param baseUrl The base URL to normalize (e.g., 'http://example.com/' or '/api/')
|
|
73
|
+
* @returns The normalized base URL without trailing slash
|
|
74
|
+
* @example
|
|
75
|
+
* PathHelper.normalizeBaseUrl('http://example.com/') // 'http://example.com'
|
|
76
|
+
* PathHelper.normalizeBaseUrl('/api/') // '/api'
|
|
77
|
+
* PathHelper.normalizeBaseUrl('/api') // '/api'
|
|
78
|
+
*/
|
|
79
|
+
static normalizeBaseUrl(baseUrl: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* Joins a base URL with a path, handling slashes correctly
|
|
82
|
+
* Preserves protocols (http://, https://, etc.)
|
|
83
|
+
* @param baseUrl The base URL (with or without trailing slash)
|
|
84
|
+
* @param path The path to append (with or without leading slash)
|
|
85
|
+
* @returns The combined URL with correct slash handling
|
|
86
|
+
* @example
|
|
87
|
+
* PathHelper.joinUrl('http://example.com', '/path') // 'http://example.com/path'
|
|
88
|
+
* PathHelper.joinUrl('http://example.com/', 'path') // 'http://example.com/path'
|
|
89
|
+
* PathHelper.joinUrl('/api', '/users') // '/api/users'
|
|
90
|
+
* PathHelper.joinUrl('/api/', 'users') // '/api/users'
|
|
91
|
+
* PathHelper.joinUrl('http://example.com', '') // 'http://example.com'
|
|
92
|
+
*/
|
|
93
|
+
static joinUrl(baseUrl: string, path: string): string;
|
|
94
|
+
/**
|
|
95
|
+
* Checks if a request URL matches a base URL pattern
|
|
96
|
+
* Handles trailing slash variations correctly
|
|
97
|
+
* @param requestUrl The incoming request URL
|
|
98
|
+
* @param baseUrl The base URL pattern to match against
|
|
99
|
+
* @returns true if the request URL matches the base URL
|
|
100
|
+
* @example
|
|
101
|
+
* PathHelper.matchesBaseUrl('/api/users', '/api') // true
|
|
102
|
+
* PathHelper.matchesBaseUrl('/api', '/api') // true
|
|
103
|
+
* PathHelper.matchesBaseUrl('/api', '/api/') // true
|
|
104
|
+
* PathHelper.matchesBaseUrl('/other', '/api') // false
|
|
105
|
+
* PathHelper.matchesBaseUrl('/api2', '/api') // false (not a path match)
|
|
106
|
+
*/
|
|
107
|
+
static matchesBaseUrl(requestUrl: string, baseUrl: string): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Extracts the remaining path after a base URL
|
|
110
|
+
* Always returns a path with a leading slash (or empty string for exact matches)
|
|
111
|
+
* @param requestUrl The full request URL
|
|
112
|
+
* @param baseUrl The base URL to remove
|
|
113
|
+
* @returns The remaining path with leading slash, or empty string if exact match
|
|
114
|
+
* @example
|
|
115
|
+
* PathHelper.extractPath('/api/users', '/api') // '/users'
|
|
116
|
+
* PathHelper.extractPath('/api', '/api') // ''
|
|
117
|
+
* PathHelper.extractPath('/api/users?id=1', '/api') // '/users?id=1'
|
|
118
|
+
* PathHelper.extractPath('/api/', '/api') // '/'
|
|
119
|
+
*/
|
|
120
|
+
static extractPath(requestUrl: string, baseUrl: string): string;
|
|
121
|
+
/**
|
|
122
|
+
* Normalizes a URL by removing consecutive slashes (except after protocol)
|
|
123
|
+
* @param url The URL to normalize
|
|
124
|
+
* @returns The normalized URL
|
|
125
|
+
* @example
|
|
126
|
+
* PathHelper.normalizeUrl('http://example.com//path') // 'http://example.com/path'
|
|
127
|
+
* PathHelper.normalizeUrl('/api//users///123') // '/api/users/123'
|
|
128
|
+
* PathHelper.normalizeUrl('http://example.com/') // 'http://example.com/'
|
|
129
|
+
*/
|
|
130
|
+
static normalizeUrl(url: string): string;
|
|
43
131
|
}
|
|
44
132
|
//# sourceMappingURL=path-helper.d.ts.map
|
package/esm/path-helper.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-helper.d.ts","sourceRoot":"","sources":["../src/path-helper.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,UAAU;IACrB;;;;OAIG;WACW,WAAW,CAAC,IAAI,EAAE,MAAM;IAUtC;;;;;OAKG;WACW,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAIjD;;;;OAIG;WACW,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;IAIzC;;;;;OAKG;WACW,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO;IAIjF;;;;;;;OAOG;WACW,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;WAQnC,SAAS,CAAC,IAAI,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"path-helper.d.ts","sourceRoot":"","sources":["../src/path-helper.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,UAAU;IACrB;;;;OAIG;WACW,WAAW,CAAC,IAAI,EAAE,MAAM;IAUtC;;;;;OAKG;WACW,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAIjD;;;;OAIG;WACW,SAAS,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE;IAIzC;;;;;OAKG;WACW,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO;IAIjF;;;;;;;OAOG;WACW,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;WAQnC,SAAS,CAAC,IAAI,EAAE,MAAM;IAIpC;;;;;;;OAOG;WACW,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIpD;;;;;;;OAOG;WACW,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIpD;;;;;;;OAOG;WACW,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAItD;;;;;;;;OAQG;WACW,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIvD;;;;;;;;;;;;OAYG;WACW,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAS5D;;;;;;;;;;;;OAYG;WACW,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAc1E;;;;;;;;;;;OAWG;WACW,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAiBtE;;;;;;;;OAQG;WACW,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;CAchD"}
|
package/esm/path-helper.js
CHANGED
|
@@ -62,5 +62,141 @@ export class PathHelper {
|
|
|
62
62
|
static normalize(path) {
|
|
63
63
|
return this.getSegments(path).join('/');
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Trims only the trailing slash from a URL or path
|
|
67
|
+
* @param url The URL or path to trim
|
|
68
|
+
* @returns The URL/path without trailing slash
|
|
69
|
+
* @example
|
|
70
|
+
* PathHelper.trimTrailingSlash('/api/') // '/api'
|
|
71
|
+
* PathHelper.trimTrailingSlash('http://example.com/') // 'http://example.com'
|
|
72
|
+
*/
|
|
73
|
+
static trimTrailingSlash(url) {
|
|
74
|
+
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Trims only the leading slash from a path
|
|
78
|
+
* @param path The path to trim
|
|
79
|
+
* @returns The path without leading slash
|
|
80
|
+
* @example
|
|
81
|
+
* PathHelper.trimLeadingSlash('/api') // 'api'
|
|
82
|
+
* PathHelper.trimLeadingSlash('api') // 'api'
|
|
83
|
+
*/
|
|
84
|
+
static trimLeadingSlash(path) {
|
|
85
|
+
return path.startsWith('/') ? path.slice(1) : path;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Ensures a path has a leading slash
|
|
89
|
+
* @param path The path to check
|
|
90
|
+
* @returns The path with a leading slash
|
|
91
|
+
* @example
|
|
92
|
+
* PathHelper.ensureLeadingSlash('api') // '/api'
|
|
93
|
+
* PathHelper.ensureLeadingSlash('/api') // '/api'
|
|
94
|
+
*/
|
|
95
|
+
static ensureLeadingSlash(path) {
|
|
96
|
+
return path.startsWith('/') ? path : `/${path}`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Normalizes a base URL by ensuring it has no trailing slash
|
|
100
|
+
* @param baseUrl The base URL to normalize (e.g., 'http://example.com/' or '/api/')
|
|
101
|
+
* @returns The normalized base URL without trailing slash
|
|
102
|
+
* @example
|
|
103
|
+
* PathHelper.normalizeBaseUrl('http://example.com/') // 'http://example.com'
|
|
104
|
+
* PathHelper.normalizeBaseUrl('/api/') // '/api'
|
|
105
|
+
* PathHelper.normalizeBaseUrl('/api') // '/api'
|
|
106
|
+
*/
|
|
107
|
+
static normalizeBaseUrl(baseUrl) {
|
|
108
|
+
return this.trimTrailingSlash(baseUrl);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Joins a base URL with a path, handling slashes correctly
|
|
112
|
+
* Preserves protocols (http://, https://, etc.)
|
|
113
|
+
* @param baseUrl The base URL (with or without trailing slash)
|
|
114
|
+
* @param path The path to append (with or without leading slash)
|
|
115
|
+
* @returns The combined URL with correct slash handling
|
|
116
|
+
* @example
|
|
117
|
+
* PathHelper.joinUrl('http://example.com', '/path') // 'http://example.com/path'
|
|
118
|
+
* PathHelper.joinUrl('http://example.com/', 'path') // 'http://example.com/path'
|
|
119
|
+
* PathHelper.joinUrl('/api', '/users') // '/api/users'
|
|
120
|
+
* PathHelper.joinUrl('/api/', 'users') // '/api/users'
|
|
121
|
+
* PathHelper.joinUrl('http://example.com', '') // 'http://example.com'
|
|
122
|
+
*/
|
|
123
|
+
static joinUrl(baseUrl, path) {
|
|
124
|
+
if (!path) {
|
|
125
|
+
return this.normalizeBaseUrl(baseUrl);
|
|
126
|
+
}
|
|
127
|
+
const normalizedBase = this.normalizeBaseUrl(baseUrl);
|
|
128
|
+
const normalizedPath = this.ensureLeadingSlash(path);
|
|
129
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Checks if a request URL matches a base URL pattern
|
|
133
|
+
* Handles trailing slash variations correctly
|
|
134
|
+
* @param requestUrl The incoming request URL
|
|
135
|
+
* @param baseUrl The base URL pattern to match against
|
|
136
|
+
* @returns true if the request URL matches the base URL
|
|
137
|
+
* @example
|
|
138
|
+
* PathHelper.matchesBaseUrl('/api/users', '/api') // true
|
|
139
|
+
* PathHelper.matchesBaseUrl('/api', '/api') // true
|
|
140
|
+
* PathHelper.matchesBaseUrl('/api', '/api/') // true
|
|
141
|
+
* PathHelper.matchesBaseUrl('/other', '/api') // false
|
|
142
|
+
* PathHelper.matchesBaseUrl('/api2', '/api') // false (not a path match)
|
|
143
|
+
*/
|
|
144
|
+
static matchesBaseUrl(requestUrl, baseUrl) {
|
|
145
|
+
const normalizedBase = this.normalizeBaseUrl(baseUrl);
|
|
146
|
+
const normalizedRequest = requestUrl;
|
|
147
|
+
// Exact match
|
|
148
|
+
if (normalizedRequest === normalizedBase) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
// Check if request starts with base followed by a slash
|
|
152
|
+
// This prevents '/api2' from matching '/api'
|
|
153
|
+
return normalizedRequest.startsWith(`${normalizedBase}/`);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Extracts the remaining path after a base URL
|
|
157
|
+
* Always returns a path with a leading slash (or empty string for exact matches)
|
|
158
|
+
* @param requestUrl The full request URL
|
|
159
|
+
* @param baseUrl The base URL to remove
|
|
160
|
+
* @returns The remaining path with leading slash, or empty string if exact match
|
|
161
|
+
* @example
|
|
162
|
+
* PathHelper.extractPath('/api/users', '/api') // '/users'
|
|
163
|
+
* PathHelper.extractPath('/api', '/api') // ''
|
|
164
|
+
* PathHelper.extractPath('/api/users?id=1', '/api') // '/users?id=1'
|
|
165
|
+
* PathHelper.extractPath('/api/', '/api') // '/'
|
|
166
|
+
*/
|
|
167
|
+
static extractPath(requestUrl, baseUrl) {
|
|
168
|
+
const normalizedBase = this.normalizeBaseUrl(baseUrl);
|
|
169
|
+
// Exact match
|
|
170
|
+
if (requestUrl === normalizedBase) {
|
|
171
|
+
return '';
|
|
172
|
+
}
|
|
173
|
+
// If request doesn't match base, return the original request URL
|
|
174
|
+
if (!this.matchesBaseUrl(requestUrl, baseUrl)) {
|
|
175
|
+
return requestUrl;
|
|
176
|
+
}
|
|
177
|
+
// Extract the path after the base
|
|
178
|
+
return requestUrl.substring(normalizedBase.length);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Normalizes a URL by removing consecutive slashes (except after protocol)
|
|
182
|
+
* @param url The URL to normalize
|
|
183
|
+
* @returns The normalized URL
|
|
184
|
+
* @example
|
|
185
|
+
* PathHelper.normalizeUrl('http://example.com//path') // 'http://example.com/path'
|
|
186
|
+
* PathHelper.normalizeUrl('/api//users///123') // '/api/users/123'
|
|
187
|
+
* PathHelper.normalizeUrl('http://example.com/') // 'http://example.com/'
|
|
188
|
+
*/
|
|
189
|
+
static normalizeUrl(url) {
|
|
190
|
+
// Handle protocol separately to preserve ://
|
|
191
|
+
const protocolMatch = url.match(/^([a-z][a-z0-9+.-]*:\/\/)(.*)$/i);
|
|
192
|
+
if (protocolMatch) {
|
|
193
|
+
const [, protocol, rest] = protocolMatch;
|
|
194
|
+
// Remove consecutive slashes from the rest
|
|
195
|
+
const normalized = rest.replace(/\/+/g, '/');
|
|
196
|
+
return `${protocol}${normalized}`;
|
|
197
|
+
}
|
|
198
|
+
// No protocol, just remove consecutive slashes
|
|
199
|
+
return url.replace(/\/+/g, '/');
|
|
200
|
+
}
|
|
65
201
|
}
|
|
66
202
|
//# sourceMappingURL=path-helper.js.map
|
package/esm/path-helper.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-helper.js","sourceRoot":"","sources":["../src/path-helper.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,UAAU;IACrB;;;;OAIG;IACI,MAAM,CAAC,WAAW,CAAC,IAAY;QACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAC3C,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACvC,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,WAAW,CAAC,IAAY;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACvE,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,SAAS,CAAC,GAAG,IAAc;QACvC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7D,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,YAAY,CAAC,YAAoB,EAAE,cAAsB;QACrE,OAAO,cAAc,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACzE,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,aAAa,CAAC,IAAY;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,QAAQ,CAAC,GAAG,EAAE,CAAA;QAChB,CAAC;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IAEM,MAAM,CAAC,SAAS,CAAC,IAAY;QAClC,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzC,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"path-helper.js","sourceRoot":"","sources":["../src/path-helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-helper.spec.d.ts","sourceRoot":"","sources":["../src/path-helper.spec.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"path-helper.spec.d.ts","sourceRoot":"","sources":["../src/path-helper.spec.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,eAAe,yCAuT1B,CAAA"}
|
package/esm/path-helper.spec.js
CHANGED
|
@@ -64,5 +64,183 @@ export const pathHelperTests = describe('PathHelper', () => {
|
|
|
64
64
|
expect(PathHelper.normalize('/Root/Example/Content/')).toBe('Root/Example/Content');
|
|
65
65
|
});
|
|
66
66
|
});
|
|
67
|
+
describe('#trimTrailingSlash()', () => {
|
|
68
|
+
it('should remove trailing slash', () => {
|
|
69
|
+
expect(PathHelper.trimTrailingSlash('/api/')).toBe('/api');
|
|
70
|
+
});
|
|
71
|
+
it('should handle URLs with trailing slash', () => {
|
|
72
|
+
expect(PathHelper.trimTrailingSlash('http://example.com/')).toBe('http://example.com');
|
|
73
|
+
});
|
|
74
|
+
it('should not modify paths without trailing slash', () => {
|
|
75
|
+
expect(PathHelper.trimTrailingSlash('/api')).toBe('/api');
|
|
76
|
+
});
|
|
77
|
+
it('should handle empty string', () => {
|
|
78
|
+
expect(PathHelper.trimTrailingSlash('')).toBe('');
|
|
79
|
+
});
|
|
80
|
+
it('should handle root path', () => {
|
|
81
|
+
expect(PathHelper.trimTrailingSlash('/')).toBe('');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe('#trimLeadingSlash()', () => {
|
|
85
|
+
it('should remove leading slash', () => {
|
|
86
|
+
expect(PathHelper.trimLeadingSlash('/api')).toBe('api');
|
|
87
|
+
});
|
|
88
|
+
it('should not modify paths without leading slash', () => {
|
|
89
|
+
expect(PathHelper.trimLeadingSlash('api')).toBe('api');
|
|
90
|
+
});
|
|
91
|
+
it('should handle empty string', () => {
|
|
92
|
+
expect(PathHelper.trimLeadingSlash('')).toBe('');
|
|
93
|
+
});
|
|
94
|
+
it('should handle root path', () => {
|
|
95
|
+
expect(PathHelper.trimLeadingSlash('/')).toBe('');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('#ensureLeadingSlash()', () => {
|
|
99
|
+
it('should add leading slash when missing', () => {
|
|
100
|
+
expect(PathHelper.ensureLeadingSlash('api')).toBe('/api');
|
|
101
|
+
});
|
|
102
|
+
it('should not add extra slash when already present', () => {
|
|
103
|
+
expect(PathHelper.ensureLeadingSlash('/api')).toBe('/api');
|
|
104
|
+
});
|
|
105
|
+
it('should handle empty string', () => {
|
|
106
|
+
expect(PathHelper.ensureLeadingSlash('')).toBe('/');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
describe('#normalizeBaseUrl()', () => {
|
|
110
|
+
it('should remove trailing slash from URL', () => {
|
|
111
|
+
expect(PathHelper.normalizeBaseUrl('http://example.com/')).toBe('http://example.com');
|
|
112
|
+
});
|
|
113
|
+
it('should remove trailing slash from path', () => {
|
|
114
|
+
expect(PathHelper.normalizeBaseUrl('/api/')).toBe('/api');
|
|
115
|
+
});
|
|
116
|
+
it('should not modify URL without trailing slash', () => {
|
|
117
|
+
expect(PathHelper.normalizeBaseUrl('/api')).toBe('/api');
|
|
118
|
+
});
|
|
119
|
+
it('should handle HTTPS URLs', () => {
|
|
120
|
+
expect(PathHelper.normalizeBaseUrl('https://example.com/')).toBe('https://example.com');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe('#joinUrl()', () => {
|
|
124
|
+
it('should join URL with path (both with slashes)', () => {
|
|
125
|
+
expect(PathHelper.joinUrl('http://example.com/', '/path')).toBe('http://example.com/path');
|
|
126
|
+
});
|
|
127
|
+
it('should join URL with path (URL with slash)', () => {
|
|
128
|
+
expect(PathHelper.joinUrl('http://example.com/', 'path')).toBe('http://example.com/path');
|
|
129
|
+
});
|
|
130
|
+
it('should join URL with path (path with slash)', () => {
|
|
131
|
+
expect(PathHelper.joinUrl('http://example.com', '/path')).toBe('http://example.com/path');
|
|
132
|
+
});
|
|
133
|
+
it('should join URL with path (neither with slash)', () => {
|
|
134
|
+
expect(PathHelper.joinUrl('http://example.com', 'path')).toBe('http://example.com/path');
|
|
135
|
+
});
|
|
136
|
+
it('should join relative paths', () => {
|
|
137
|
+
expect(PathHelper.joinUrl('/api', '/users')).toBe('/api/users');
|
|
138
|
+
expect(PathHelper.joinUrl('/api/', 'users')).toBe('/api/users');
|
|
139
|
+
});
|
|
140
|
+
it('should handle empty path', () => {
|
|
141
|
+
expect(PathHelper.joinUrl('http://example.com', '')).toBe('http://example.com');
|
|
142
|
+
expect(PathHelper.joinUrl('http://example.com/', '')).toBe('http://example.com');
|
|
143
|
+
});
|
|
144
|
+
it('should handle complex paths', () => {
|
|
145
|
+
expect(PathHelper.joinUrl('http://example.com:8080', '/api/v1/users')).toBe('http://example.com:8080/api/v1/users');
|
|
146
|
+
});
|
|
147
|
+
it('should preserve HTTPS protocol', () => {
|
|
148
|
+
expect(PathHelper.joinUrl('https://secure.example.com', '/secure/path')).toBe('https://secure.example.com/secure/path');
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('#matchesBaseUrl()', () => {
|
|
152
|
+
it('should match exact URL', () => {
|
|
153
|
+
expect(PathHelper.matchesBaseUrl('/api', '/api')).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
it('should match URL with trailing slash in base', () => {
|
|
156
|
+
expect(PathHelper.matchesBaseUrl('/api', '/api/')).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
it('should match URL starting with base', () => {
|
|
159
|
+
expect(PathHelper.matchesBaseUrl('/api/users', '/api')).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
it('should not match different URL', () => {
|
|
162
|
+
expect(PathHelper.matchesBaseUrl('/other', '/api')).toBe(false);
|
|
163
|
+
});
|
|
164
|
+
it('should not match similar prefix without slash', () => {
|
|
165
|
+
expect(PathHelper.matchesBaseUrl('/api2', '/api')).toBe(false);
|
|
166
|
+
expect(PathHelper.matchesBaseUrl('/api-v2', '/api')).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
it('should match nested paths', () => {
|
|
169
|
+
expect(PathHelper.matchesBaseUrl('/api/v1/users/123', '/api')).toBe(true);
|
|
170
|
+
expect(PathHelper.matchesBaseUrl('/api/v1/users/123', '/api/v1')).toBe(true);
|
|
171
|
+
});
|
|
172
|
+
it('should handle root path', () => {
|
|
173
|
+
expect(PathHelper.matchesBaseUrl('/api', '/')).toBe(true);
|
|
174
|
+
expect(PathHelper.matchesBaseUrl('/', '/')).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
it('should match with query string', () => {
|
|
177
|
+
expect(PathHelper.matchesBaseUrl('/api/users?page=1', '/api')).toBe(true);
|
|
178
|
+
});
|
|
179
|
+
it('should match with trailing slash in request', () => {
|
|
180
|
+
expect(PathHelper.matchesBaseUrl('/api/', '/api')).toBe(true);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe('#extractPath()', () => {
|
|
184
|
+
it('should extract path after base URL', () => {
|
|
185
|
+
expect(PathHelper.extractPath('/api/users', '/api')).toBe('/users');
|
|
186
|
+
});
|
|
187
|
+
it('should return empty string for exact match', () => {
|
|
188
|
+
expect(PathHelper.extractPath('/api', '/api')).toBe('');
|
|
189
|
+
});
|
|
190
|
+
it('should preserve query string', () => {
|
|
191
|
+
expect(PathHelper.extractPath('/api/users?id=1', '/api')).toBe('/users?id=1');
|
|
192
|
+
});
|
|
193
|
+
it('should handle trailing slash in request', () => {
|
|
194
|
+
expect(PathHelper.extractPath('/api/', '/api')).toBe('/');
|
|
195
|
+
});
|
|
196
|
+
it('should handle trailing slash in base', () => {
|
|
197
|
+
expect(PathHelper.extractPath('/api/users', '/api/')).toBe('/users');
|
|
198
|
+
});
|
|
199
|
+
it('should extract nested paths', () => {
|
|
200
|
+
expect(PathHelper.extractPath('/api/v1/users/123', '/api')).toBe('/v1/users/123');
|
|
201
|
+
expect(PathHelper.extractPath('/api/v1/users/123', '/api/v1')).toBe('/users/123');
|
|
202
|
+
});
|
|
203
|
+
it('should return original URL if no match', () => {
|
|
204
|
+
expect(PathHelper.extractPath('/other/path', '/api')).toBe('/other/path');
|
|
205
|
+
});
|
|
206
|
+
it('should handle complex query strings', () => {
|
|
207
|
+
expect(PathHelper.extractPath('/api/search?q=test&limit=10&offset=0', '/api')).toBe('/search?q=test&limit=10&offset=0');
|
|
208
|
+
});
|
|
209
|
+
it('should preserve fragments', () => {
|
|
210
|
+
expect(PathHelper.extractPath('/api/page#section', '/api')).toBe('/page#section');
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
describe('#normalizeUrl()', () => {
|
|
214
|
+
it('should remove double slashes from path', () => {
|
|
215
|
+
expect(PathHelper.normalizeUrl('/api//users')).toBe('/api/users');
|
|
216
|
+
});
|
|
217
|
+
it('should remove multiple consecutive slashes', () => {
|
|
218
|
+
expect(PathHelper.normalizeUrl('/api///users////123')).toBe('/api/users/123');
|
|
219
|
+
});
|
|
220
|
+
it('should preserve protocol slashes', () => {
|
|
221
|
+
expect(PathHelper.normalizeUrl('http://example.com//path')).toBe('http://example.com/path');
|
|
222
|
+
});
|
|
223
|
+
it('should handle HTTPS protocol', () => {
|
|
224
|
+
expect(PathHelper.normalizeUrl('https://example.com///path//to///resource')).toBe('https://example.com/path/to/resource');
|
|
225
|
+
});
|
|
226
|
+
it('should not modify already normalized URLs', () => {
|
|
227
|
+
expect(PathHelper.normalizeUrl('http://example.com/path')).toBe('http://example.com/path');
|
|
228
|
+
expect(PathHelper.normalizeUrl('/api/users')).toBe('/api/users');
|
|
229
|
+
});
|
|
230
|
+
it('should handle trailing slash', () => {
|
|
231
|
+
expect(PathHelper.normalizeUrl('http://example.com/')).toBe('http://example.com/');
|
|
232
|
+
expect(PathHelper.normalizeUrl('/api/')).toBe('/api/');
|
|
233
|
+
});
|
|
234
|
+
it('should handle custom protocols', () => {
|
|
235
|
+
expect(PathHelper.normalizeUrl('ftp://example.com//path')).toBe('ftp://example.com/path');
|
|
236
|
+
expect(PathHelper.normalizeUrl('ws://example.com//socket')).toBe('ws://example.com/socket');
|
|
237
|
+
});
|
|
238
|
+
it('should handle URLs with port', () => {
|
|
239
|
+
expect(PathHelper.normalizeUrl('http://example.com:8080//path')).toBe('http://example.com:8080/path');
|
|
240
|
+
});
|
|
241
|
+
it('should preserve query strings', () => {
|
|
242
|
+
expect(PathHelper.normalizeUrl('/api//users?page=1')).toBe('/api/users?page=1');
|
|
243
|
+
});
|
|
244
|
+
});
|
|
67
245
|
});
|
|
68
246
|
//# sourceMappingURL=path-helper.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-helper.spec.js","sourceRoot":"","sources":["../src/path-helper.spec.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"path-helper.spec.js","sourceRoot":"","sources":["../src/path-helper.spec.ts"],"names":[],"mappings":"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"}
|
package/esm/sort-by.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ declare global {
|
|
|
4
4
|
*/
|
|
5
5
|
export interface Array<T> {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Sorts the array by a specified field and direction
|
|
8
|
+
* @param field The field to sort by
|
|
9
|
+
* @param direction The sort direction, either 'asc' or 'desc' (default: 'asc')
|
|
10
|
+
* @returns A new sorted array
|
|
8
11
|
*/
|
|
9
12
|
sortBy: (field: keyof T, direction?: 'asc' | 'desc') => T[];
|
|
10
13
|
}
|
package/esm/sort-by.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-by.d.ts","sourceRoot":"","sources":["../src/sort-by.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,WAAW,KAAK,CAAC,CAAC;QACtB
|
|
1
|
+
{"version":3,"file":"sort-by.d.ts","sourceRoot":"","sources":["../src/sort-by.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,WAAW,KAAK,CAAC,CAAC;QACtB;;;;;WAKG;QACH,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,KAAK,CAAC,EAAE,CAAA;KAC5D;CACF;AAED,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,GAAG,MAAM,eAU1G,CAAA"}
|
package/esm/sort-by.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sort-by.js","sourceRoot":"","sources":["../src/sort-by.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sort-by.js","sourceRoot":"","sources":["../src/sort-by.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,SAAS,GAAG,CAAuB,OAAU,EAAE,OAAU,EAAE,KAAQ,EAAE,SAAyB,EAAE,EAAE;IAC7G,MAAM,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;IACjD,MAAM,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAA;IACjD,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC,CAAA;IACX,CAAC;IACD,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,CAAA;IACV,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC,CAAA;AAED,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,UAAU,GAAG,EAAE,SAAS,GAAG,KAAK;IACvD,+DAA+D;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAA;AAC7D,CAAC,CAAA"}
|
package/esm/using-async.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Method that accepts
|
|
2
|
+
* Method that accepts a Disposable or AsyncDisposable resource that will be disposed after the callback
|
|
3
3
|
* @param resource The resource that is used in the callback and will be disposed afterwards
|
|
4
|
-
* @param callback The callback that will be executed
|
|
4
|
+
* @param callback The callback that will be executed asynchronously before the resource will be disposed
|
|
5
5
|
* @returns A promise that will be resolved with a return value after the resource is disposed
|
|
6
6
|
*/
|
|
7
7
|
export declare const usingAsync: <T extends Disposable | AsyncDisposable, TReturns>(resource: T, callback: (r: T) => Promise<TReturns>) => Promise<TReturns>;
|
package/esm/using-async.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isAsyncDisposable } from './is-async-disposable.js';
|
|
2
2
|
import { isDisposable } from './is-disposable.js';
|
|
3
3
|
/**
|
|
4
|
-
* Method that accepts
|
|
4
|
+
* Method that accepts a Disposable or AsyncDisposable resource that will be disposed after the callback
|
|
5
5
|
* @param resource The resource that is used in the callback and will be disposed afterwards
|
|
6
|
-
* @param callback The callback that will be executed
|
|
6
|
+
* @param callback The callback that will be executed asynchronously before the resource will be disposed
|
|
7
7
|
* @returns A promise that will be resolved with a return value after the resource is disposed
|
|
8
8
|
*/
|
|
9
9
|
export const usingAsync = async (resource, callback) => {
|
package/esm/using.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Method that accepts
|
|
2
|
+
* Method that accepts a Disposable resource that will be disposed after the callback
|
|
3
3
|
* @param resource The resource that is used in the callback and will be disposed afterwards
|
|
4
|
-
* @param callback The callback that will be executed
|
|
4
|
+
* @param callback The callback that will be executed synchronously before the resource will be disposed
|
|
5
5
|
* @returns the value that will be returned by the callback method
|
|
6
6
|
*/
|
|
7
7
|
export declare const using: <T extends Disposable, TReturns>(resource: T, callback: (r: T) => TReturns) => TReturns;
|
package/esm/using.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Method that accepts
|
|
2
|
+
* Method that accepts a Disposable resource that will be disposed after the callback
|
|
3
3
|
* @param resource The resource that is used in the callback and will be disposed afterwards
|
|
4
|
-
* @param callback The callback that will be executed
|
|
4
|
+
* @param callback The callback that will be executed synchronously before the resource will be disposed
|
|
5
5
|
* @returns the value that will be returned by the callback method
|
|
6
6
|
*/
|
|
7
7
|
export const using = (resource, callback) => {
|
package/esm/value-observer.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export declare class ValueObserver<T> implements Disposable {
|
|
|
33
33
|
*/
|
|
34
34
|
[Symbol.dispose](): void;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Creates a ValueObserver instance
|
|
37
37
|
* @param observable The related Observable object
|
|
38
38
|
* @param callback The callback that will be fired on change
|
|
39
39
|
* @param options Additional options
|
package/esm/value-observer.js
CHANGED
|
@@ -31,7 +31,7 @@ export class ValueObserver {
|
|
|
31
31
|
this.observable.unsubscribe(this);
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Creates a ValueObserver instance
|
|
35
35
|
* @param observable The related Observable object
|
|
36
36
|
* @param callback The callback that will be fired on change
|
|
37
37
|
* @param options Additional options
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/utils",
|
|
3
|
-
"version": "8.1.
|
|
3
|
+
"version": "8.1.5",
|
|
4
4
|
"description": "General utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -35,6 +35,6 @@
|
|
|
35
35
|
"homepage": "https://github.com/furystack/furystack",
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"typescript": "^5.9.3",
|
|
38
|
-
"vitest": "^
|
|
38
|
+
"vitest": "^4.0.10"
|
|
39
39
|
}
|
|
40
40
|
}
|
package/src/deep-merge.ts
CHANGED
|
@@ -5,8 +5,8 @@ export type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Deep merge two objects.
|
|
8
|
-
* @param
|
|
9
|
-
* @param sources The source objects
|
|
8
|
+
* @param target The target object to be merged into
|
|
9
|
+
* @param sources The source objects to merge
|
|
10
10
|
* @returns A new instance with the merged values
|
|
11
11
|
*/
|
|
12
12
|
export const deepMerge = <T>(target: T, ...sources: Array<DeepPartial<T> | undefined>) => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
2
|
* @param value The value to check
|
|
4
|
-
* @returns
|
|
3
|
+
* @returns whether the value is an instance of an async disposable object
|
|
5
4
|
*/
|
|
6
5
|
export const isAsyncDisposable = (value: unknown): value is AsyncDisposable => {
|
|
7
6
|
return (value as AsyncDisposable)?.[Symbol.asyncDispose] instanceof Function
|
package/src/is-disposable.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
2
|
* @param value The value to check
|
|
4
|
-
* @returns
|
|
3
|
+
* @returns whether the value is an instance of a disposable object
|
|
5
4
|
*/
|
|
6
5
|
export const isDisposable = (value: unknown): value is Disposable => {
|
|
7
6
|
return (value as Disposable)?.[Symbol.dispose] instanceof Function
|
package/src/observable-value.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type ObservableValueOptions<T> = {
|
|
|
20
20
|
* Defines a custom compare function to determine if the value should be updated and the observers should be notified
|
|
21
21
|
* @param lastValue the last value
|
|
22
22
|
* @param nextValue the next value
|
|
23
|
-
* @returns
|
|
23
|
+
* @returns whether the value should be updated and the observers should be notified
|
|
24
24
|
*/
|
|
25
25
|
compare: (lastValue: T, nextValue: T) => boolean
|
|
26
26
|
}
|
|
@@ -84,7 +84,7 @@ export class ObservableValue<T> implements Disposable {
|
|
|
84
84
|
/**
|
|
85
85
|
* The observer will unsubscribe from the Observable
|
|
86
86
|
* @param observer The ValueObserver instance
|
|
87
|
-
* @returns
|
|
87
|
+
* @returns whether unsubscribing was successful
|
|
88
88
|
*/
|
|
89
89
|
public unsubscribe(observer: ValueObserver<T>) {
|
|
90
90
|
return this.observers.delete(observer)
|
package/src/path-helper.spec.ts
CHANGED
|
@@ -78,4 +78,241 @@ export const pathHelperTests = describe('PathHelper', () => {
|
|
|
78
78
|
expect(PathHelper.normalize('/Root/Example/Content/')).toBe('Root/Example/Content')
|
|
79
79
|
})
|
|
80
80
|
})
|
|
81
|
+
|
|
82
|
+
describe('#trimTrailingSlash()', () => {
|
|
83
|
+
it('should remove trailing slash', () => {
|
|
84
|
+
expect(PathHelper.trimTrailingSlash('/api/')).toBe('/api')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('should handle URLs with trailing slash', () => {
|
|
88
|
+
expect(PathHelper.trimTrailingSlash('http://example.com/')).toBe('http://example.com')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('should not modify paths without trailing slash', () => {
|
|
92
|
+
expect(PathHelper.trimTrailingSlash('/api')).toBe('/api')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should handle empty string', () => {
|
|
96
|
+
expect(PathHelper.trimTrailingSlash('')).toBe('')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('should handle root path', () => {
|
|
100
|
+
expect(PathHelper.trimTrailingSlash('/')).toBe('')
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
describe('#trimLeadingSlash()', () => {
|
|
105
|
+
it('should remove leading slash', () => {
|
|
106
|
+
expect(PathHelper.trimLeadingSlash('/api')).toBe('api')
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should not modify paths without leading slash', () => {
|
|
110
|
+
expect(PathHelper.trimLeadingSlash('api')).toBe('api')
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('should handle empty string', () => {
|
|
114
|
+
expect(PathHelper.trimLeadingSlash('')).toBe('')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('should handle root path', () => {
|
|
118
|
+
expect(PathHelper.trimLeadingSlash('/')).toBe('')
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
describe('#ensureLeadingSlash()', () => {
|
|
123
|
+
it('should add leading slash when missing', () => {
|
|
124
|
+
expect(PathHelper.ensureLeadingSlash('api')).toBe('/api')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('should not add extra slash when already present', () => {
|
|
128
|
+
expect(PathHelper.ensureLeadingSlash('/api')).toBe('/api')
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('should handle empty string', () => {
|
|
132
|
+
expect(PathHelper.ensureLeadingSlash('')).toBe('/')
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
describe('#normalizeBaseUrl()', () => {
|
|
137
|
+
it('should remove trailing slash from URL', () => {
|
|
138
|
+
expect(PathHelper.normalizeBaseUrl('http://example.com/')).toBe('http://example.com')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should remove trailing slash from path', () => {
|
|
142
|
+
expect(PathHelper.normalizeBaseUrl('/api/')).toBe('/api')
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('should not modify URL without trailing slash', () => {
|
|
146
|
+
expect(PathHelper.normalizeBaseUrl('/api')).toBe('/api')
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('should handle HTTPS URLs', () => {
|
|
150
|
+
expect(PathHelper.normalizeBaseUrl('https://example.com/')).toBe('https://example.com')
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
describe('#joinUrl()', () => {
|
|
155
|
+
it('should join URL with path (both with slashes)', () => {
|
|
156
|
+
expect(PathHelper.joinUrl('http://example.com/', '/path')).toBe('http://example.com/path')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('should join URL with path (URL with slash)', () => {
|
|
160
|
+
expect(PathHelper.joinUrl('http://example.com/', 'path')).toBe('http://example.com/path')
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('should join URL with path (path with slash)', () => {
|
|
164
|
+
expect(PathHelper.joinUrl('http://example.com', '/path')).toBe('http://example.com/path')
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('should join URL with path (neither with slash)', () => {
|
|
168
|
+
expect(PathHelper.joinUrl('http://example.com', 'path')).toBe('http://example.com/path')
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('should join relative paths', () => {
|
|
172
|
+
expect(PathHelper.joinUrl('/api', '/users')).toBe('/api/users')
|
|
173
|
+
expect(PathHelper.joinUrl('/api/', 'users')).toBe('/api/users')
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
it('should handle empty path', () => {
|
|
177
|
+
expect(PathHelper.joinUrl('http://example.com', '')).toBe('http://example.com')
|
|
178
|
+
expect(PathHelper.joinUrl('http://example.com/', '')).toBe('http://example.com')
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('should handle complex paths', () => {
|
|
182
|
+
expect(PathHelper.joinUrl('http://example.com:8080', '/api/v1/users')).toBe(
|
|
183
|
+
'http://example.com:8080/api/v1/users',
|
|
184
|
+
)
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('should preserve HTTPS protocol', () => {
|
|
188
|
+
expect(PathHelper.joinUrl('https://secure.example.com', '/secure/path')).toBe(
|
|
189
|
+
'https://secure.example.com/secure/path',
|
|
190
|
+
)
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
describe('#matchesBaseUrl()', () => {
|
|
195
|
+
it('should match exact URL', () => {
|
|
196
|
+
expect(PathHelper.matchesBaseUrl('/api', '/api')).toBe(true)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it('should match URL with trailing slash in base', () => {
|
|
200
|
+
expect(PathHelper.matchesBaseUrl('/api', '/api/')).toBe(true)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('should match URL starting with base', () => {
|
|
204
|
+
expect(PathHelper.matchesBaseUrl('/api/users', '/api')).toBe(true)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
it('should not match different URL', () => {
|
|
208
|
+
expect(PathHelper.matchesBaseUrl('/other', '/api')).toBe(false)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('should not match similar prefix without slash', () => {
|
|
212
|
+
expect(PathHelper.matchesBaseUrl('/api2', '/api')).toBe(false)
|
|
213
|
+
expect(PathHelper.matchesBaseUrl('/api-v2', '/api')).toBe(false)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it('should match nested paths', () => {
|
|
217
|
+
expect(PathHelper.matchesBaseUrl('/api/v1/users/123', '/api')).toBe(true)
|
|
218
|
+
expect(PathHelper.matchesBaseUrl('/api/v1/users/123', '/api/v1')).toBe(true)
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('should handle root path', () => {
|
|
222
|
+
expect(PathHelper.matchesBaseUrl('/api', '/')).toBe(true)
|
|
223
|
+
expect(PathHelper.matchesBaseUrl('/', '/')).toBe(true)
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('should match with query string', () => {
|
|
227
|
+
expect(PathHelper.matchesBaseUrl('/api/users?page=1', '/api')).toBe(true)
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('should match with trailing slash in request', () => {
|
|
231
|
+
expect(PathHelper.matchesBaseUrl('/api/', '/api')).toBe(true)
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
describe('#extractPath()', () => {
|
|
236
|
+
it('should extract path after base URL', () => {
|
|
237
|
+
expect(PathHelper.extractPath('/api/users', '/api')).toBe('/users')
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('should return empty string for exact match', () => {
|
|
241
|
+
expect(PathHelper.extractPath('/api', '/api')).toBe('')
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('should preserve query string', () => {
|
|
245
|
+
expect(PathHelper.extractPath('/api/users?id=1', '/api')).toBe('/users?id=1')
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it('should handle trailing slash in request', () => {
|
|
249
|
+
expect(PathHelper.extractPath('/api/', '/api')).toBe('/')
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('should handle trailing slash in base', () => {
|
|
253
|
+
expect(PathHelper.extractPath('/api/users', '/api/')).toBe('/users')
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('should extract nested paths', () => {
|
|
257
|
+
expect(PathHelper.extractPath('/api/v1/users/123', '/api')).toBe('/v1/users/123')
|
|
258
|
+
expect(PathHelper.extractPath('/api/v1/users/123', '/api/v1')).toBe('/users/123')
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
it('should return original URL if no match', () => {
|
|
262
|
+
expect(PathHelper.extractPath('/other/path', '/api')).toBe('/other/path')
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('should handle complex query strings', () => {
|
|
266
|
+
expect(PathHelper.extractPath('/api/search?q=test&limit=10&offset=0', '/api')).toBe(
|
|
267
|
+
'/search?q=test&limit=10&offset=0',
|
|
268
|
+
)
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('should preserve fragments', () => {
|
|
272
|
+
expect(PathHelper.extractPath('/api/page#section', '/api')).toBe('/page#section')
|
|
273
|
+
})
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
describe('#normalizeUrl()', () => {
|
|
277
|
+
it('should remove double slashes from path', () => {
|
|
278
|
+
expect(PathHelper.normalizeUrl('/api//users')).toBe('/api/users')
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it('should remove multiple consecutive slashes', () => {
|
|
282
|
+
expect(PathHelper.normalizeUrl('/api///users////123')).toBe('/api/users/123')
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it('should preserve protocol slashes', () => {
|
|
286
|
+
expect(PathHelper.normalizeUrl('http://example.com//path')).toBe('http://example.com/path')
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
it('should handle HTTPS protocol', () => {
|
|
290
|
+
expect(PathHelper.normalizeUrl('https://example.com///path//to///resource')).toBe(
|
|
291
|
+
'https://example.com/path/to/resource',
|
|
292
|
+
)
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
it('should not modify already normalized URLs', () => {
|
|
296
|
+
expect(PathHelper.normalizeUrl('http://example.com/path')).toBe('http://example.com/path')
|
|
297
|
+
expect(PathHelper.normalizeUrl('/api/users')).toBe('/api/users')
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
it('should handle trailing slash', () => {
|
|
301
|
+
expect(PathHelper.normalizeUrl('http://example.com/')).toBe('http://example.com/')
|
|
302
|
+
expect(PathHelper.normalizeUrl('/api/')).toBe('/api/')
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
it('should handle custom protocols', () => {
|
|
306
|
+
expect(PathHelper.normalizeUrl('ftp://example.com//path')).toBe('ftp://example.com/path')
|
|
307
|
+
expect(PathHelper.normalizeUrl('ws://example.com//socket')).toBe('ws://example.com/socket')
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
it('should handle URLs with port', () => {
|
|
311
|
+
expect(PathHelper.normalizeUrl('http://example.com:8080//path')).toBe('http://example.com:8080/path')
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it('should preserve query strings', () => {
|
|
315
|
+
expect(PathHelper.normalizeUrl('/api//users?page=1')).toBe('/api/users?page=1')
|
|
316
|
+
})
|
|
317
|
+
})
|
|
81
318
|
})
|
package/src/path-helper.ts
CHANGED
|
@@ -67,4 +67,155 @@ export class PathHelper {
|
|
|
67
67
|
public static normalize(path: string) {
|
|
68
68
|
return this.getSegments(path).join('/')
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Trims only the trailing slash from a URL or path
|
|
73
|
+
* @param url The URL or path to trim
|
|
74
|
+
* @returns The URL/path without trailing slash
|
|
75
|
+
* @example
|
|
76
|
+
* PathHelper.trimTrailingSlash('/api/') // '/api'
|
|
77
|
+
* PathHelper.trimTrailingSlash('http://example.com/') // 'http://example.com'
|
|
78
|
+
*/
|
|
79
|
+
public static trimTrailingSlash(url: string): string {
|
|
80
|
+
return url.endsWith('/') ? url.slice(0, -1) : url
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Trims only the leading slash from a path
|
|
85
|
+
* @param path The path to trim
|
|
86
|
+
* @returns The path without leading slash
|
|
87
|
+
* @example
|
|
88
|
+
* PathHelper.trimLeadingSlash('/api') // 'api'
|
|
89
|
+
* PathHelper.trimLeadingSlash('api') // 'api'
|
|
90
|
+
*/
|
|
91
|
+
public static trimLeadingSlash(path: string): string {
|
|
92
|
+
return path.startsWith('/') ? path.slice(1) : path
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Ensures a path has a leading slash
|
|
97
|
+
* @param path The path to check
|
|
98
|
+
* @returns The path with a leading slash
|
|
99
|
+
* @example
|
|
100
|
+
* PathHelper.ensureLeadingSlash('api') // '/api'
|
|
101
|
+
* PathHelper.ensureLeadingSlash('/api') // '/api'
|
|
102
|
+
*/
|
|
103
|
+
public static ensureLeadingSlash(path: string): string {
|
|
104
|
+
return path.startsWith('/') ? path : `/${path}`
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Normalizes a base URL by ensuring it has no trailing slash
|
|
109
|
+
* @param baseUrl The base URL to normalize (e.g., 'http://example.com/' or '/api/')
|
|
110
|
+
* @returns The normalized base URL without trailing slash
|
|
111
|
+
* @example
|
|
112
|
+
* PathHelper.normalizeBaseUrl('http://example.com/') // 'http://example.com'
|
|
113
|
+
* PathHelper.normalizeBaseUrl('/api/') // '/api'
|
|
114
|
+
* PathHelper.normalizeBaseUrl('/api') // '/api'
|
|
115
|
+
*/
|
|
116
|
+
public static normalizeBaseUrl(baseUrl: string): string {
|
|
117
|
+
return this.trimTrailingSlash(baseUrl)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Joins a base URL with a path, handling slashes correctly
|
|
122
|
+
* Preserves protocols (http://, https://, etc.)
|
|
123
|
+
* @param baseUrl The base URL (with or without trailing slash)
|
|
124
|
+
* @param path The path to append (with or without leading slash)
|
|
125
|
+
* @returns The combined URL with correct slash handling
|
|
126
|
+
* @example
|
|
127
|
+
* PathHelper.joinUrl('http://example.com', '/path') // 'http://example.com/path'
|
|
128
|
+
* PathHelper.joinUrl('http://example.com/', 'path') // 'http://example.com/path'
|
|
129
|
+
* PathHelper.joinUrl('/api', '/users') // '/api/users'
|
|
130
|
+
* PathHelper.joinUrl('/api/', 'users') // '/api/users'
|
|
131
|
+
* PathHelper.joinUrl('http://example.com', '') // 'http://example.com'
|
|
132
|
+
*/
|
|
133
|
+
public static joinUrl(baseUrl: string, path: string): string {
|
|
134
|
+
if (!path) {
|
|
135
|
+
return this.normalizeBaseUrl(baseUrl)
|
|
136
|
+
}
|
|
137
|
+
const normalizedBase = this.normalizeBaseUrl(baseUrl)
|
|
138
|
+
const normalizedPath = this.ensureLeadingSlash(path)
|
|
139
|
+
return `${normalizedBase}${normalizedPath}`
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Checks if a request URL matches a base URL pattern
|
|
144
|
+
* Handles trailing slash variations correctly
|
|
145
|
+
* @param requestUrl The incoming request URL
|
|
146
|
+
* @param baseUrl The base URL pattern to match against
|
|
147
|
+
* @returns true if the request URL matches the base URL
|
|
148
|
+
* @example
|
|
149
|
+
* PathHelper.matchesBaseUrl('/api/users', '/api') // true
|
|
150
|
+
* PathHelper.matchesBaseUrl('/api', '/api') // true
|
|
151
|
+
* PathHelper.matchesBaseUrl('/api', '/api/') // true
|
|
152
|
+
* PathHelper.matchesBaseUrl('/other', '/api') // false
|
|
153
|
+
* PathHelper.matchesBaseUrl('/api2', '/api') // false (not a path match)
|
|
154
|
+
*/
|
|
155
|
+
public static matchesBaseUrl(requestUrl: string, baseUrl: string): boolean {
|
|
156
|
+
const normalizedBase = this.normalizeBaseUrl(baseUrl)
|
|
157
|
+
const normalizedRequest = requestUrl
|
|
158
|
+
|
|
159
|
+
// Exact match
|
|
160
|
+
if (normalizedRequest === normalizedBase) {
|
|
161
|
+
return true
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Check if request starts with base followed by a slash
|
|
165
|
+
// This prevents '/api2' from matching '/api'
|
|
166
|
+
return normalizedRequest.startsWith(`${normalizedBase}/`)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Extracts the remaining path after a base URL
|
|
171
|
+
* Always returns a path with a leading slash (or empty string for exact matches)
|
|
172
|
+
* @param requestUrl The full request URL
|
|
173
|
+
* @param baseUrl The base URL to remove
|
|
174
|
+
* @returns The remaining path with leading slash, or empty string if exact match
|
|
175
|
+
* @example
|
|
176
|
+
* PathHelper.extractPath('/api/users', '/api') // '/users'
|
|
177
|
+
* PathHelper.extractPath('/api', '/api') // ''
|
|
178
|
+
* PathHelper.extractPath('/api/users?id=1', '/api') // '/users?id=1'
|
|
179
|
+
* PathHelper.extractPath('/api/', '/api') // '/'
|
|
180
|
+
*/
|
|
181
|
+
public static extractPath(requestUrl: string, baseUrl: string): string {
|
|
182
|
+
const normalizedBase = this.normalizeBaseUrl(baseUrl)
|
|
183
|
+
|
|
184
|
+
// Exact match
|
|
185
|
+
if (requestUrl === normalizedBase) {
|
|
186
|
+
return ''
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// If request doesn't match base, return the original request URL
|
|
190
|
+
if (!this.matchesBaseUrl(requestUrl, baseUrl)) {
|
|
191
|
+
return requestUrl
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Extract the path after the base
|
|
195
|
+
return requestUrl.substring(normalizedBase.length)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Normalizes a URL by removing consecutive slashes (except after protocol)
|
|
200
|
+
* @param url The URL to normalize
|
|
201
|
+
* @returns The normalized URL
|
|
202
|
+
* @example
|
|
203
|
+
* PathHelper.normalizeUrl('http://example.com//path') // 'http://example.com/path'
|
|
204
|
+
* PathHelper.normalizeUrl('/api//users///123') // '/api/users/123'
|
|
205
|
+
* PathHelper.normalizeUrl('http://example.com/') // 'http://example.com/'
|
|
206
|
+
*/
|
|
207
|
+
public static normalizeUrl(url: string): string {
|
|
208
|
+
// Handle protocol separately to preserve ://
|
|
209
|
+
const protocolMatch = url.match(/^([a-z][a-z0-9+.-]*:\/\/)(.*)$/i)
|
|
210
|
+
|
|
211
|
+
if (protocolMatch) {
|
|
212
|
+
const [, protocol, rest] = protocolMatch
|
|
213
|
+
// Remove consecutive slashes from the rest
|
|
214
|
+
const normalized = rest.replace(/\/+/g, '/')
|
|
215
|
+
return `${protocol}${normalized}`
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// No protocol, just remove consecutive slashes
|
|
219
|
+
return url.replace(/\/+/g, '/')
|
|
220
|
+
}
|
|
70
221
|
}
|
package/src/sort-by.ts
CHANGED
|
@@ -4,7 +4,10 @@ declare global {
|
|
|
4
4
|
*/
|
|
5
5
|
export interface Array<T> {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Sorts the array by a specified field and direction
|
|
8
|
+
* @param field The field to sort by
|
|
9
|
+
* @param direction The sort direction, either 'asc' or 'desc' (default: 'asc')
|
|
10
|
+
* @returns A new sorted array
|
|
8
11
|
*/
|
|
9
12
|
sortBy: (field: keyof T, direction?: 'asc' | 'desc') => T[]
|
|
10
13
|
}
|
package/src/using-async.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { isAsyncDisposable } from './is-async-disposable.js'
|
|
|
2
2
|
import { isDisposable } from './is-disposable.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Method that accepts
|
|
5
|
+
* Method that accepts a Disposable or AsyncDisposable resource that will be disposed after the callback
|
|
6
6
|
* @param resource The resource that is used in the callback and will be disposed afterwards
|
|
7
|
-
* @param callback The callback that will be executed
|
|
7
|
+
* @param callback The callback that will be executed asynchronously before the resource will be disposed
|
|
8
8
|
* @returns A promise that will be resolved with a return value after the resource is disposed
|
|
9
9
|
*/
|
|
10
10
|
export const usingAsync = async <T extends Disposable | AsyncDisposable, TReturns>(
|
package/src/using.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Method that accepts
|
|
2
|
+
* Method that accepts a Disposable resource that will be disposed after the callback
|
|
3
3
|
* @param resource The resource that is used in the callback and will be disposed afterwards
|
|
4
|
-
* @param callback The callback that will be executed
|
|
4
|
+
* @param callback The callback that will be executed synchronously before the resource will be disposed
|
|
5
5
|
* @returns the value that will be returned by the callback method
|
|
6
6
|
*/
|
|
7
7
|
export const using = <T extends Disposable, TReturns>(resource: T, callback: (r: T) => TReturns) => {
|
package/src/value-observer.ts
CHANGED
|
@@ -35,7 +35,7 @@ export class ValueObserver<T> implements Disposable {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* Creates a ValueObserver instance
|
|
39
39
|
* @param observable The related Observable object
|
|
40
40
|
* @param callback The callback that will be fired on change
|
|
41
41
|
* @param options Additional options
|