@guanghechen/path 1.0.0-alpha.10

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/CHANGELOG.md ADDED
@@ -0,0 +1,102 @@
1
+ # Change Log
2
+
3
+ All notable changes to this project will be documented in this file.
4
+ See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
+
6
+ # [1.0.0-alpha.10](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.9...@guanghechen/path@1.0.0-alpha.10) (2023-11-18)
7
+
8
+
9
+ ### Performance Improvements
10
+
11
+ * 🔧 upgrade engine version requirement from '>= 16.0.0' to '>= 18.0.0' ([ddb9521](https://github.com/guanghechen/sora/commit/ddb9521b529b2ca838554794339b9e27ac80b8aa))
12
+
13
+
14
+
15
+
16
+
17
+ # [1.0.0-alpha.9](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.8...@guanghechen/path@1.0.0-alpha.9) (2023-11-07)
18
+
19
+
20
+ ### Performance Improvements
21
+
22
+ * 🔧 make tsconfig.json tidy ([809f8cf](https://github.com/guanghechen/sora/commit/809f8cf6b18da2d8fbba1566a5f4a783b52683da))
23
+
24
+
25
+
26
+
27
+
28
+ # [1.0.0-alpha.8](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.7...@guanghechen/path@1.0.0-alpha.8) (2023-10-25)
29
+
30
+
31
+ ### Performance Improvements
32
+
33
+ * ⬆️ ugprade dependencies ([e8e7a92](https://github.com/guanghechen/sora/commit/e8e7a92f58fbeee3afbb04e1ef023a894249c0bc))
34
+
35
+
36
+
37
+
38
+
39
+ # [1.0.0-alpha.7](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.6...@guanghechen/path@1.0.0-alpha.7) (2023-10-16)
40
+
41
+
42
+ ### Performance Improvements
43
+
44
+ * 🎨 support 'preferSlash' option for 'relativexx' funcs ([e59d415](https://github.com/guanghechen/sora/commit/e59d415df8272f6a5b8afed1f57152e4b44c89b8))
45
+
46
+
47
+
48
+
49
+
50
+ # [1.0.0-alpha.6](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.5...@guanghechen/path@1.0.0-alpha.6) (2023-10-16)
51
+
52
+
53
+ ### Performance Improvements
54
+
55
+ * :art: refactor @guanghechen/path ([8952da3](https://github.com/guanghechen/sora/commit/8952da3154a042a10e76b356da7461a1f8ad8582))
56
+
57
+
58
+
59
+
60
+
61
+ # [1.0.0-alpha.5](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.4...@guanghechen/path@1.0.0-alpha.5) (2023-10-16)
62
+
63
+
64
+ ### Performance Improvements
65
+
66
+ * :art: refactor @guanghechen/path and @guanghechen/filepath ([5952ac3](https://github.com/guanghechen/sora/commit/5952ac39fee92e807e3cccc8e4b4dfa1aba1fa34))
67
+ * 🔧 remove unnecessary devDependencies ([944f3ae](https://github.com/guanghechen/sora/commit/944f3aee64e68ce52ca30237c7d0240a82c9c58f))
68
+
69
+
70
+
71
+
72
+
73
+ # [1.0.0-alpha.4](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.3...@guanghechen/path@1.0.0-alpha.4) (2023-10-10)
74
+
75
+ **Note:** Version bump only for package @guanghechen/path
76
+
77
+
78
+
79
+
80
+
81
+ # [1.0.0-alpha.3](https://github.com/guanghechen/sora/compare/@guanghechen/path@1.0.0-alpha.2...@guanghechen/path@1.0.0-alpha.3) (2023-10-09)
82
+
83
+
84
+ ### Performance Improvements
85
+
86
+ * re-expose @guanghechen/path.types ([92f5299](https://github.com/guanghechen/sora/commit/92f5299a62093f5e4167dda1b57adda1a45a3c8d))
87
+
88
+
89
+
90
+
91
+
92
+ # 1.0.0-alpha.2 (2023-10-09)
93
+
94
+
95
+ ### Features
96
+
97
+ * ✨ add @guanghechen/path ([cf68a08](https://github.com/guanghechen/sora/commit/cf68a08d661896d642254c58a5377b0556452cde))
98
+
99
+
100
+ ### Performance Improvements
101
+
102
+ * ✅ update tests ([ad6cd01](https://github.com/guanghechen/sora/commit/ad6cd01188a9b3739dbe390053de9de3ea32770a))
@@ -0,0 +1,270 @@
1
+ 'use strict';
2
+
3
+ var path = require('node:path');
4
+ var node_fs = require('node:fs');
5
+ var node_url = require('node:url');
6
+ var path_types = require('@guanghechen/path.types');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var path__default = /*#__PURE__*/_interopDefault(path);
11
+
12
+ const clazz$1 = 'PathResolver';
13
+ class PathResolver {
14
+ basename(filepath) {
15
+ this.ensureAbsolute(filepath);
16
+ const p = this.normalize(filepath);
17
+ return path__default.default.basename(p);
18
+ }
19
+ ensureAbsolute(filepath, message) {
20
+ if (this.isAbsolute(filepath))
21
+ return;
22
+ throw new Error(message ?? `[${clazz$1}] not an absolute path: ${filepath}.`);
23
+ }
24
+ ensureSafeRelative(root, filepath, message) {
25
+ if (this.isSafeRelative(root, filepath))
26
+ return;
27
+ throw new Error(message ?? `[${clazz$1}] not under the root path: filepath ${filepath}, root: ${root}.`);
28
+ }
29
+ dirname(filepath) {
30
+ this.ensureAbsolute(filepath);
31
+ const p = path__default.default.dirname(filepath);
32
+ return this.normalize(p);
33
+ }
34
+ isAbsolute(filepath) {
35
+ return path__default.default.isAbsolute(filepath);
36
+ }
37
+ isSafeRelative(root, filepath) {
38
+ if (!this.isAbsolute(root))
39
+ return false;
40
+ const relativePath = this._internalSafeRelative(root, filepath);
41
+ return !relativePath.startsWith('..');
42
+ }
43
+ join(filepath, ...pathPieces) {
44
+ this.ensureAbsolute(filepath, `[${clazz$1}.join] not an absolute path: ${filepath}.`);
45
+ for (const pathPiece of pathPieces) {
46
+ if (this.isAbsolute(pathPiece)) {
47
+ throw new Error(`[${clazz$1}.join] pathPiece shouldn't be absolute path. ${pathPiece}`);
48
+ }
49
+ }
50
+ const p = path__default.default.join(filepath, ...pathPieces);
51
+ return this.normalize(p);
52
+ }
53
+ normalize(filepath) {
54
+ this.ensureAbsolute(filepath);
55
+ return this._internalNormalize(filepath);
56
+ }
57
+ relative(from, to, preferSlash = false) {
58
+ this.ensureAbsolute(from, `[${clazz$1}.relative] from is not an absolute path: ${from}`);
59
+ this.ensureAbsolute(to, `[${clazz$1}.relative] to is not an absolute path: ${to}`);
60
+ const relativePath = this._internalRelative(from, to);
61
+ return preferSlash ? relativePath.replaceAll('\\', '/') : relativePath;
62
+ }
63
+ safeRelative(root, filepath, preferSlash = false) {
64
+ this.ensureSafeRelative(root, filepath);
65
+ const relativePath = this._internalSafeRelative(root, filepath);
66
+ return preferSlash ? relativePath.replaceAll('\\', '/') : relativePath;
67
+ }
68
+ safeResolve(root, filepath) {
69
+ this.ensureSafeRelative(root, filepath);
70
+ return this._internalSafeResolve(root, filepath);
71
+ }
72
+ _internalNormalize(filepath) {
73
+ const p = path__default.default
74
+ .normalize(filepath)
75
+ .replace(/[/\\]+/g, path__default.default.sep)
76
+ .replace(/[/\\]+$/, '');
77
+ return p.length <= 0 ? '/' : p;
78
+ }
79
+ _internalRelative(from_, to_) {
80
+ const from = this.normalize(from_);
81
+ const to = this.normalize(to_);
82
+ const relativePath = path__default.default.relative(from, to);
83
+ return relativePath;
84
+ }
85
+ _internalSafeRelative(root_, filepath_) {
86
+ const root = this._internalNormalize(root_);
87
+ const filepath = this._internalSafeResolve(root, filepath_);
88
+ const relativePath = this._internalRelative(root, filepath);
89
+ return relativePath;
90
+ }
91
+ _internalSafeResolve(root, filepath_) {
92
+ const filepath = this.isAbsolute(filepath_) ? filepath_ : path__default.default.join(root, filepath_);
93
+ return this._internalNormalize(filepath);
94
+ }
95
+ }
96
+
97
+ const clazz = 'UrlPathResolver';
98
+ class UrlPathResolver {
99
+ basename(filepath) {
100
+ this.ensureAbsolute(filepath);
101
+ const p = this.normalize(filepath);
102
+ const i = p.lastIndexOf('/');
103
+ return p.slice(i + 1);
104
+ }
105
+ ensureAbsolute(filepath, message) {
106
+ if (this.isAbsolute(filepath))
107
+ return;
108
+ throw new Error(message ?? `[${clazz}] not an absolute path: ${filepath}.`);
109
+ }
110
+ ensureSafeRelative(root, filepath, message) {
111
+ if (this.isSafeRelative(root, filepath))
112
+ return;
113
+ throw new Error(message ?? `[${clazz}] not under the root path: filepath ${filepath}, root: ${root}.`);
114
+ }
115
+ dirname(filepath) {
116
+ this.ensureAbsolute(filepath);
117
+ const p = this.normalize(filepath);
118
+ const i = p.lastIndexOf('/');
119
+ return i <= 0 ? '/' : p.slice(0, i);
120
+ }
121
+ isAbsolute(filepath) {
122
+ return filepath.startsWith('/') || filepath.startsWith('\\');
123
+ }
124
+ isSafeRelative(root, filepath) {
125
+ if (!this.isAbsolute(root))
126
+ return false;
127
+ const relativePath = this._internalSafeRelative(root, filepath);
128
+ return !relativePath.startsWith('..');
129
+ }
130
+ join(filepath, ...pathPieces) {
131
+ this.ensureAbsolute(filepath, `[${clazz}.join] not an absolute path: ${filepath}.`);
132
+ for (const pathPiece of pathPieces) {
133
+ if (this.isAbsolute(pathPiece)) {
134
+ throw new Error(`[${clazz}.join] pathPiece shouldn't be absolute path. ${pathPiece}`);
135
+ }
136
+ }
137
+ return this._internalJoin(filepath, pathPieces.join('/'));
138
+ }
139
+ normalize(filepath) {
140
+ this.ensureAbsolute(filepath);
141
+ return this._internalNormalize(filepath);
142
+ }
143
+ relative(from, to) {
144
+ this.ensureAbsolute(from, `[${clazz}.relative] from is not an absolute path: ${from}`);
145
+ this.ensureAbsolute(to, `[${clazz}.relative] to is not an absolute path: ${to}`);
146
+ return this._internalRelative(from, to);
147
+ }
148
+ safeRelative(root, filepath) {
149
+ this.ensureSafeRelative(root, filepath);
150
+ return this._internalSafeRelative(root, filepath);
151
+ }
152
+ safeResolve(root, filepath) {
153
+ this.ensureSafeRelative(root, filepath);
154
+ return this._internalSafeResolve(root, filepath);
155
+ }
156
+ _internalJoin(root, relativePath) {
157
+ const filepath = root + '/' + relativePath;
158
+ return this._internalNormalize(filepath);
159
+ }
160
+ _internalNormalize(filepath) {
161
+ const pieces = [];
162
+ for (const piece of filepath.split(/[/\\]+/g)) {
163
+ if (!piece)
164
+ continue;
165
+ if (piece === '.')
166
+ continue;
167
+ if (piece === '..') {
168
+ pieces.pop();
169
+ continue;
170
+ }
171
+ pieces.push(piece);
172
+ }
173
+ return '/' + pieces.join('/');
174
+ }
175
+ _internalRelative(from_, to_) {
176
+ const from = this.normalize(from_);
177
+ const to = this.normalize(to_);
178
+ const fromPieces = from.split('/');
179
+ const toPieces = to.split('/');
180
+ let ci = 0;
181
+ const L = fromPieces.length < toPieces.length ? fromPieces.length : toPieces.length;
182
+ for (; ci < L; ++ci) {
183
+ if (fromPieces[ci] !== toPieces[ci])
184
+ break;
185
+ }
186
+ return '../'.repeat(fromPieces.length - ci) + toPieces.slice(ci).join('/');
187
+ }
188
+ _internalSafeRelative(root_, filepath_) {
189
+ const root = this._internalNormalize(root_);
190
+ const filepath = this._internalSafeResolve(root, filepath_);
191
+ const relativePath = this._internalRelative(root, filepath);
192
+ return relativePath;
193
+ }
194
+ _internalSafeResolve(root, filepath_) {
195
+ const filepath = this.isAbsolute(filepath_) ? filepath_ : this.join(root, filepath_);
196
+ return filepath;
197
+ }
198
+ }
199
+
200
+ function locateNearestFilepath(currentDir, filenames) {
201
+ return internalRecursiveLocate(currentDir.startsWith('file://') ? node_url.fileURLToPath(currentDir) : currentDir, [filenames].flat());
202
+ }
203
+ function findNearestFilepath(currentDir, predicate) {
204
+ return internalFindNearestFilepath(currentDir.startsWith('file://') ? node_url.fileURLToPath(currentDir) : currentDir, predicate);
205
+ }
206
+ function internalRecursiveLocate(currentDir, filenames) {
207
+ for (const filename of filenames) {
208
+ const filepath = path.join(currentDir, filename);
209
+ if (node_fs.existsSync(filepath))
210
+ return filepath;
211
+ }
212
+ const parentDir = path.dirname(currentDir);
213
+ if (parentDir === currentDir || !path.isAbsolute(parentDir))
214
+ return null;
215
+ return locateNearestFilepath(parentDir, filenames);
216
+ }
217
+ function internalFindNearestFilepath(currentDir, predicate) {
218
+ const filenames = node_fs.readdirSync(currentDir);
219
+ for (const filename of filenames) {
220
+ const filepath = path.join(currentDir, filename);
221
+ if (predicate(filepath))
222
+ return filepath;
223
+ }
224
+ const parentDir = path.dirname(currentDir);
225
+ if (parentDir === currentDir)
226
+ return null;
227
+ return internalFindNearestFilepath(parentDir, predicate);
228
+ }
229
+
230
+ class WorkspacePathResolver {
231
+ root;
232
+ pathResolver;
233
+ constructor(root, pathResolver) {
234
+ this.root = root;
235
+ this.pathResolver = pathResolver;
236
+ }
237
+ ensureSafePath(filepath, message) {
238
+ const { root, pathResolver } = this;
239
+ pathResolver.ensureSafeRelative(root, filepath, message);
240
+ }
241
+ isSafePath(filepath) {
242
+ const { root, pathResolver } = this;
243
+ return pathResolver.isSafeRelative(root, filepath);
244
+ }
245
+ relative(filepath, preferSlash) {
246
+ const { root, pathResolver } = this;
247
+ return pathResolver.safeRelative(root, filepath, preferSlash);
248
+ }
249
+ resolve(filepath) {
250
+ const { root, pathResolver } = this;
251
+ return pathResolver.safeResolve(root, filepath);
252
+ }
253
+ }
254
+
255
+ const pathResolver = new PathResolver();
256
+ const urlPathResolver = new UrlPathResolver();
257
+
258
+ exports.PathResolver = PathResolver;
259
+ exports.UrlPathResolver = UrlPathResolver;
260
+ exports.WorkspacePathResolver = WorkspacePathResolver;
261
+ exports.findNearestFilepath = findNearestFilepath;
262
+ exports.locateNearestFilepath = locateNearestFilepath;
263
+ exports.pathResolver = pathResolver;
264
+ exports.urlPathResolver = urlPathResolver;
265
+ Object.keys(path_types).forEach(function (k) {
266
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
267
+ enumerable: true,
268
+ get: function () { return path_types[k]; }
269
+ });
270
+ });
@@ -0,0 +1,252 @@
1
+ import path, { join, dirname, isAbsolute } from 'node:path';
2
+ import { existsSync, readdirSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ export * from '@guanghechen/path.types';
5
+
6
+ const clazz$1 = 'PathResolver';
7
+ class PathResolver {
8
+ basename(filepath) {
9
+ this.ensureAbsolute(filepath);
10
+ const p = this.normalize(filepath);
11
+ return path.basename(p);
12
+ }
13
+ ensureAbsolute(filepath, message) {
14
+ if (this.isAbsolute(filepath))
15
+ return;
16
+ throw new Error(message ?? `[${clazz$1}] not an absolute path: ${filepath}.`);
17
+ }
18
+ ensureSafeRelative(root, filepath, message) {
19
+ if (this.isSafeRelative(root, filepath))
20
+ return;
21
+ throw new Error(message ?? `[${clazz$1}] not under the root path: filepath ${filepath}, root: ${root}.`);
22
+ }
23
+ dirname(filepath) {
24
+ this.ensureAbsolute(filepath);
25
+ const p = path.dirname(filepath);
26
+ return this.normalize(p);
27
+ }
28
+ isAbsolute(filepath) {
29
+ return path.isAbsolute(filepath);
30
+ }
31
+ isSafeRelative(root, filepath) {
32
+ if (!this.isAbsolute(root))
33
+ return false;
34
+ const relativePath = this._internalSafeRelative(root, filepath);
35
+ return !relativePath.startsWith('..');
36
+ }
37
+ join(filepath, ...pathPieces) {
38
+ this.ensureAbsolute(filepath, `[${clazz$1}.join] not an absolute path: ${filepath}.`);
39
+ for (const pathPiece of pathPieces) {
40
+ if (this.isAbsolute(pathPiece)) {
41
+ throw new Error(`[${clazz$1}.join] pathPiece shouldn't be absolute path. ${pathPiece}`);
42
+ }
43
+ }
44
+ const p = path.join(filepath, ...pathPieces);
45
+ return this.normalize(p);
46
+ }
47
+ normalize(filepath) {
48
+ this.ensureAbsolute(filepath);
49
+ return this._internalNormalize(filepath);
50
+ }
51
+ relative(from, to, preferSlash = false) {
52
+ this.ensureAbsolute(from, `[${clazz$1}.relative] from is not an absolute path: ${from}`);
53
+ this.ensureAbsolute(to, `[${clazz$1}.relative] to is not an absolute path: ${to}`);
54
+ const relativePath = this._internalRelative(from, to);
55
+ return preferSlash ? relativePath.replaceAll('\\', '/') : relativePath;
56
+ }
57
+ safeRelative(root, filepath, preferSlash = false) {
58
+ this.ensureSafeRelative(root, filepath);
59
+ const relativePath = this._internalSafeRelative(root, filepath);
60
+ return preferSlash ? relativePath.replaceAll('\\', '/') : relativePath;
61
+ }
62
+ safeResolve(root, filepath) {
63
+ this.ensureSafeRelative(root, filepath);
64
+ return this._internalSafeResolve(root, filepath);
65
+ }
66
+ _internalNormalize(filepath) {
67
+ const p = path
68
+ .normalize(filepath)
69
+ .replace(/[/\\]+/g, path.sep)
70
+ .replace(/[/\\]+$/, '');
71
+ return p.length <= 0 ? '/' : p;
72
+ }
73
+ _internalRelative(from_, to_) {
74
+ const from = this.normalize(from_);
75
+ const to = this.normalize(to_);
76
+ const relativePath = path.relative(from, to);
77
+ return relativePath;
78
+ }
79
+ _internalSafeRelative(root_, filepath_) {
80
+ const root = this._internalNormalize(root_);
81
+ const filepath = this._internalSafeResolve(root, filepath_);
82
+ const relativePath = this._internalRelative(root, filepath);
83
+ return relativePath;
84
+ }
85
+ _internalSafeResolve(root, filepath_) {
86
+ const filepath = this.isAbsolute(filepath_) ? filepath_ : path.join(root, filepath_);
87
+ return this._internalNormalize(filepath);
88
+ }
89
+ }
90
+
91
+ const clazz = 'UrlPathResolver';
92
+ class UrlPathResolver {
93
+ basename(filepath) {
94
+ this.ensureAbsolute(filepath);
95
+ const p = this.normalize(filepath);
96
+ const i = p.lastIndexOf('/');
97
+ return p.slice(i + 1);
98
+ }
99
+ ensureAbsolute(filepath, message) {
100
+ if (this.isAbsolute(filepath))
101
+ return;
102
+ throw new Error(message ?? `[${clazz}] not an absolute path: ${filepath}.`);
103
+ }
104
+ ensureSafeRelative(root, filepath, message) {
105
+ if (this.isSafeRelative(root, filepath))
106
+ return;
107
+ throw new Error(message ?? `[${clazz}] not under the root path: filepath ${filepath}, root: ${root}.`);
108
+ }
109
+ dirname(filepath) {
110
+ this.ensureAbsolute(filepath);
111
+ const p = this.normalize(filepath);
112
+ const i = p.lastIndexOf('/');
113
+ return i <= 0 ? '/' : p.slice(0, i);
114
+ }
115
+ isAbsolute(filepath) {
116
+ return filepath.startsWith('/') || filepath.startsWith('\\');
117
+ }
118
+ isSafeRelative(root, filepath) {
119
+ if (!this.isAbsolute(root))
120
+ return false;
121
+ const relativePath = this._internalSafeRelative(root, filepath);
122
+ return !relativePath.startsWith('..');
123
+ }
124
+ join(filepath, ...pathPieces) {
125
+ this.ensureAbsolute(filepath, `[${clazz}.join] not an absolute path: ${filepath}.`);
126
+ for (const pathPiece of pathPieces) {
127
+ if (this.isAbsolute(pathPiece)) {
128
+ throw new Error(`[${clazz}.join] pathPiece shouldn't be absolute path. ${pathPiece}`);
129
+ }
130
+ }
131
+ return this._internalJoin(filepath, pathPieces.join('/'));
132
+ }
133
+ normalize(filepath) {
134
+ this.ensureAbsolute(filepath);
135
+ return this._internalNormalize(filepath);
136
+ }
137
+ relative(from, to) {
138
+ this.ensureAbsolute(from, `[${clazz}.relative] from is not an absolute path: ${from}`);
139
+ this.ensureAbsolute(to, `[${clazz}.relative] to is not an absolute path: ${to}`);
140
+ return this._internalRelative(from, to);
141
+ }
142
+ safeRelative(root, filepath) {
143
+ this.ensureSafeRelative(root, filepath);
144
+ return this._internalSafeRelative(root, filepath);
145
+ }
146
+ safeResolve(root, filepath) {
147
+ this.ensureSafeRelative(root, filepath);
148
+ return this._internalSafeResolve(root, filepath);
149
+ }
150
+ _internalJoin(root, relativePath) {
151
+ const filepath = root + '/' + relativePath;
152
+ return this._internalNormalize(filepath);
153
+ }
154
+ _internalNormalize(filepath) {
155
+ const pieces = [];
156
+ for (const piece of filepath.split(/[/\\]+/g)) {
157
+ if (!piece)
158
+ continue;
159
+ if (piece === '.')
160
+ continue;
161
+ if (piece === '..') {
162
+ pieces.pop();
163
+ continue;
164
+ }
165
+ pieces.push(piece);
166
+ }
167
+ return '/' + pieces.join('/');
168
+ }
169
+ _internalRelative(from_, to_) {
170
+ const from = this.normalize(from_);
171
+ const to = this.normalize(to_);
172
+ const fromPieces = from.split('/');
173
+ const toPieces = to.split('/');
174
+ let ci = 0;
175
+ const L = fromPieces.length < toPieces.length ? fromPieces.length : toPieces.length;
176
+ for (; ci < L; ++ci) {
177
+ if (fromPieces[ci] !== toPieces[ci])
178
+ break;
179
+ }
180
+ return '../'.repeat(fromPieces.length - ci) + toPieces.slice(ci).join('/');
181
+ }
182
+ _internalSafeRelative(root_, filepath_) {
183
+ const root = this._internalNormalize(root_);
184
+ const filepath = this._internalSafeResolve(root, filepath_);
185
+ const relativePath = this._internalRelative(root, filepath);
186
+ return relativePath;
187
+ }
188
+ _internalSafeResolve(root, filepath_) {
189
+ const filepath = this.isAbsolute(filepath_) ? filepath_ : this.join(root, filepath_);
190
+ return filepath;
191
+ }
192
+ }
193
+
194
+ function locateNearestFilepath(currentDir, filenames) {
195
+ return internalRecursiveLocate(currentDir.startsWith('file://') ? fileURLToPath(currentDir) : currentDir, [filenames].flat());
196
+ }
197
+ function findNearestFilepath(currentDir, predicate) {
198
+ return internalFindNearestFilepath(currentDir.startsWith('file://') ? fileURLToPath(currentDir) : currentDir, predicate);
199
+ }
200
+ function internalRecursiveLocate(currentDir, filenames) {
201
+ for (const filename of filenames) {
202
+ const filepath = join(currentDir, filename);
203
+ if (existsSync(filepath))
204
+ return filepath;
205
+ }
206
+ const parentDir = dirname(currentDir);
207
+ if (parentDir === currentDir || !isAbsolute(parentDir))
208
+ return null;
209
+ return locateNearestFilepath(parentDir, filenames);
210
+ }
211
+ function internalFindNearestFilepath(currentDir, predicate) {
212
+ const filenames = readdirSync(currentDir);
213
+ for (const filename of filenames) {
214
+ const filepath = join(currentDir, filename);
215
+ if (predicate(filepath))
216
+ return filepath;
217
+ }
218
+ const parentDir = dirname(currentDir);
219
+ if (parentDir === currentDir)
220
+ return null;
221
+ return internalFindNearestFilepath(parentDir, predicate);
222
+ }
223
+
224
+ class WorkspacePathResolver {
225
+ root;
226
+ pathResolver;
227
+ constructor(root, pathResolver) {
228
+ this.root = root;
229
+ this.pathResolver = pathResolver;
230
+ }
231
+ ensureSafePath(filepath, message) {
232
+ const { root, pathResolver } = this;
233
+ pathResolver.ensureSafeRelative(root, filepath, message);
234
+ }
235
+ isSafePath(filepath) {
236
+ const { root, pathResolver } = this;
237
+ return pathResolver.isSafeRelative(root, filepath);
238
+ }
239
+ relative(filepath, preferSlash) {
240
+ const { root, pathResolver } = this;
241
+ return pathResolver.safeRelative(root, filepath, preferSlash);
242
+ }
243
+ resolve(filepath) {
244
+ const { root, pathResolver } = this;
245
+ return pathResolver.safeResolve(root, filepath);
246
+ }
247
+ }
248
+
249
+ const pathResolver = new PathResolver();
250
+ const urlPathResolver = new UrlPathResolver();
251
+
252
+ export { PathResolver, UrlPathResolver, WorkspacePathResolver, findNearestFilepath, locateNearestFilepath, pathResolver, urlPathResolver };
@@ -0,0 +1,71 @@
1
+ import { IPathResolver, IWorkspacePathResolver } from '@guanghechen/path.types';
2
+ export * from '@guanghechen/path.types';
3
+
4
+ /**
5
+ * Locate a nearest filepath from the given `currentDir` which name included in the give `filenames`.
6
+ *
7
+ * @param currentDir
8
+ * @param filenames
9
+ * @returns
10
+ */
11
+ declare function locateNearestFilepath(currentDir: string, filenames: string | ReadonlyArray<string>): string | null;
12
+ /**
13
+ * Find a nearest filepath from the give `currentDir`which matched the give tester `testFilepath`.
14
+ *
15
+ * @param currentDir
16
+ * @param predicate
17
+ * @returns
18
+ */
19
+ declare function findNearestFilepath(currentDir: string, predicate: (filepath: string) => boolean): string | null;
20
+
21
+ declare class PathResolver implements IPathResolver {
22
+ basename(filepath: string): string;
23
+ ensureAbsolute(filepath: string, message?: string | undefined): void | never;
24
+ ensureSafeRelative(root: string, filepath: string, message?: string | undefined): void | never;
25
+ dirname(filepath: string): string | never;
26
+ isAbsolute(filepath: string): boolean;
27
+ isSafeRelative(root: string, filepath: string): boolean;
28
+ join(filepath: string, ...pathPieces: string[]): string | never;
29
+ normalize(filepath: string): string | never;
30
+ relative(from: string, to: string, preferSlash?: boolean): string | never;
31
+ safeRelative(root: string, filepath: string, preferSlash?: boolean): string;
32
+ safeResolve(root: string, filepath: string): string;
33
+ protected _internalNormalize(filepath: string): string;
34
+ protected _internalRelative(from_: string, to_: string): string;
35
+ protected _internalSafeRelative(root_: string, filepath_: string): string;
36
+ protected _internalSafeResolve(root: string, filepath_: string): string;
37
+ }
38
+
39
+ declare class UrlPathResolver implements IPathResolver {
40
+ basename(filepath: string): string;
41
+ ensureAbsolute(filepath: string, message?: string | undefined): void | never;
42
+ ensureSafeRelative(root: string, filepath: string, message?: string | undefined): void;
43
+ dirname(filepath: string): string | never;
44
+ isAbsolute(filepath: string): boolean;
45
+ isSafeRelative(root: string, filepath: string): boolean;
46
+ join(filepath: string, ...pathPieces: string[]): string | never;
47
+ normalize(filepath: string): string | never;
48
+ relative(from: string, to: string): string | never;
49
+ safeRelative(root: string, filepath: string): string;
50
+ safeResolve(root: string, filepath: string): string;
51
+ protected _internalJoin(root: string, relativePath: string): string;
52
+ protected _internalNormalize(filepath: string): string;
53
+ protected _internalRelative(from_: string, to_: string): string;
54
+ protected _internalSafeRelative(root_: string, filepath_: string): string;
55
+ protected _internalSafeResolve(root: string, filepath_: string): string;
56
+ }
57
+
58
+ declare class WorkspacePathResolver implements IWorkspacePathResolver {
59
+ readonly root: string;
60
+ readonly pathResolver: IPathResolver;
61
+ constructor(root: string, pathResolver: IPathResolver);
62
+ ensureSafePath(filepath: string, message?: string | undefined): void | never;
63
+ isSafePath(filepath: string): boolean;
64
+ relative(filepath: string, preferSlash?: boolean): string | never;
65
+ resolve(filepath: string): string | never;
66
+ }
67
+
68
+ declare const pathResolver: IPathResolver;
69
+ declare const urlPathResolver: IPathResolver;
70
+
71
+ export { PathResolver, UrlPathResolver, WorkspacePathResolver, findNearestFilepath, locateNearestFilepath, pathResolver, urlPathResolver };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@guanghechen/path",
3
+ "version": "1.0.0-alpha.10",
4
+ "description": "Path utils.",
5
+ "author": {
6
+ "name": "guanghechen",
7
+ "url": "https://github.com/guanghechen/"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/guanghechen/sora/tree/@guanghechen/path@1.0.0-alpha.9",
12
+ "directory": "packages/path"
13
+ },
14
+ "homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/path@1.0.0-alpha.9/packages/path#readme",
15
+ "type": "module",
16
+ "exports": {
17
+ ".": {
18
+ "source": "./src/index.ts",
19
+ "import": "./lib/esm/index.mjs",
20
+ "require": "./lib/cjs/index.cjs",
21
+ "types": "./lib/types/index.d.ts"
22
+ }
23
+ },
24
+ "source": "./src/index.ts",
25
+ "main": "./lib/cjs/index.cjs",
26
+ "module": "./lib/esm/index.mjs",
27
+ "types": "./lib/types/index.d.ts",
28
+ "license": "MIT",
29
+ "engines": {
30
+ "node": ">= 18.0.0"
31
+ },
32
+ "files": [
33
+ "lib/",
34
+ "!lib/**/*.map",
35
+ "package.json",
36
+ "CHANGELOG.md",
37
+ "LICENSE",
38
+ "README.md"
39
+ ],
40
+ "scripts": {
41
+ "build": "../../node_modules/.bin/rimraf lib/ && ../../node_modules/.bin/cross-env NODE_ENV=production ../../node_modules/.bin/rollup -c ../../rollup.config.mjs",
42
+ "prepublishOnly": "yarn build",
43
+ "test": "node --experimental-vm-modules ../../node_modules/.bin/jest --config ../../jest.config.mjs --rootDir ."
44
+ },
45
+ "dependencies": {
46
+ "@guanghechen/path.types": "^1.0.0-alpha.7"
47
+ },
48
+ "gitHead": "5c53d6c6b20a5bc1e97a19f97c6adfe88067a7f9"
49
+ }