@reliverse/pathkit 1.1.10 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +510 -247
- package/bin/impl/getFileImportsExports.d.ts +2 -0
- package/bin/impl/getFileImportsExports.js +44 -5
- package/bin/mod.d.ts +2 -1
- package/bin/mod.js +18 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,247 +1,510 @@
|
|
|
1
|
-
# pathkit • cross‑platform path manipulation
|
|
2
|
-
|
|
3
|
-
> @reliverse/pathkit is a slash‑consistent, cross‑platform path manipulation, with POSIX forward slash, drop‑in for node:path and unjs/pathe. This library extends the node:path module with a set of functions for manipulating file paths.
|
|
4
|
-
|
|
5
|
-
[sponsor](https://github.com/sponsors/blefnk) • [discord](https://discord.gg/Pb8uKbwpsJ) • [npm](https://npmjs.com/package/@reliverse/pathkit) • [repo](https://github.com/reliverse/pathkit)
|
|
6
|
-
|
|
7
|
-
## Key Features
|
|
8
|
-
|
|
9
|
-
- 🔹 **drop in** and replace `node:path` and `unjs/pathe` instantly
|
|
10
|
-
- ➕ **`unjs/pathe` on steroids** – alias resolution, import parsing, and more
|
|
11
|
-
- 🌀 **always `/`** – posix separators 100% of the time (buh‑bye `\\`)
|
|
12
|
-
- ⚙️ **node.js api compatible** – familiar methods, no learning curve
|
|
13
|
-
- 🚀 **modern & fast** – typescript, pure esm, bun & node‑ready
|
|
14
|
-
- 🧠 **predictable & testable** – deterministic output across windows / macos / linux
|
|
15
|
-
- 🧼 **no dependencies** – just better path api + couple of cool utilities = [4kB](https://bundlephobia.com/package/@reliverse/pathkit@latest)
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
# bun • pnpm • yarn • npm
|
|
21
|
-
bun add @reliverse/pathkit
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
**Migrate**:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# soon:
|
|
28
|
-
# bun add -D @reliverse/dler
|
|
29
|
-
# bun dler migrate --lib path-to-pathkit
|
|
30
|
-
# bun dler migrate --lib pathe-to-pathkit
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### `unjs/pathe` vs `@reliverse/pathkit`
|
|
34
|
-
|
|
35
|
-
| Package | What you get | When to use |
|
|
36
|
-
|---------|--------------|-------------|
|
|
37
|
-
| **`pathe`** | Path API only (with POSIX everywhere) | You only need a drop‑in for `node:path` |
|
|
38
|
-
| **`pathkit`** | Everything in `pathe` **+** advanced utilities | You need alias resolution, import transforms, etc. |
|
|
39
|
-
|
|
40
|
-
## Why Pathkit? — The Problem with Native Paths
|
|
41
|
-
|
|
42
|
-
Native `node:path` flips behavior between operating systems, spurring subtle bugs and OS checks.
|
|
43
|
-
|
|
44
|
-
```js
|
|
45
|
-
// With node:path – the same call may yield different separators on each OS
|
|
46
|
-
import path from "node:path";
|
|
47
|
-
|
|
48
|
-
const project = "users/blefnk/project";
|
|
49
|
-
const full = path.join("C:\\", project);
|
|
50
|
-
console.log(full); // "C:\\users\\blefnk\\project" (Windows) vs ??? (others)
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### ✅ The `pathkit` Fix
|
|
54
|
-
|
|
55
|
-
```js
|
|
56
|
-
import { join } from "@reliverse/pathkit";
|
|
57
|
-
|
|
58
|
-
const full = join("C:", "users", "blefnk", "project");
|
|
59
|
-
console.log(full); // "C:/users/blefnk/project" on **every** OS 🎉
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
| Pain Point | `@reliverse/pathkit` Solution |
|
|
63
|
-
| :----------------------------- | :--------------------------- |
|
|
64
|
-
| Inconsistent separators | ✅ Always `/` |
|
|
65
|
-
| OS‑specific work‑arounds | ✅ One code path |
|
|
66
|
-
| Needs TypeScript + ESM | ✅ Built‑in |
|
|
67
|
-
| Works in Bun / Deno / Node | ✅ Out of the box |
|
|
68
|
-
|
|
69
|
-
## Quick Start
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
import { resolve, join, normalize } from "@reliverse/pathkit";
|
|
73
|
-
|
|
74
|
-
// Mixed slashes & dot‑segments? No problem.
|
|
75
|
-
const messy = "src\\..\\./dist///file.js";
|
|
76
|
-
console.log(resolve(messy)); // → "dist/file.js"
|
|
77
|
-
|
|
78
|
-
// Join is predictable everywhere:
|
|
79
|
-
console.log(join("users", "blefnk")); // → "users/blefnk"
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
**Side‑by‑Side Demo**:
|
|
83
|
-
|
|
84
|
-
| Code | Windows Output | macOS / Linux Output |
|
|
85
|
-
|------|----------------|----------------------|
|
|
86
|
-
| `join("a", "b")` | `a/b` | `a/b` |
|
|
87
|
-
| `resolve("..", "x")` | `x` | `x` |
|
|
88
|
-
|
|
89
|
-
Say goodbye to `process.platform` conditionals 👋.
|
|
90
|
-
|
|
91
|
-
## pathkit advanced features
|
|
92
|
-
|
|
93
|
-
`@reliverse/pathkit` extends the core functionality of `node:path` with powerful utilities for working with imports, aliases, and more.
|
|
94
|
-
|
|
95
|
-
### Import/Export Analysis
|
|
96
|
-
|
|
97
|
-
The `getFileImportsExports` function provides detailed analysis of ES module imports and exports:
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
import { getFileImportsExports } from "@reliverse/pathkit";
|
|
101
|
-
|
|
102
|
-
const code = `
|
|
103
|
-
import { ref } from "vue";
|
|
104
|
-
import utils from "@/utils";
|
|
105
|
-
import type { Config } from "./types";
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
1
|
+
# pathkit • cross‑platform path manipulation
|
|
2
|
+
|
|
3
|
+
> @reliverse/pathkit is a slash‑consistent, cross‑platform path manipulation, with POSIX forward slash, drop‑in for node:path and unjs/pathe. This library extends the node:path module with a set of functions for manipulating file paths.
|
|
4
|
+
|
|
5
|
+
[sponsor](https://github.com/sponsors/blefnk) • [discord](https://discord.gg/Pb8uKbwpsJ) • [npm](https://npmjs.com/package/@reliverse/pathkit) • [repo](https://github.com/reliverse/pathkit)
|
|
6
|
+
|
|
7
|
+
## Key Features
|
|
8
|
+
|
|
9
|
+
- 🔹 **drop in** and replace `node:path` and `unjs/pathe` instantly
|
|
10
|
+
- ➕ **`unjs/pathe` on steroids** – alias resolution, import parsing, and more
|
|
11
|
+
- 🌀 **always `/`** – posix separators 100% of the time (buh‑bye `\\`)
|
|
12
|
+
- ⚙️ **node.js api compatible** – familiar methods, no learning curve
|
|
13
|
+
- 🚀 **modern & fast** – typescript, pure esm, bun & node‑ready
|
|
14
|
+
- 🧠 **predictable & testable** – deterministic output across windows / macos / linux
|
|
15
|
+
- 🧼 **no dependencies** – just better path api + couple of cool utilities = [4kB](https://bundlephobia.com/package/@reliverse/pathkit@latest)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# bun • pnpm • yarn • npm
|
|
21
|
+
bun add @reliverse/pathkit
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Migrate**:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# soon:
|
|
28
|
+
# bun add -D @reliverse/dler
|
|
29
|
+
# bun dler migrate --lib path-to-pathkit
|
|
30
|
+
# bun dler migrate --lib pathe-to-pathkit
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### `unjs/pathe` vs `@reliverse/pathkit`
|
|
34
|
+
|
|
35
|
+
| Package | What you get | When to use |
|
|
36
|
+
|---------|--------------|-------------|
|
|
37
|
+
| **`pathe`** | Path API only (with POSIX everywhere) | You only need a drop‑in for `node:path` |
|
|
38
|
+
| **`pathkit`** | Everything in `pathe` **+** advanced utilities | You need alias resolution, import transforms, etc. |
|
|
39
|
+
|
|
40
|
+
## Why Pathkit? — The Problem with Native Paths
|
|
41
|
+
|
|
42
|
+
Native `node:path` flips behavior between operating systems, spurring subtle bugs and OS checks.
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
// With node:path – the same call may yield different separators on each OS
|
|
46
|
+
import path from "node:path";
|
|
47
|
+
|
|
48
|
+
const project = "users/blefnk/project";
|
|
49
|
+
const full = path.join("C:\\", project);
|
|
50
|
+
console.log(full); // "C:\\users\\blefnk\\project" (Windows) vs ??? (others)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### ✅ The `pathkit` Fix
|
|
54
|
+
|
|
55
|
+
```js
|
|
56
|
+
import { join } from "@reliverse/pathkit";
|
|
57
|
+
|
|
58
|
+
const full = join("C:", "users", "blefnk", "project");
|
|
59
|
+
console.log(full); // "C:/users/blefnk/project" on **every** OS 🎉
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
| Pain Point | `@reliverse/pathkit` Solution |
|
|
63
|
+
| :----------------------------- | :--------------------------- |
|
|
64
|
+
| Inconsistent separators | ✅ Always `/` |
|
|
65
|
+
| OS‑specific work‑arounds | ✅ One code path |
|
|
66
|
+
| Needs TypeScript + ESM | ✅ Built‑in |
|
|
67
|
+
| Works in Bun / Deno / Node | ✅ Out of the box |
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { resolve, join, normalize } from "@reliverse/pathkit";
|
|
73
|
+
|
|
74
|
+
// Mixed slashes & dot‑segments? No problem.
|
|
75
|
+
const messy = "src\\..\\./dist///file.js";
|
|
76
|
+
console.log(resolve(messy)); // → "dist/file.js"
|
|
77
|
+
|
|
78
|
+
// Join is predictable everywhere:
|
|
79
|
+
console.log(join("users", "blefnk")); // → "users/blefnk"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Side‑by‑Side Demo**:
|
|
83
|
+
|
|
84
|
+
| Code | Windows Output | macOS / Linux Output |
|
|
85
|
+
|------|----------------|----------------------|
|
|
86
|
+
| `join("a", "b")` | `a/b` | `a/b` |
|
|
87
|
+
| `resolve("..", "x")` | `x` | `x` |
|
|
88
|
+
|
|
89
|
+
Say goodbye to `process.platform` conditionals 👋.
|
|
90
|
+
|
|
91
|
+
## pathkit advanced features
|
|
92
|
+
|
|
93
|
+
`@reliverse/pathkit` extends the core functionality of `node:path` with powerful utilities for working with imports, aliases, and more.
|
|
94
|
+
|
|
95
|
+
### Import/Export Analysis
|
|
96
|
+
|
|
97
|
+
The `getFileImportsExports` function provides detailed analysis of ES module imports and exports in your code:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { getFileImportsExports } from "@reliverse/pathkit";
|
|
101
|
+
|
|
102
|
+
const code = `
|
|
103
|
+
import { ref } from "vue";
|
|
104
|
+
import utils from "@/utils";
|
|
105
|
+
import type { Config } from "./types";
|
|
106
|
+
import * as React from "react";
|
|
107
|
+
import { Button as UIButton } from "./components";
|
|
108
|
+
export { default as MyComponent } from "./MyComponent";
|
|
109
|
+
export type { Props } from "./types";
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
const analysis = getFileImportsExports(code, {
|
|
113
|
+
kind: "all", // "import" | "export" | "all"
|
|
114
|
+
pathTypes: ["alias"], // Filter by path types: "alias" | "relative" | "absolute" | "bare" | "module"
|
|
115
|
+
limitPerType: 2 // Limit results per type
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The analysis provides rich information about each import/export statement:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
interface ImportExportInfo {
|
|
123
|
+
statement: string; // Full original statement
|
|
124
|
+
type: "static" | "dynamic"; // Import type (static or dynamic import())
|
|
125
|
+
kind: "import" | "export"; // Statement kind
|
|
126
|
+
source?: string; // Import/export source path
|
|
127
|
+
pathType?: "alias" | "relative" | "absolute" | "bare" | "module";
|
|
128
|
+
pathTypeSymbol?: string; // Path prefix (e.g., "@/", "~/")
|
|
129
|
+
isTypeOnly?: boolean; // Type-only import/export
|
|
130
|
+
specifiers?: { // Imported/exported items
|
|
131
|
+
type: "named" | "default" | "namespace" | "all";
|
|
132
|
+
name: string;
|
|
133
|
+
alias?: string;
|
|
134
|
+
isType?: boolean;
|
|
135
|
+
}[];
|
|
136
|
+
start: number; // Position in source
|
|
137
|
+
end: number;
|
|
138
|
+
importExt?: string; // Extension as written in import/export statement
|
|
139
|
+
realFileExt?: string; // Likely actual file extension (e.g., .ts for .js imports)
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Features:
|
|
144
|
+
|
|
145
|
+
- ✨ **Comprehensive Syntax Support**
|
|
146
|
+
- Static imports (`import x from "y"`)
|
|
147
|
+
- Dynamic imports (`import("y")`)
|
|
148
|
+
- Named imports/exports (`import { x } from "y"`)
|
|
149
|
+
- Default imports/exports (`import x from "y"`)
|
|
150
|
+
- Namespace imports (`import * as x from "y"`)
|
|
151
|
+
- Re-exports (`export * from "y"`)
|
|
152
|
+
- Type imports/exports (`import type { x } from "y"`)
|
|
153
|
+
|
|
154
|
+
- 🔍 **Path Analysis**
|
|
155
|
+
- Detects path types (alias, relative, absolute, bare, module)
|
|
156
|
+
- Extracts path prefixes (e.g., `@/`, `~/`)
|
|
157
|
+
- Preserves original path format
|
|
158
|
+
- Tracks both import statement extensions and likely real file extensions
|
|
159
|
+
- Handles TypeScript/JavaScript extension conversion (e.g., `.js` → `.ts`)
|
|
160
|
+
|
|
161
|
+
- 🎯 **Specifier Details**
|
|
162
|
+
- Named imports/exports with aliases
|
|
163
|
+
- Default imports/exports
|
|
164
|
+
- Namespace imports
|
|
165
|
+
- Type-only imports/exports
|
|
166
|
+
- Mixed type and value imports
|
|
167
|
+
|
|
168
|
+
- 📊 **Filtering Options**
|
|
169
|
+
- Filter by statement kind (import/export)
|
|
170
|
+
- Filter by path types
|
|
171
|
+
- Limit results per type
|
|
172
|
+
- Preserve statement order
|
|
173
|
+
|
|
174
|
+
- 🛡️ **Type Safety**
|
|
175
|
+
- Full TypeScript support
|
|
176
|
+
- Detailed type definitions
|
|
177
|
+
- Null-safe operations
|
|
178
|
+
|
|
179
|
+
Example output:
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
[
|
|
183
|
+
{
|
|
184
|
+
statement: 'import { ref } from "vue"',
|
|
185
|
+
type: "static",
|
|
186
|
+
kind: "import",
|
|
187
|
+
source: "vue",
|
|
188
|
+
pathType: "bare",
|
|
189
|
+
specifiers: [{
|
|
190
|
+
type: "named",
|
|
191
|
+
name: "ref"
|
|
192
|
+
}],
|
|
193
|
+
start: 0,
|
|
194
|
+
end: 24,
|
|
195
|
+
importExt: "",
|
|
196
|
+
realFileExt: ""
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
statement: 'import type { Config } from "./types.js"',
|
|
200
|
+
type: "static",
|
|
201
|
+
kind: "import",
|
|
202
|
+
source: "./types.js",
|
|
203
|
+
pathType: "relative",
|
|
204
|
+
isTypeOnly: true,
|
|
205
|
+
specifiers: [{
|
|
206
|
+
type: "named",
|
|
207
|
+
name: "Config",
|
|
208
|
+
isType: true
|
|
209
|
+
}],
|
|
210
|
+
start: 45,
|
|
211
|
+
end: 85,
|
|
212
|
+
importExt: ".js",
|
|
213
|
+
realFileExt: ".ts"
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Path Transformation
|
|
219
|
+
|
|
220
|
+
Convert between different path formats:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
import { convertImportPaths } from "@reliverse/pathkit";
|
|
224
|
+
|
|
225
|
+
await convertImportPaths({
|
|
226
|
+
baseDir: "./src",
|
|
227
|
+
fromType: "relative", // "./components/Button"
|
|
228
|
+
toType: "alias", // "@/components/Button"
|
|
229
|
+
aliasPrefix: "@/",
|
|
230
|
+
generateSourceMap: true
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Extension Conversion
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
import { convertImportsExt } from "@reliverse/pathkit";
|
|
238
|
+
|
|
239
|
+
// Basic usage - convert all relative imports to .ts
|
|
240
|
+
await convertImportsExt({
|
|
241
|
+
targetDir: "./src",
|
|
242
|
+
extFrom: "none",
|
|
243
|
+
extTo: "ts"
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Convert .js to .ts
|
|
247
|
+
await convertImportsExt({
|
|
248
|
+
targetDir: "./src",
|
|
249
|
+
extFrom: "js",
|
|
250
|
+
extTo: "ts"
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Remove extensions
|
|
254
|
+
await convertImportsExt({
|
|
255
|
+
targetDir: "./src",
|
|
256
|
+
extFrom: "ts",
|
|
257
|
+
extTo: "none"
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Handle alias paths (e.g. @/components)
|
|
261
|
+
await convertImportsExt({
|
|
262
|
+
targetDir: "./src",
|
|
263
|
+
extFrom: "none",
|
|
264
|
+
extTo: "ts",
|
|
265
|
+
alias: "@" // or "@/*"
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
The function intelligently handles different import types:
|
|
270
|
+
|
|
271
|
+
- ✅ Relative imports (`./file`, `../file`)
|
|
272
|
+
- ✅ Alias imports (when alias is specified)
|
|
273
|
+
- ✅ Package imports (`lodash`, `@scope/pkg`)
|
|
274
|
+
- ✅ Node built-ins (`node:path`, `node:fs`)
|
|
275
|
+
- ✅ URLs (`http://`, `https://`)
|
|
276
|
+
- ✅ Already processed paths
|
|
277
|
+
|
|
278
|
+
Features:
|
|
279
|
+
|
|
280
|
+
- 🔄 Recursively processes directories
|
|
281
|
+
- 🎯 Preserves package imports
|
|
282
|
+
- 🛡️ Safe for code generation
|
|
283
|
+
- 📝 Detailed change logging
|
|
284
|
+
- 🎨 Supports custom aliases
|
|
285
|
+
|
|
286
|
+
### Alias Resolution
|
|
287
|
+
|
|
288
|
+
Advanced alias handling and resolution:
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
import {
|
|
292
|
+
normalizeAliases,
|
|
293
|
+
resolveAlias,
|
|
294
|
+
reverseResolveAlias
|
|
295
|
+
} from "@reliverse/pathkit";
|
|
296
|
+
|
|
297
|
+
const aliases = { "@/": "/src/", "~/": "/home/user/" };
|
|
298
|
+
|
|
299
|
+
// Normalize alias config
|
|
300
|
+
console.log(normalizeAliases(aliases));
|
|
301
|
+
|
|
302
|
+
// Resolve alias to absolute path
|
|
303
|
+
console.log(resolveAlias("@/components", aliases)); // "/src/components"
|
|
304
|
+
|
|
305
|
+
// Convert absolute path back to alias
|
|
306
|
+
console.log(reverseResolveAlias("/src/utils", aliases)); // "@/utils"
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
import {
|
|
311
|
+
normalizeAliases,
|
|
312
|
+
resolveAlias,
|
|
313
|
+
reverseResolveAlias,
|
|
314
|
+
findAliasMatch
|
|
315
|
+
} from "@reliverse/pathkit";
|
|
316
|
+
|
|
317
|
+
// Normalize and optimize alias configurations
|
|
318
|
+
const aliases = {
|
|
319
|
+
"@/": "/src/",
|
|
320
|
+
"~/": "/home/user/",
|
|
321
|
+
"@/components/": "/src/components/" // Nested alias
|
|
322
|
+
};
|
|
323
|
+
const normalized = normalizeAliases(aliases);
|
|
324
|
+
|
|
325
|
+
// Resolve aliased paths
|
|
326
|
+
resolveAlias("@/components/Button", aliases); // "/src/components/Button"
|
|
327
|
+
|
|
328
|
+
// Convert absolute paths back to aliases
|
|
329
|
+
reverseResolveAlias("/src/utils", aliases); // ["@/utils"]
|
|
330
|
+
|
|
331
|
+
// Find matching alias in tsconfig-style paths
|
|
332
|
+
const paths = {
|
|
333
|
+
"@/*": ["./src/*"],
|
|
334
|
+
"~/*": ["./home/*"]
|
|
335
|
+
};
|
|
336
|
+
findAliasMatch("@/components/Button", paths);
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Path Conversion
|
|
340
|
+
|
|
341
|
+
Convert between different path formats:
|
|
342
|
+
|
|
343
|
+
```ts
|
|
344
|
+
import {
|
|
345
|
+
convertStringAliasRelative,
|
|
346
|
+
convertImportsAliasToRelative
|
|
347
|
+
} from "@reliverse/pathkit";
|
|
348
|
+
|
|
349
|
+
// Convert a single aliased path to relative
|
|
350
|
+
await convertStringAliasRelative({
|
|
351
|
+
importPath: "@/components/Button",
|
|
352
|
+
importerFile: "src/pages/Home.tsx",
|
|
353
|
+
pathPattern: "@/*",
|
|
354
|
+
targetDir: "src"
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Convert all aliased imports to relative in a directory
|
|
358
|
+
await convertImportsAliasToRelative({
|
|
359
|
+
targetDir: "./src",
|
|
360
|
+
aliasToReplace: "@",
|
|
361
|
+
pathExtFilter: "js-ts-none" // "js" | "ts" | "none" | "js-ts-none"
|
|
362
|
+
});
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Platform-Specific Features
|
|
366
|
+
|
|
367
|
+
Handle platform-specific path operations:
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
import { posix, win32 } from "@reliverse/pathkit";
|
|
371
|
+
|
|
372
|
+
// Use platform-specific path handling
|
|
373
|
+
const path = process.platform === "win32" ? win32 : posix;
|
|
374
|
+
|
|
375
|
+
// Windows-specific features
|
|
376
|
+
win32.toNamespacedPath("C:\\path\\to\\file"); // "\\\\?\\C:\\path\\to\\file"
|
|
377
|
+
win32.delimiter; // ";"
|
|
378
|
+
|
|
379
|
+
// POSIX-specific features
|
|
380
|
+
posix.delimiter; // ":"
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### Utility Functions
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
import {
|
|
387
|
+
filename, // Strip extension
|
|
388
|
+
normalizeQuotes, // Standardize quote style
|
|
389
|
+
matchesGlob // Test glob patterns
|
|
390
|
+
} from "@reliverse/pathkit";
|
|
391
|
+
|
|
392
|
+
console.log(filename("/path/component.vue")); // "component"
|
|
393
|
+
console.log(normalizeQuotes("import 'pkg'")); // 'import "pkg"'
|
|
394
|
+
console.log(matchesGlob("file.ts", "**/*.ts")); // true
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
import {
|
|
399
|
+
filename,
|
|
400
|
+
normalizeWindowsPath,
|
|
401
|
+
replaceAllInString
|
|
402
|
+
} from "@reliverse/pathkit";
|
|
403
|
+
|
|
404
|
+
// Get filename without extension
|
|
405
|
+
filename("/path/to/file.ts"); // "file"
|
|
406
|
+
|
|
407
|
+
// Normalize Windows paths
|
|
408
|
+
normalizeWindowsPath("C:\\path\\to\\file"); // "C:/path/to/file"
|
|
409
|
+
|
|
410
|
+
// Replace strings while tracking position
|
|
411
|
+
replaceAllInString("import x from 'y'", "'y'", "'z'");
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Supported File Extensions
|
|
415
|
+
|
|
416
|
+
The library supports the following file extensions by default:
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
const EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Type Definitions
|
|
423
|
+
|
|
424
|
+
```ts
|
|
425
|
+
type PathExtFilter = "js" | "ts" | "none" | "js-ts-none";
|
|
426
|
+
type ImportExtType = "js" | "ts" | "none";
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Use Cases / Ideal For
|
|
430
|
+
|
|
431
|
+
- 🛠️ **CLI tools**
|
|
432
|
+
- 🌍 **Cross‑platform dev environments**
|
|
433
|
+
- 🔄 **Bundlers, linters, compilers**
|
|
434
|
+
- 🏗️ **Framework & library authors**
|
|
435
|
+
- 📜 **Scripts / test runners**
|
|
436
|
+
- …anywhere file‑paths roam!
|
|
437
|
+
|
|
438
|
+
## Examples & Contributing
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
git clone https://github.com/reliverse/pathkit.git
|
|
442
|
+
cd pathkit
|
|
443
|
+
bun install
|
|
444
|
+
bun dev
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Bug reports & PRs are warmly welcome—come on in!
|
|
448
|
+
|
|
449
|
+
## Related
|
|
450
|
+
|
|
451
|
+
- [`@reliverse/rempts`](https://npmjs.com/package/@reliverse/rempts) – Terminal Prompts Engine
|
|
452
|
+
|
|
453
|
+
## Community
|
|
454
|
+
|
|
455
|
+
- ⭐ **Star** the repo if this helped you.
|
|
456
|
+
- 💖 **Sponsor** [@blefnk](https://github.com/sponsors/blefnk) to keep the lights on.
|
|
457
|
+
- 💬 **Chat** with us on [Discord](https://discord.gg/Pb8uKbwpsJ).
|
|
458
|
+
|
|
459
|
+
## License
|
|
460
|
+
|
|
461
|
+
[MIT](LICENSE) © [Nazar Kornienko (blefnk)](https://github.com/blefnk), [Reliverse](https://github.com/reliverse)
|
|
462
|
+
|
|
463
|
+
## Badges
|
|
464
|
+
|
|
465
|
+
[](https://npmjs.com/package/@reliverse/pathkit)
|
|
466
|
+
[](https://npmjs.com/package/@reliverse/pathkit)
|
|
467
|
+
[](https://github.com/reliverse/pathkit)
|
|
468
|
+
[](LICENSE)
|
|
469
|
+
|
|
470
|
+
### Path Segment Manipulation
|
|
471
|
+
|
|
472
|
+
Manipulate path segments in import statements:
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
import {
|
|
476
|
+
stripPathSegments,
|
|
477
|
+
stripPathSegmentsInDirectory,
|
|
478
|
+
attachPathSegments,
|
|
479
|
+
attachPathSegmentsInDirectory
|
|
480
|
+
} from "@reliverse/pathkit";
|
|
481
|
+
|
|
482
|
+
// Strip segments from a path
|
|
483
|
+
stripPathSegments("src/components/Button.tsx", 1); // "components/Button.tsx"
|
|
484
|
+
|
|
485
|
+
// Strip segments from imports in a directory
|
|
486
|
+
await stripPathSegmentsInDirectory({
|
|
487
|
+
targetDir: "./src",
|
|
488
|
+
segmentsToStrip: 1,
|
|
489
|
+
alias: "@" // Optional: preserve alias prefix
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
// Attach segments to a path
|
|
493
|
+
attachPathSegments("Button.tsx", "components", {
|
|
494
|
+
position: "before", // "before" | "after"
|
|
495
|
+
normalize: true, // Normalize the path
|
|
496
|
+
ensureSlash: true, // Ensure slash between segments
|
|
497
|
+
preserveRoot: true, // Preserve root in absolute paths
|
|
498
|
+
preserveAlias: "@" // Optional: preserve alias prefix
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// Attach segments to imports in a directory
|
|
502
|
+
await attachPathSegmentsInDirectory({
|
|
503
|
+
targetDir: "./src",
|
|
504
|
+
segments: "components",
|
|
505
|
+
options: {
|
|
506
|
+
position: "before",
|
|
507
|
+
preserveAlias: "@"
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
```
|
|
@@ -5,6 +5,35 @@ export function getFileImportsExports(content, options = {}) {
|
|
|
5
5
|
limitPerType
|
|
6
6
|
} = options;
|
|
7
7
|
const results = [];
|
|
8
|
+
function getImportExtension(path) {
|
|
9
|
+
if (!path) return "";
|
|
10
|
+
const lastDotIndex = path.lastIndexOf(".");
|
|
11
|
+
if (lastDotIndex <= 0 || lastDotIndex === path.length - 1) {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
const extension = path.slice(lastDotIndex);
|
|
15
|
+
if (path.endsWith(".d.ts")) {
|
|
16
|
+
return ".d.ts";
|
|
17
|
+
}
|
|
18
|
+
return extension;
|
|
19
|
+
}
|
|
20
|
+
function getRealFileExtension(path, pathType) {
|
|
21
|
+
if (pathType === "bare" || pathType === "alias") {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
if (pathType === "module") {
|
|
25
|
+
return getImportExtension(path);
|
|
26
|
+
}
|
|
27
|
+
const pathExt = getImportExtension(path);
|
|
28
|
+
if (!pathExt) return "";
|
|
29
|
+
if (pathExt === ".js" || pathExt === ".jsx") {
|
|
30
|
+
return pathExt === ".jsx" ? ".tsx" : ".ts";
|
|
31
|
+
}
|
|
32
|
+
if (pathExt === ".ts" || pathExt === ".tsx") {
|
|
33
|
+
return pathExt;
|
|
34
|
+
}
|
|
35
|
+
return pathExt;
|
|
36
|
+
}
|
|
8
37
|
const patterns = {
|
|
9
38
|
// import statements with from clause
|
|
10
39
|
staticImport: /import\s+(?:type\s+)?(?:(?:\w+)(?:\s*,\s*)?)?(?:\{[^}]*\}|\*\s+as\s+\w+)?\s+from\s+['"]([^'"]+)['"]|import\s+(?:type\s+)?(\w+)\s+from\s+['"]([^'"]+)['"]/g,
|
|
@@ -92,7 +121,9 @@ export function getFileImportsExports(content, options = {}) {
|
|
|
92
121
|
isTypeOnly: match[0].includes("import type"),
|
|
93
122
|
specifiers: extractSpecifiers(match[0]),
|
|
94
123
|
start: match.index ?? 0,
|
|
95
|
-
end: (match.index ?? 0) + match[0].length
|
|
124
|
+
end: (match.index ?? 0) + match[0].length,
|
|
125
|
+
importExt: getImportExtension(source),
|
|
126
|
+
realFileExt: getRealFileExtension(source, pathType)
|
|
96
127
|
};
|
|
97
128
|
results.push(info);
|
|
98
129
|
}
|
|
@@ -112,7 +143,9 @@ export function getFileImportsExports(content, options = {}) {
|
|
|
112
143
|
isTypeOnly: false,
|
|
113
144
|
specifiers: [],
|
|
114
145
|
start: match.index ?? 0,
|
|
115
|
-
end: (match.index ?? 0) + match[0].length
|
|
146
|
+
end: (match.index ?? 0) + match[0].length,
|
|
147
|
+
importExt: getImportExtension(source),
|
|
148
|
+
realFileExt: getRealFileExtension(source, pathType)
|
|
116
149
|
};
|
|
117
150
|
results.push(info);
|
|
118
151
|
}
|
|
@@ -134,7 +167,9 @@ export function getFileImportsExports(content, options = {}) {
|
|
|
134
167
|
isTypeOnly: match[0].includes("export type"),
|
|
135
168
|
specifiers: extractSpecifiers(match[0]),
|
|
136
169
|
start: match.index ?? 0,
|
|
137
|
-
end: (match.index ?? 0) + match[0].length
|
|
170
|
+
end: (match.index ?? 0) + match[0].length,
|
|
171
|
+
importExt: getImportExtension(source),
|
|
172
|
+
realFileExt: getRealFileExtension(source, pathType)
|
|
138
173
|
};
|
|
139
174
|
results.push(info);
|
|
140
175
|
}
|
|
@@ -150,7 +185,9 @@ export function getFileImportsExports(content, options = {}) {
|
|
|
150
185
|
isTypeOnly: false,
|
|
151
186
|
specifiers: [{ type: "default", name: "default" }],
|
|
152
187
|
start: match.index,
|
|
153
|
-
end: match.index + match[0].length
|
|
188
|
+
end: match.index + match[0].length,
|
|
189
|
+
importExt: void 0,
|
|
190
|
+
realFileExt: void 0
|
|
154
191
|
};
|
|
155
192
|
results.push(info);
|
|
156
193
|
}
|
|
@@ -168,7 +205,9 @@ export function getFileImportsExports(content, options = {}) {
|
|
|
168
205
|
isTypeOnly: match[0].includes("export type"),
|
|
169
206
|
specifiers: [{ type: "named", name }],
|
|
170
207
|
start: match.index,
|
|
171
|
-
end: match.index + match[0].length
|
|
208
|
+
end: match.index + match[0].length,
|
|
209
|
+
importExt: void 0,
|
|
210
|
+
realFileExt: void 0
|
|
172
211
|
};
|
|
173
212
|
results.push(info);
|
|
174
213
|
}
|
package/bin/mod.d.ts
CHANGED
|
@@ -111,10 +111,11 @@ declare function convertImportsAliasToRelative({ targetDir, aliasToReplace, path
|
|
|
111
111
|
/**
|
|
112
112
|
* converts extensions in import paths from one format to another
|
|
113
113
|
*/
|
|
114
|
-
declare function convertImportsExt({ targetDir, extFrom, extTo, }: {
|
|
114
|
+
declare function convertImportsExt({ targetDir, extFrom, extTo, alias, }: {
|
|
115
115
|
targetDir: string;
|
|
116
116
|
extFrom: ImportExtType;
|
|
117
117
|
extTo: ImportExtType;
|
|
118
|
+
alias?: string;
|
|
118
119
|
}): Promise<{
|
|
119
120
|
file: string;
|
|
120
121
|
changes: {
|
package/bin/mod.js
CHANGED
|
@@ -574,10 +574,13 @@ async function convertImportsAliasToRelative({
|
|
|
574
574
|
async function convertImportsExt({
|
|
575
575
|
targetDir,
|
|
576
576
|
extFrom,
|
|
577
|
-
extTo
|
|
577
|
+
extTo,
|
|
578
|
+
alias
|
|
578
579
|
}) {
|
|
579
580
|
const fromExtStr = extFrom === "none" ? "" : `.${extFrom}`;
|
|
580
581
|
const toExtStr = extTo === "none" ? "" : `.${extTo}`;
|
|
582
|
+
const normalizedAlias = alias ? alias.endsWith("/*") ? alias : `${alias}/*` : void 0;
|
|
583
|
+
const aliasPrefix = normalizedAlias?.replace("/*", "");
|
|
581
584
|
const importRegex = new RegExp(
|
|
582
585
|
`(?:^|;|\\n)\\s*(?:import\\s+(?:[\\s\\S]*?)\\s+from\\s+|import\\s*\\(\\s*|export\\s+\\*\\s+from\\s+)\\s*(['"])([^'"]+${fromExtStr.replace(".", "\\.")})(\\1)`,
|
|
583
586
|
"gm"
|
|
@@ -585,9 +588,19 @@ async function convertImportsExt({
|
|
|
585
588
|
function shouldSkipPath(path2) {
|
|
586
589
|
if (path2.startsWith("node:") || path2.startsWith("bun:") || path2.startsWith("npm:") || path2.startsWith("jsr:") || path2.startsWith("node_modules"))
|
|
587
590
|
return true;
|
|
588
|
-
if (
|
|
591
|
+
if (aliasPrefix && path2.startsWith(aliasPrefix)) {
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
const segments = path2.split("/");
|
|
595
|
+
const firstSegment = segments[0];
|
|
596
|
+
if (!firstSegment) return false;
|
|
597
|
+
if (path2.startsWith("@") || // scoped packages
|
|
598
|
+
!firstSegment.includes(".") || // simple package names
|
|
599
|
+
firstSegment.includes("-") && !firstSegment.startsWith("."))
|
|
600
|
+
return true;
|
|
589
601
|
if (path2.startsWith("http://") || path2.startsWith("https://")) return true;
|
|
590
602
|
if (extTo !== "none" && path2.endsWith(`.${extTo}`)) return true;
|
|
603
|
+
if (extFrom === "none" && /\.[^/]+$/.test(path2)) return true;
|
|
591
604
|
return false;
|
|
592
605
|
}
|
|
593
606
|
try {
|
|
@@ -601,7 +614,8 @@ async function convertImportsExt({
|
|
|
601
614
|
const subdirResults = await convertImportsExt({
|
|
602
615
|
targetDir: fullPath,
|
|
603
616
|
extFrom,
|
|
604
|
-
extTo
|
|
617
|
+
extTo,
|
|
618
|
+
alias
|
|
605
619
|
});
|
|
606
620
|
results.push(...subdirResults);
|
|
607
621
|
} else if (EXTENSIONS.includes(extname(entry.name))) {
|
|
@@ -620,7 +634,7 @@ async function convertImportsExt({
|
|
|
620
634
|
}
|
|
621
635
|
let replacementPath;
|
|
622
636
|
if (extFrom === "none") {
|
|
623
|
-
replacementPath = importPath + toExtStr;
|
|
637
|
+
replacementPath = /\.[^/]+$/.test(importPath) ? importPath : importPath + toExtStr;
|
|
624
638
|
} else if (extTo === "none") {
|
|
625
639
|
replacementPath = importPath.slice(0, -fromExtStr.length);
|
|
626
640
|
} else {
|