@guanghechen/path 2.0.0 → 2.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-present guanghechen (https://github.com/guanghechen)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -49,7 +49,8 @@
49
49
  </header>
50
50
  <br/>
51
51
 
52
- Path utilities for file system operations and workspace path resolution.
52
+ Path utilities for file system operations with safe path resolution and workspace management.
53
+ Provides strict path validation to prevent directory traversal attacks.
53
54
 
54
55
  ## Install
55
56
 
@@ -67,5 +68,94 @@ Path utilities for file system operations and workspace path resolution.
67
68
 
68
69
  ## Usage
69
70
 
71
+ ### PathResolver
72
+
73
+ Standard path resolver with safety checks:
74
+
75
+ ```typescript
76
+ import { PathResolver, pathResolver } from '@guanghechen/path'
77
+
78
+ // Use the default singleton
79
+ pathResolver.normalize('/foo/bar/../baz') // '/foo/baz'
80
+ pathResolver.basename('/foo/bar/file.txt') // 'file.txt'
81
+ pathResolver.dirname('/foo/bar/file.txt') // '/foo/bar'
82
+ pathResolver.join('/foo', 'bar', 'baz') // '/foo/bar/baz'
83
+ pathResolver.relative('/foo/bar', '/foo/baz') // '../baz'
84
+
85
+ // Check if path is within a root directory (safe from traversal)
86
+ pathResolver.isSafeRelative('/workspace', '/workspace/src/file.ts') // true
87
+ pathResolver.isSafeRelative('/workspace', '/etc/passwd') // false
88
+
89
+ // Safe relative path (throws if unsafe)
90
+ pathResolver.safeRelative('/workspace', '/workspace/src/file.ts') // 'src/file.ts'
91
+
92
+ // Safe resolve (resolve relative path within root)
93
+ pathResolver.safeResolve('/workspace', './src/file.ts') // '/workspace/src/file.ts'
94
+ pathResolver.safeResolve('/workspace', '../outside') // throws Error
95
+
96
+ // Create custom resolver with slash preference
97
+ const resolver = new PathResolver({ preferSlash: true })
98
+ resolver.relative('/foo/bar', '/foo/baz') // '../baz' (uses forward slashes on Windows)
99
+ ```
100
+
101
+ ### WorkspacePathResolver
102
+
103
+ Workspace-scoped path operations:
104
+
105
+ ```typescript
106
+ import { WorkspacePathResolver, pathResolver } from '@guanghechen/path'
107
+
108
+ const workspace = new WorkspacePathResolver('/project/workspace', pathResolver)
109
+
110
+ // Check if path is within workspace
111
+ workspace.isSafePath('/project/workspace/src/index.ts') // true
112
+ workspace.isSafePath('/etc/passwd') // false
113
+
114
+ // Resolve relative paths within workspace
115
+ workspace.resolve('./src/index.ts') // '/project/workspace/src/index.ts'
116
+ workspace.resolve('package.json') // '/project/workspace/package.json'
117
+
118
+ // Get relative path from workspace root
119
+ workspace.relative('/project/workspace/src/index.ts') // 'src/index.ts'
120
+ ```
121
+
122
+ ### UrlPathResolver
123
+
124
+ URL-style path resolution (forward slashes):
125
+
126
+ ```typescript
127
+ import { UrlPathResolver, urlPathResolver } from '@guanghechen/path'
128
+
129
+ urlPathResolver.normalize('/foo/bar/../baz') // '/foo/baz'
130
+ urlPathResolver.join('/api', 'users', '123') // '/api/users/123'
131
+ ```
132
+
133
+ ### Locate Utilities
134
+
135
+ Find files by traversing up the directory tree:
136
+
137
+ ```typescript
138
+ import { locateNearestFilepath, findNearestFilepath } from '@guanghechen/path'
139
+
140
+ // Find nearest file by name(s)
141
+ const packageJson = locateNearestFilepath('/project/src/utils', 'package.json')
142
+ // Returns: '/project/package.json' (if exists)
143
+
144
+ // Find nearest file matching multiple names
145
+ const config = locateNearestFilepath('/project/src', [
146
+ 'tsconfig.json',
147
+ 'jsconfig.json',
148
+ ])
149
+
150
+ // Find nearest file with custom predicate
151
+ const readme = findNearestFilepath('/project/src', (filepath) => {
152
+ return filepath.toLowerCase().endsWith('readme.md')
153
+ })
154
+ ```
155
+
156
+ ## Reference
157
+
158
+ - [homepage][homepage]
159
+
70
160
  [homepage]:
71
- https://github.com/guanghechen/sora/tree/@guanghechen/path@2.0.0/packages/path#readme
161
+ https://github.com/guanghechen/sora/tree/@guanghechen/path@2.0.0/packages/path#readme
package/lib/cjs/index.cjs CHANGED
@@ -3,11 +3,6 @@
3
3
  var path = require('node:path');
4
4
  var node_fs = require('node:fs');
5
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
6
 
12
7
  const clazz$1 = 'PathResolver';
13
8
  class PathResolver {
@@ -18,7 +13,7 @@ class PathResolver {
18
13
  basename(filepath) {
19
14
  this.ensureAbsolute(filepath);
20
15
  const p = this.normalize(filepath);
21
- return path__default.default.basename(p);
16
+ return path.basename(p);
22
17
  }
23
18
  ensureAbsolute(filepath, message) {
24
19
  if (this.isAbsolute(filepath))
@@ -32,11 +27,11 @@ class PathResolver {
32
27
  }
33
28
  dirname(filepath) {
34
29
  this.ensureAbsolute(filepath);
35
- const p = path__default.default.dirname(filepath);
30
+ const p = path.dirname(filepath);
36
31
  return this.normalize(p);
37
32
  }
38
33
  isAbsolute(filepath) {
39
- return path__default.default.isAbsolute(filepath);
34
+ return path.isAbsolute(filepath);
40
35
  }
41
36
  isSafeRelative(root, filepath) {
42
37
  if (!this.isAbsolute(root))
@@ -51,7 +46,7 @@ class PathResolver {
51
46
  throw new Error(`[${clazz$1}.join] pathPiece shouldn't be absolute path. ${pathPiece}`);
52
47
  }
53
48
  }
54
- const p = path__default.default.join(filepath, ...pathPieces);
49
+ const p = path.join(filepath, ...pathPieces);
55
50
  return this.normalize(p);
56
51
  }
57
52
  normalize(filepath) {
@@ -76,16 +71,16 @@ class PathResolver {
76
71
  return this._internalSafeResolve(root, filepath);
77
72
  }
78
73
  _internalNormalize(filepath) {
79
- const p = path__default.default
74
+ const p = path
80
75
  .normalize(filepath)
81
- .replace(/[/\\]+/g, path__default.default.sep)
76
+ .replace(/[/\\]+/g, path.sep)
82
77
  .replace(/[/\\]+$/, '');
83
78
  return p.length <= 0 ? '/' : p;
84
79
  }
85
80
  _internalRelative(from_, to_) {
86
81
  const from = this.normalize(from_);
87
82
  const to = this.normalize(to_);
88
- const relativePath = path__default.default.relative(from, to);
83
+ const relativePath = path.relative(from, to);
89
84
  return relativePath;
90
85
  }
91
86
  _internalSafeRelative(root_, filepath_) {
@@ -95,7 +90,7 @@ class PathResolver {
95
90
  return relativePath;
96
91
  }
97
92
  _internalSafeResolve(root, filepath_) {
98
- const filepath = this.isAbsolute(filepath_) ? filepath_ : path__default.default.join(root, filepath_);
93
+ const filepath = this.isAbsolute(filepath_) ? filepath_ : path.join(root, filepath_);
99
94
  return this._internalNormalize(filepath);
100
95
  }
101
96
  }
@@ -268,9 +263,3 @@ exports.findNearestFilepath = findNearestFilepath;
268
263
  exports.locateNearestFilepath = locateNearestFilepath;
269
264
  exports.pathResolver = pathResolver;
270
265
  exports.urlPathResolver = urlPathResolver;
271
- Object.keys(path_types).forEach(function (k) {
272
- if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
273
- enumerable: true,
274
- get: function () { return path_types[k]; }
275
- });
276
- });
package/lib/esm/index.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  import path, { join, dirname, isAbsolute } from 'node:path';
2
2
  import { readdirSync, existsSync } from 'node:fs';
3
3
  import { fileURLToPath } from 'node:url';
4
- export * from '@guanghechen/path.types';
5
4
 
6
5
  const clazz$1 = 'PathResolver';
7
6
  class PathResolver {
@@ -1,5 +1,4 @@
1
- import { IPathResolver, IPathResolverParams, IWorkspacePathResolver } from '@guanghechen/path.types';
2
- export * from '@guanghechen/path.types';
1
+ import { IPathResolver, IPathResolverParams, IWorkspacePathResolver } from '@guanghechen/types';
3
2
 
4
3
  /**
5
4
  * Locate a nearest filepath from the given `currentDir` which name included in the `filenames`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guanghechen/path",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Path utils.",
5
5
  "author": {
6
6
  "name": "guanghechen",
@@ -8,17 +8,17 @@
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "https://github.com/guanghechen/sora/tree/@guanghechen/path@1.0.3",
11
+ "url": "https://github.com/guanghechen/sora/tree/@guanghechen/path@2.0.0",
12
12
  "directory": "packages/path"
13
13
  },
14
- "homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/path@1.0.3/packages/path#readme",
14
+ "homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/path@2.0.0/packages/path#readme",
15
15
  "type": "module",
16
16
  "exports": {
17
17
  ".": {
18
+ "types": "./lib/types/index.d.ts",
18
19
  "source": "./src/index.ts",
19
20
  "import": "./lib/esm/index.mjs",
20
- "require": "./lib/cjs/index.cjs",
21
- "types": "./lib/types/index.d.ts"
21
+ "require": "./lib/cjs/index.cjs"
22
22
  }
23
23
  },
24
24
  "source": "./src/index.ts",
@@ -26,13 +26,6 @@
26
26
  "module": "./lib/esm/index.mjs",
27
27
  "types": "./lib/types/index.d.ts",
28
28
  "license": "MIT",
29
- "scripts": {
30
- "build": "rollup -c ../../rollup.config.mjs",
31
- "clean": "rimraf lib",
32
- "test": "vitest run --config ../../vitest.config.ts",
33
- "test:coverage": "vitest run --config ../../vitest.config.ts --coverage",
34
- "test:update": "vitest run --config ../../vitest.config.ts -u"
35
- },
36
29
  "files": [
37
30
  "lib/",
38
31
  "!lib/**/*.map",
@@ -42,7 +35,13 @@
42
35
  "README.md"
43
36
  ],
44
37
  "dependencies": {
45
- "@guanghechen/path.types": "^2.0.0"
38
+ "@guanghechen/types": "^2.0.1"
46
39
  },
47
- "gitHead": "12990a720b31d50d217e2e17a6191256dc94eda6"
48
- }
40
+ "scripts": {
41
+ "build": "rollup -c ../../rollup.config.mjs",
42
+ "clean": "rimraf lib",
43
+ "test": "vitest run --config ../../vitest.config.ts",
44
+ "test:coverage": "vitest run --config ../../vitest.config.ts --coverage",
45
+ "test:update": "vitest run --config ../../vitest.config.ts -u"
46
+ }
47
+ }