@reliverse/pathkit 1.0.6 → 1.1.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/bin/mod.js CHANGED
@@ -1,50 +1,994 @@
1
- import { delimiter, posix, win32 } from "./pathkit-impl/impl.js";
2
- import {
1
+ import fs from "node:fs/promises";
2
+ const log = (msg) => console.log(`\x1B[2m${msg}\x1B[0m`);
3
+ const logInternal = (msg) => console.log(`\x1B[36;2m${msg}\x1B[0m`);
4
+ const EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
5
+ const SLASH = "/";
6
+ const BACK_SLASH = "\\";
7
+ const DOT = ".";
8
+ const DOUBLE_DOT = "..";
9
+ const EMPTY = "";
10
+ const normalizedAliasSymbol = Symbol.for("pathkit:normalizedAlias");
11
+ const DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
12
+ const DRIVE_LETTER_RE = /^[A-Za-z]:$/;
13
+ const UNC_REGEX = /^[/\\]{2}/;
14
+ const IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
15
+ const ROOT_FOLDER_RE = /^\/([A-Za-z]:)?$/;
16
+ const PATH_ROOT_RE = /^[/\\]|^[a-zA-Z]:[/\\]/;
17
+ const IMPORT_REGEX = /(?:import\s+(?:[\s\S]*?)\s+from\s+|import\s*\(\s*)\s*(['"])((?:@)[^'"]+)\1/g;
18
+ async function cleanDirs(dirs) {
19
+ await Promise.all(
20
+ dirs.map(async (d) => {
21
+ try {
22
+ await fs.rm(d, { recursive: true, force: true });
23
+ logInternal(`\u2713 cleaned: ${d}`);
24
+ } catch (error) {
25
+ log(
26
+ `\u2717 error cleaning ${d}: ${error instanceof Error ? error.message : String(error)}`
27
+ );
28
+ }
29
+ })
30
+ );
31
+ }
32
+ async function copyDir(src, dest) {
33
+ logInternal(`\u2713 copying: ${src} \u2192 ${dest}`);
34
+ try {
35
+ await fs.mkdir(dest, { recursive: true });
36
+ const entries = await fs.readdir(src, { withFileTypes: true });
37
+ await Promise.all(
38
+ entries.map(async (entry) => {
39
+ const srcPath = join(src, entry.name);
40
+ const destPath = join(dest, entry.name);
41
+ if (entry.isDirectory()) {
42
+ return copyDir(srcPath, destPath);
43
+ }
44
+ await fs.copyFile(srcPath, destPath);
45
+ logInternal(` copied: ${srcPath} \u2192 ${destPath}`);
46
+ })
47
+ );
48
+ } catch (error) {
49
+ const errorMsg = error instanceof Error ? error.message : String(error);
50
+ log(`\u2717 error copying directory ${src} to ${dest}: ${errorMsg}`);
51
+ throw error;
52
+ }
53
+ }
54
+ function normalizeWindowsPath(input = "") {
55
+ if (!input) return input;
56
+ return input.replace(/\\/g, SLASH).replace(DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
57
+ }
58
+ function compareAliases(a, b) {
59
+ return b.split(SLASH).length - a.split(SLASH).length;
60
+ }
61
+ function cwd() {
62
+ if (typeof process !== "undefined" && typeof process.cwd === "function") {
63
+ return process.cwd().replace(/\\/g, SLASH);
64
+ }
65
+ return SLASH;
66
+ }
67
+ function normalizeString(path2, allowAboveRoot) {
68
+ let res = EMPTY;
69
+ let lastSegmentLength = 0;
70
+ let lastSlash = -1;
71
+ let dots = 0;
72
+ let char = null;
73
+ for (let index = 0; index <= path2.length; ++index) {
74
+ if (index < path2.length) {
75
+ char = path2[index];
76
+ } else if (char === SLASH) {
77
+ break;
78
+ } else {
79
+ char = SLASH;
80
+ }
81
+ if (char === SLASH) {
82
+ if (lastSlash === index - 1 || dots === 1) {
83
+ } else if (dots === 2) {
84
+ if (res.length < 2 || lastSegmentLength !== 2 || !res.endsWith(DOT) || res[res.length - 2] !== DOT) {
85
+ if (res.length > 2) {
86
+ const lastSlashIndex = res.lastIndexOf(SLASH);
87
+ if (lastSlashIndex === -1) {
88
+ res = EMPTY;
89
+ lastSegmentLength = 0;
90
+ } else {
91
+ res = res.slice(0, lastSlashIndex);
92
+ lastSegmentLength = res.length - 1 - res.lastIndexOf(SLASH);
93
+ }
94
+ lastSlash = index;
95
+ dots = 0;
96
+ continue;
97
+ }
98
+ if (res.length > 0) {
99
+ res = EMPTY;
100
+ lastSegmentLength = 0;
101
+ lastSlash = index;
102
+ dots = 0;
103
+ continue;
104
+ }
105
+ }
106
+ if (allowAboveRoot) {
107
+ res += res.length > 0 ? `${SLASH}..` : DOUBLE_DOT;
108
+ lastSegmentLength = 2;
109
+ }
110
+ } else {
111
+ const segment = path2.slice(lastSlash + 1, index);
112
+ if (res.length > 0) {
113
+ res += `${SLASH}${segment}`;
114
+ } else {
115
+ res = segment;
116
+ }
117
+ lastSegmentLength = segment.length;
118
+ }
119
+ lastSlash = index;
120
+ dots = 0;
121
+ } else if (char === DOT && dots !== -1) {
122
+ ++dots;
123
+ } else {
124
+ dots = -1;
125
+ }
126
+ }
127
+ return res;
128
+ }
129
+ const sep = SLASH;
130
+ const normalize = (path2) => {
131
+ if (path2.length === 0) return DOT;
132
+ const originalPath = path2;
133
+ path2 = normalizeWindowsPath(path2);
134
+ const isPathAbsolute = IS_ABSOLUTE_RE.test(path2);
135
+ const trailingSeparator = path2.endsWith(SLASH);
136
+ path2 = normalizeString(path2, !isPathAbsolute);
137
+ if (path2.length === 0) {
138
+ if (isPathAbsolute) return SLASH;
139
+ return trailingSeparator && originalPath.length > 0 && originalPath !== DOT ? "./" : DOT;
140
+ }
141
+ if (trailingSeparator && !path2.endsWith(SLASH)) {
142
+ path2 += SLASH;
143
+ }
144
+ if (DRIVE_LETTER_RE.test(path2) && path2.length === 2) {
145
+ path2 += SLASH;
146
+ }
147
+ if (UNC_REGEX.test(originalPath.replace(/\\/g, SLASH))) {
148
+ const normOriginal = originalPath.replace(/\\/g, SLASH);
149
+ if (normOriginal.startsWith("//./")) {
150
+ return `//./${path2.startsWith(SLASH) ? path2.substring(1) : path2}`;
151
+ }
152
+ if (normOriginal.startsWith("//") && !normOriginal.startsWith("//./")) {
153
+ return `//${path2.startsWith(SLASH) ? path2.substring(1) : path2}`;
154
+ }
155
+ }
156
+ if (isPathAbsolute && !IS_ABSOLUTE_RE.test(path2) && path2 !== SLASH) {
157
+ return `${SLASH}${path2}`;
158
+ }
159
+ return path2;
160
+ };
161
+ const join = (...segments) => {
162
+ if (segments.length === 0) return DOT;
163
+ let joined = EMPTY;
164
+ for (const segment of segments) {
165
+ if (typeof segment !== "string") {
166
+ throw new TypeError("Arguments to path.join must be strings");
167
+ }
168
+ if (segment.length > 0) {
169
+ if (joined.length === 0) {
170
+ joined = segment;
171
+ } else {
172
+ joined += `${SLASH}${segment}`;
173
+ }
174
+ }
175
+ }
176
+ if (joined.length === 0) return DOT;
177
+ return normalize(joined);
178
+ };
179
+ const resolve = (...args) => {
180
+ let resolvedPath = EMPTY;
181
+ let resolvedAbsolute = false;
182
+ for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
183
+ const path2 = i >= 0 ? args[i] : cwd();
184
+ if (typeof path2 !== "string") {
185
+ throw new TypeError("Arguments to path.resolve must be strings");
186
+ }
187
+ if (path2.length === 0) continue;
188
+ const normalizedSegment = normalizeWindowsPath(path2);
189
+ resolvedPath = `${normalizedSegment}${SLASH}${resolvedPath}`;
190
+ resolvedAbsolute = IS_ABSOLUTE_RE.test(normalizedSegment);
191
+ }
192
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
193
+ if (resolvedAbsolute) {
194
+ if (IS_ABSOLUTE_RE.test(resolvedPath)) {
195
+ return resolvedPath;
196
+ }
197
+ return `${SLASH}${resolvedPath}`;
198
+ }
199
+ return resolvedPath.length > 0 ? resolvedPath : DOT;
200
+ };
201
+ const isAbsolute = (p) => {
202
+ if (typeof p !== "string") return false;
203
+ return IS_ABSOLUTE_RE.test(normalizeWindowsPath(p));
204
+ };
205
+ const toNamespacedPath = (p) => {
206
+ if (typeof p !== "string" || p.length === 0) return p;
207
+ return normalize(p);
208
+ };
209
+ const extname = (p) => {
210
+ if (typeof p !== "string") return EMPTY;
211
+ const path2 = normalizeWindowsPath(p);
212
+ let lastSlashIdx = path2.lastIndexOf(SLASH);
213
+ if (lastSlashIdx === -1) lastSlashIdx = 0;
214
+ const basePart = lastSlashIdx === 0 ? path2 : path2.substring(lastSlashIdx + 1);
215
+ if (basePart === DOT || basePart === DOUBLE_DOT) return EMPTY;
216
+ const lastDotIdx = basePart.lastIndexOf(DOT);
217
+ if (lastDotIdx <= 0) return EMPTY;
218
+ return basePart.substring(lastDotIdx);
219
+ };
220
+ const relative = (from, to) => {
221
+ const resolvedFrom = resolve(from);
222
+ const resolvedTo = resolve(to);
223
+ if (resolvedFrom === resolvedTo) return EMPTY;
224
+ const fromSegments = resolvedFrom.replace(ROOT_FOLDER_RE, "$1").split(SLASH).filter(Boolean);
225
+ const toSegments = resolvedTo.replace(ROOT_FOLDER_RE, "$1").split(SLASH).filter(Boolean);
226
+ if (fromSegments.length > 0 && toSegments.length > 0 && DRIVE_LETTER_RE.test(fromSegments[0]) && DRIVE_LETTER_RE.test(toSegments[0]) && fromSegments[0].toUpperCase() !== toSegments[0].toUpperCase()) {
227
+ return resolvedTo;
228
+ }
229
+ let commonSegments = 0;
230
+ const maxCommon = Math.min(fromSegments.length, toSegments.length);
231
+ while (commonSegments < maxCommon && fromSegments[commonSegments] === toSegments[commonSegments]) {
232
+ commonSegments++;
233
+ }
234
+ const upSegments = Array(fromSegments.length - commonSegments).fill(
235
+ DOUBLE_DOT
236
+ );
237
+ const downSegments = toSegments.slice(commonSegments);
238
+ const result = [...upSegments, ...downSegments].join(SLASH);
239
+ return result.length > 0 ? result : DOT;
240
+ };
241
+ const dirname = (p) => {
242
+ if (typeof p !== "string" || p.length === 0) return DOT;
243
+ const normalizedPath = normalizeWindowsPath(p);
244
+ const lastSlash = normalizedPath.lastIndexOf(SLASH);
245
+ if (lastSlash === -1) {
246
+ return IS_ABSOLUTE_RE.test(normalizedPath) ? SLASH : DOT;
247
+ }
248
+ if (lastSlash === 0) return SLASH;
249
+ const dir = normalizedPath.slice(0, lastSlash);
250
+ if (DRIVE_LETTER_RE.test(dir) && dir.length === 2) {
251
+ return dir + SLASH;
252
+ }
253
+ return normalize(dir);
254
+ };
255
+ const format = (p) => {
256
+ if (typeof p !== "object" || p === null) {
257
+ throw new TypeError(
258
+ 'Parameter "pathObject" must be an object, not null or other type.'
259
+ );
260
+ }
261
+ const dir = p.dir || p.root || "";
262
+ const base = p.base || `${p.name || ""}${p.ext || ""}`;
263
+ if (!dir) return base;
264
+ if (dir === p.root) return `${dir}${base}`;
265
+ return normalize(`${dir}${SLASH}${base}`);
266
+ };
267
+ const basename = (p, ext) => {
268
+ if (typeof p !== "string") throw new TypeError("Path must be a string.");
269
+ if (ext !== void 0 && typeof ext !== "string")
270
+ throw new TypeError("[basename] `ext` must be a string.");
271
+ const normalizedPath = normalizeWindowsPath(p);
272
+ let end = normalizedPath.length;
273
+ while (end > 0 && normalizedPath[end - 1] === SLASH) {
274
+ end--;
275
+ }
276
+ if (end === 0) return EMPTY;
277
+ let start = normalizedPath.lastIndexOf(SLASH, end - 1);
278
+ start = start === -1 ? 0 : start + 1;
279
+ let filename2 = normalizedPath.slice(start, end);
280
+ if (ext && filename2.endsWith(ext) && filename2 !== ext) {
281
+ filename2 = filename2.slice(0, filename2.length - ext.length);
282
+ }
283
+ return filename2;
284
+ };
285
+ const parse = (p) => {
286
+ if (typeof p !== "string") throw new TypeError("Path must be a string.");
287
+ const normalizedPath = normalizeWindowsPath(p);
288
+ const B = basename(normalizedPath);
289
+ const E = extname(B);
290
+ const N = B.slice(0, B.length - E.length);
291
+ const D = dirname(normalizedPath);
292
+ let R = EMPTY;
293
+ const rootMatch = PATH_ROOT_RE.exec(normalizedPath);
294
+ if (rootMatch) {
295
+ R = rootMatch[0];
296
+ if (DRIVE_LETTER_RE.test(R) && R.length === 2 && normalizedPath.length > 2 && normalizedPath[2] === SLASH) {
297
+ R += SLASH;
298
+ } else if (R === SLASH && D.startsWith("//")) {
299
+ if (UNC_REGEX.exec(D)) {
300
+ const uncParts = D.split(SLASH).slice(0, 3);
301
+ R = uncParts.join(SLASH) || R;
302
+ }
303
+ }
304
+ }
305
+ const resolvedDir = D === DOT && R !== EMPTY && R !== DOT ? R : D;
306
+ return {
307
+ root: R,
308
+ dir: resolvedDir,
309
+ base: B,
310
+ ext: E,
311
+ name: N
312
+ };
313
+ };
314
+ function filename(pathString) {
315
+ const base = basename(pathString);
316
+ if (!base) return void 0;
317
+ const separatorIndex = base.lastIndexOf(DOT);
318
+ return separatorIndex <= 0 ? base : base.slice(0, separatorIndex);
319
+ }
320
+ function normalizeAliases(aliases) {
321
+ if (aliases[normalizedAliasSymbol]) {
322
+ return aliases;
323
+ }
324
+ const sortedAliasesEntries = Object.entries(aliases).map(
325
+ ([key, value]) => [normalizeWindowsPath(key), normalizeWindowsPath(value)]
326
+ ).sort(([a], [b]) => compareAliases(a, b));
327
+ const sortedAliases = Object.fromEntries(sortedAliasesEntries);
328
+ for (const key in sortedAliases) {
329
+ for (const aliasPrefix in sortedAliases) {
330
+ if (aliasPrefix === key || key.startsWith(aliasPrefix + SLASH) || key === aliasPrefix)
331
+ continue;
332
+ const value = sortedAliases[key];
333
+ if (value?.startsWith(aliasPrefix)) {
334
+ const nextChar = value[aliasPrefix.length];
335
+ if (nextChar === void 0 || nextChar === SLASH) {
336
+ sortedAliases[key] = sortedAliases[aliasPrefix] + value.slice(aliasPrefix.length);
337
+ }
338
+ }
339
+ }
340
+ }
341
+ const finalNormalizedAliases = { ...sortedAliases };
342
+ Object.defineProperty(finalNormalizedAliases, normalizedAliasSymbol, {
343
+ value: true,
344
+ enumerable: false
345
+ });
346
+ return finalNormalizedAliases;
347
+ }
348
+ function resolveAlias(path2, aliases) {
349
+ const normalizedPath = normalizeWindowsPath(path2);
350
+ const normalizedAliases = normalizeAliases(aliases);
351
+ for (const [alias, to] of Object.entries(normalizedAliases)) {
352
+ const effectiveAlias = alias.endsWith(SLASH) ? alias : alias + SLASH;
353
+ const effectivePath = normalizedPath.endsWith(SLASH) ? normalizedPath : normalizedPath + SLASH;
354
+ if (effectivePath.startsWith(effectiveAlias)) {
355
+ return join(to, normalizedPath.slice(alias.length));
356
+ }
357
+ if (normalizedPath === alias) {
358
+ return to;
359
+ }
360
+ }
361
+ return normalizedPath;
362
+ }
363
+ function reverseResolveAlias(path2, aliases) {
364
+ const normalizedPath = normalizeWindowsPath(path2);
365
+ const normalizedAliases = normalizeAliases(aliases);
366
+ const matches = [];
367
+ for (const [alias, to] of Object.entries(normalizedAliases)) {
368
+ const effectiveTo = to.endsWith(SLASH) ? to : to + SLASH;
369
+ const effectivePath = normalizedPath.endsWith(SLASH) ? normalizedPath : normalizedPath + SLASH;
370
+ if (effectivePath.startsWith(effectiveTo)) {
371
+ matches.push(join(alias, normalizedPath.slice(to.length)));
372
+ }
373
+ if (normalizedPath === to) {
374
+ matches.push(alias);
375
+ }
376
+ }
377
+ return matches.sort((a, b) => b.length - a.length);
378
+ }
379
+ const findAliasMatch = (importPath, paths) => {
380
+ if (paths[importPath]?.[0]) {
381
+ return {
382
+ key: importPath,
383
+ root: importPath,
384
+ resolvedPath: paths[importPath][0],
385
+ suffix: ""
386
+ };
387
+ }
388
+ for (const aliasKey in paths) {
389
+ if (aliasKey.endsWith("/*")) {
390
+ const aliasRoot = aliasKey.slice(0, -2);
391
+ if (importPath === aliasRoot || importPath.startsWith(`${aliasRoot}/`)) {
392
+ const suffix = importPath === aliasRoot ? "" : importPath.slice(aliasRoot.length + 1);
393
+ const targetPaths = paths[aliasKey];
394
+ if (targetPaths?.[0]) {
395
+ const resolvedPathPattern = targetPaths[0].slice(0, -2);
396
+ return {
397
+ key: aliasKey,
398
+ root: aliasRoot,
399
+ resolvedPath: resolvedPathPattern,
400
+ suffix
401
+ };
402
+ }
403
+ }
404
+ }
405
+ }
406
+ return null;
407
+ };
408
+ const toRelativeImport = (absPath, fromDir) => {
409
+ const rel = normalizeWindowsPath(relative(fromDir, absPath));
410
+ return rel.startsWith(DOT) ? rel : `./${rel}`;
411
+ };
412
+ async function resolveFileWithExtensions(basePath, extensions = ["", ...EXTENSIONS, ".json"]) {
413
+ for (const ext of extensions) {
414
+ try {
415
+ const fullPath = basePath + ext;
416
+ const stat = await fs.stat(fullPath);
417
+ if (stat.isFile()) {
418
+ return fullPath;
419
+ }
420
+ } catch {
421
+ }
422
+ }
423
+ for (const ext of extensions) {
424
+ try {
425
+ const indexPath = join(basePath, `index${ext}`);
426
+ const stat = await fs.stat(indexPath);
427
+ if (stat.isFile()) {
428
+ return indexPath;
429
+ }
430
+ } catch {
431
+ }
432
+ }
433
+ return null;
434
+ }
435
+ function getTargetExtension(relPath, originalExt) {
436
+ const foundExt = extname(relPath);
437
+ if (originalExt) {
438
+ return relPath;
439
+ }
440
+ if (foundExt) {
441
+ return relPath.slice(0, -foundExt.length);
442
+ }
443
+ return relPath;
444
+ }
445
+ async function convertStringAliasRelative({
446
+ importPath,
447
+ importerFile,
448
+ pathPattern,
449
+ targetDir
450
+ }) {
451
+ const paths = { [pathPattern]: ["./*"] };
452
+ const importerDir = dirname(importerFile);
453
+ const match = findAliasMatch(importPath, paths);
454
+ if (!match) return importPath;
455
+ const absPath = resolve(targetDir, match.resolvedPath, match.suffix);
456
+ const resolvedFile = await resolveFileWithExtensions(absPath);
457
+ const relPath = toRelativeImport(resolvedFile || absPath, importerDir);
458
+ const originalExt = extname(importPath);
459
+ return getTargetExtension(relPath, originalExt);
460
+ }
461
+ function replaceAllInString(original, searchValue, replaceValue) {
462
+ let currentPosition = 0;
463
+ let result = "";
464
+ while (currentPosition < original.length) {
465
+ const foundIdx = original.indexOf(searchValue, currentPosition);
466
+ if (foundIdx === -1) {
467
+ result += original.substring(currentPosition);
468
+ break;
469
+ }
470
+ result += original.substring(currentPosition, foundIdx);
471
+ result += replaceValue;
472
+ currentPosition = foundIdx + searchValue.length;
473
+ }
474
+ return result;
475
+ }
476
+ async function processFile(filePath, aliasToReplace, targetDir, pathExtFilter) {
477
+ const content = await fs.readFile(filePath, "utf-8");
478
+ let updated = content;
479
+ const changes = [];
480
+ const matches = Array.from(content.matchAll(IMPORT_REGEX));
481
+ const normalizedAlias = aliasToReplace.endsWith("/*") ? aliasToReplace : `${aliasToReplace}/*`;
482
+ for (const match of matches) {
483
+ const originalQuote = match[1];
484
+ const importPath = match[2];
485
+ const importExt = extname(importPath);
486
+ const shouldProcess = pathExtFilter === "js" && importExt === ".js" || pathExtFilter === "ts" && importExt === ".ts" || pathExtFilter === "none" && importExt === "" || pathExtFilter === "js-ts-none";
487
+ if (!shouldProcess) continue;
488
+ const relPath = await convertStringAliasRelative({
489
+ importPath,
490
+ importerFile: filePath,
491
+ pathPattern: normalizedAlias,
492
+ targetDir
493
+ });
494
+ if (importPath !== relPath) {
495
+ changes.push({ from: importPath, to: relPath });
496
+ const searchString = `${originalQuote}${importPath}${originalQuote}`;
497
+ const replacementString = `${originalQuote}${relPath}${originalQuote}`;
498
+ updated = replaceAllInString(updated, searchString, replacementString);
499
+ }
500
+ }
501
+ if (content !== updated) {
502
+ await fs.writeFile(filePath, updated);
503
+ logInternal(`\u2713 processed: ${filePath}`);
504
+ }
505
+ return changes;
506
+ }
507
+ async function processAllFiles({
508
+ srcDir,
509
+ aliasToReplace,
510
+ extensionsToProcess,
511
+ rootDir,
512
+ pathExtFilter
513
+ }) {
514
+ try {
515
+ const entries = await fs.readdir(srcDir, { withFileTypes: true });
516
+ const results = [];
517
+ await Promise.all(
518
+ entries.map(async (entry) => {
519
+ const fullPath = join(srcDir, entry.name);
520
+ if (entry.isDirectory()) {
521
+ if (entry.name === "node_modules" || entry.name.startsWith("."))
522
+ return;
523
+ const subdirResults = await processAllFiles({
524
+ srcDir: fullPath,
525
+ aliasToReplace,
526
+ extensionsToProcess,
527
+ rootDir,
528
+ pathExtFilter
529
+ });
530
+ results.push(...subdirResults);
531
+ } else if (extensionsToProcess.includes(extname(entry.name))) {
532
+ const changes = await processFile(
533
+ fullPath,
534
+ aliasToReplace,
535
+ rootDir,
536
+ pathExtFilter
537
+ );
538
+ if (changes.length > 0) {
539
+ results.push({ file: fullPath, changes });
540
+ }
541
+ } else {
542
+ logInternal(` - skipping non-matching file: ${entry.name}`);
543
+ }
544
+ })
545
+ );
546
+ return results;
547
+ } catch (error) {
548
+ log(
549
+ `error processing directory ${srcDir}: ${error instanceof Error ? error.message : String(error)}`
550
+ );
551
+ return [];
552
+ }
553
+ }
554
+ async function convertImportsAliasToRelative({
555
+ targetDir,
556
+ aliasToReplace,
557
+ // e.g. @, ~, @/*, ~/*
558
+ pathExtFilter
559
+ }) {
560
+ const normalizedAlias = aliasToReplace.endsWith("/*") ? aliasToReplace : `${aliasToReplace}/*`;
561
+ log(
562
+ `Converting aliased imports starting with '${aliasToReplace}' to relative paths in "${targetDir}"...`
563
+ );
564
+ log(` (Assuming "${normalizedAlias}" resolves relative to "${targetDir}")`);
565
+ logInternal(` (Using extension mode: ${pathExtFilter})`);
566
+ const results = await processAllFiles({
567
+ srcDir: targetDir,
568
+ aliasToReplace: normalizedAlias,
569
+ extensionsToProcess: EXTENSIONS,
570
+ rootDir: targetDir,
571
+ pathExtFilter
572
+ });
573
+ if (results.length > 0) {
574
+ log("\n[convertImportsAliasToRelative] Summary of changes:");
575
+ for (const { file, changes } of results) {
576
+ const displayPath = relative(targetDir, file) || basename(file);
577
+ log(` in ${displayPath}:`);
578
+ for (const { from, to } of changes) {
579
+ log(` - ${from} \u2192 ${to}`);
580
+ }
581
+ }
582
+ } else {
583
+ }
584
+ log("Import path conversion process complete.");
585
+ return results;
586
+ }
587
+ async function convertImportsExt({
588
+ targetDir,
589
+ extFrom,
590
+ extTo
591
+ }) {
592
+ logInternal(
593
+ `Converting import extensions from '${extFrom}' to '${extTo}' in "${targetDir}"...`
594
+ );
595
+ const fromExtStr = extFrom === "none" ? "" : `.${extFrom}`;
596
+ const toExtStr = extTo === "none" ? "" : `.${extTo}`;
597
+ const importRegex = new RegExp(
598
+ `(?:import\\s+(?:[\\s\\S]*?)\\s+from\\s+|import\\s*\\(\\s*)\\s*(['"])([^'"]+${fromExtStr.replace(".", "\\.")})(\\1)`,
599
+ "g"
600
+ );
601
+ try {
602
+ const entries = await fs.readdir(targetDir, { withFileTypes: true });
603
+ const results = [];
604
+ await Promise.all(
605
+ entries.map(async (entry) => {
606
+ const fullPath = join(targetDir, entry.name);
607
+ if (entry.isDirectory()) {
608
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) {
609
+ return;
610
+ }
611
+ const subdirResults = await convertImportsExt({
612
+ targetDir: fullPath,
613
+ extFrom,
614
+ extTo
615
+ });
616
+ results.push(...subdirResults);
617
+ } else if (EXTENSIONS.includes(extname(entry.name))) {
618
+ const content = await fs.readFile(fullPath, "utf-8");
619
+ let updated = content;
620
+ const changes = [];
621
+ const matches = Array.from(content.matchAll(importRegex));
622
+ for (const match of matches) {
623
+ const quote = match[1];
624
+ const importPath = match[2];
625
+ let replacementPath;
626
+ if (extFrom === "none") {
627
+ replacementPath = importPath + toExtStr;
628
+ } else if (extTo === "none") {
629
+ replacementPath = importPath.slice(0, -fromExtStr.length);
630
+ } else {
631
+ replacementPath = importPath.slice(0, -fromExtStr.length) + toExtStr;
632
+ }
633
+ if (importPath === replacementPath) continue;
634
+ changes.push({ from: importPath, to: replacementPath });
635
+ const searchStr = `${quote}${importPath}${quote}`;
636
+ const replaceStr = `${quote}${replacementPath}${quote}`;
637
+ updated = replaceAllInString(updated, searchStr, replaceStr);
638
+ }
639
+ if (content !== updated) {
640
+ await fs.writeFile(fullPath, updated);
641
+ logInternal(`\u2713 processed: ${fullPath}`);
642
+ if (changes.length > 0) {
643
+ results.push({ file: fullPath, changes });
644
+ }
645
+ }
646
+ } else {
647
+ logInternal(` - skipping non-matching file: ${entry.name}`);
648
+ }
649
+ })
650
+ );
651
+ if (results.length > 0) {
652
+ log("\n[convertImportsExt] Summary of changes:");
653
+ for (const { file, changes } of results) {
654
+ const displayPath = relative(targetDir, file) || basename(file);
655
+ log(` in ${displayPath}:`);
656
+ for (const { from, to } of changes) {
657
+ log(` - ${from} \u2192 ${to}`);
658
+ }
659
+ }
660
+ } else {
661
+ }
662
+ logInternal("Extension conversion complete.");
663
+ return results;
664
+ } catch (error) {
665
+ log(
666
+ `error processing directory ${targetDir}: ${error instanceof Error ? error.message : String(error)}`
667
+ );
668
+ return [];
669
+ }
670
+ }
671
+ function stripPathSegments(path2, count = 1, alias = "") {
672
+ if (typeof path2 !== "string" || path2.length === 0) return path2;
673
+ if (count <= 0) return path2;
674
+ logInternal(`[stripPathSegments] Processing path: ${path2}`);
675
+ logInternal(` - count: ${count}, alias: ${alias}`);
676
+ const normalizedPath = normalizeWindowsPath(path2);
677
+ logInternal(` - normalized: ${normalizedPath}`);
678
+ const parsed = parse(normalizedPath);
679
+ logInternal(` - parsed: ${JSON.stringify(parsed)}`);
680
+ let pathSegments = [];
681
+ if (parsed.dir && parsed.dir !== parsed.root) {
682
+ let dirRelativeToRoot = parsed.dir;
683
+ if (parsed.root && parsed.dir.startsWith(parsed.root)) {
684
+ dirRelativeToRoot = parsed.dir.substring(parsed.root.length);
685
+ }
686
+ pathSegments.push(...dirRelativeToRoot.split(SLASH));
687
+ }
688
+ if (parsed.base) {
689
+ pathSegments.push(parsed.base);
690
+ }
691
+ pathSegments = pathSegments.filter(Boolean);
692
+ logInternal(` - initial segments: ${JSON.stringify(pathSegments)}`);
693
+ const leadingPreservedSegments = [];
694
+ if (alias && pathSegments.length > 0 && pathSegments[0].startsWith(alias)) {
695
+ const preserved = pathSegments.shift();
696
+ leadingPreservedSegments.push(preserved);
697
+ logInternal(` - preserved alias segment: ${preserved}`);
698
+ }
699
+ while (pathSegments.length > 0 && (pathSegments[0] === DOT || pathSegments[0] === DOUBLE_DOT)) {
700
+ const preserved = pathSegments.shift();
701
+ leadingPreservedSegments.push(preserved);
702
+ logInternal(` - preserved relative segment: ${preserved}`);
703
+ }
704
+ const numToStrip = Math.min(count, pathSegments.length);
705
+ const remainingBodySegments = pathSegments.slice(numToStrip);
706
+ logInternal(
707
+ ` - stripping ${numToStrip} segments from: ${JSON.stringify(pathSegments)}`
708
+ );
709
+ logInternal(
710
+ ` - remaining body segments: ${JSON.stringify(remainingBodySegments)}`
711
+ );
712
+ const pathRoot = parsed.root;
713
+ const effectiveSegments = [
714
+ ...leadingPreservedSegments,
715
+ ...remainingBodySegments
716
+ ];
717
+ logInternal(` - effective segments: ${JSON.stringify(effectiveSegments)}`);
718
+ let result;
719
+ if (effectiveSegments.length === 0) {
720
+ result = normalize(pathRoot || DOT);
721
+ } else if (pathRoot) {
722
+ result = join(pathRoot, ...effectiveSegments);
723
+ } else {
724
+ result = join(...effectiveSegments);
725
+ }
726
+ logInternal(` - final result: ${result}`);
727
+ return result;
728
+ }
729
+ async function stripPathSegmentsInDirectory({
730
+ targetDir,
731
+ segmentsToStrip,
732
+ alias = "",
733
+ extensionsToProcess = EXTENSIONS
734
+ }) {
735
+ log(`[stripPathSegmentsInDirectory] Processing directory: ${targetDir}`);
736
+ log(` - segmentsToStrip: ${segmentsToStrip}, alias: ${alias}`);
737
+ logInternal(` - extensions: ${JSON.stringify(extensionsToProcess)}`);
738
+ try {
739
+ const entries = await fs.readdir(targetDir, { withFileTypes: true });
740
+ const results = [];
741
+ await Promise.all(
742
+ entries.map(async (entry) => {
743
+ const fullPath = join(targetDir, entry.name);
744
+ if (entry.isDirectory()) {
745
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) {
746
+ logInternal(` - skipping directory: ${entry.name}`);
747
+ return;
748
+ }
749
+ logInternal(` - recursing into directory: ${entry.name}`);
750
+ const subdirResults = await stripPathSegmentsInDirectory({
751
+ targetDir: fullPath,
752
+ segmentsToStrip,
753
+ alias,
754
+ extensionsToProcess
755
+ });
756
+ results.push(...subdirResults);
757
+ } else if (extensionsToProcess.includes(extname(entry.name))) {
758
+ logInternal(` Processing file: ${entry.name}`);
759
+ const content = await fs.readFile(fullPath, "utf-8");
760
+ let updated = content;
761
+ const changes = [];
762
+ const matches = Array.from(content.matchAll(IMPORT_REGEX));
763
+ logInternal(` - found ${matches.length} import statements`);
764
+ for (const match of matches) {
765
+ const originalQuote = match[1];
766
+ const importPath = match[2];
767
+ if (!importPath.includes(SLASH)) {
768
+ logInternal(` - skipping non-path import: ${importPath}`);
769
+ continue;
770
+ }
771
+ logInternal(` Processing import: ${importPath}`);
772
+ const strippedPath = stripPathSegments(
773
+ importPath,
774
+ segmentsToStrip,
775
+ alias
776
+ );
777
+ if (importPath === strippedPath) {
778
+ logInternal(" - no changes needed");
779
+ continue;
780
+ }
781
+ changes.push({ from: importPath, to: strippedPath });
782
+ logInternal(` - transformed: ${importPath} \u2192 ${strippedPath}`);
783
+ const searchStr = `${originalQuote}${importPath}${originalQuote}`;
784
+ const replaceStr = `${originalQuote}${strippedPath}${originalQuote}`;
785
+ updated = replaceAllInString(updated, searchStr, replaceStr);
786
+ }
787
+ if (content !== updated) {
788
+ await fs.writeFile(fullPath, updated);
789
+ logInternal(" \u2713 wrote changes to file");
790
+ if (changes.length > 0) {
791
+ results.push({ file: fullPath, changes });
792
+ }
793
+ } else {
794
+ logInternal(" - no changes made to file");
795
+ }
796
+ } else {
797
+ logInternal(` - skipping non-matching file: ${entry.name}`);
798
+ }
799
+ })
800
+ );
801
+ if (results.length > 0) {
802
+ log("[stripPathSegmentsInDirectory] Summary of changes:");
803
+ for (const { file, changes } of results) {
804
+ const displayPath = relative(targetDir, file) || basename(file);
805
+ log(` in ${displayPath}:`);
806
+ for (const { from, to } of changes) {
807
+ log(` - ${from} \u2192 ${to}`);
808
+ }
809
+ }
810
+ } else {
811
+ logInternal(" No changes were made in any files");
812
+ }
813
+ return results;
814
+ } catch (error) {
815
+ log(
816
+ `error processing directory ${targetDir}: ${error instanceof Error ? error.message : String(error)}`
817
+ );
818
+ return [];
819
+ }
820
+ }
821
+ function attachPathSegments(path2, segments, options = {}) {
822
+ if (typeof path2 !== "string" || path2.length === 0) return path2;
823
+ const {
824
+ position = "after",
825
+ normalize: shouldNormalize = true,
826
+ ensureSlash = true,
827
+ preserveRoot = true,
828
+ preserveAlias
829
+ } = options;
830
+ const segmentsArray = Array.isArray(segments) ? segments : [segments];
831
+ const validSegments = segmentsArray.filter((s) => s.length > 0);
832
+ if (validSegments.length === 0) return path2;
833
+ const basePath = shouldNormalize ? normalizeWindowsPath(path2) : path2;
834
+ let alias = "";
835
+ let pathWithoutAlias = basePath;
836
+ if (preserveAlias && position === "before") {
837
+ const aliasMatch = new RegExp(`^${preserveAlias.replace("*", ".*")}`).exec(
838
+ basePath
839
+ );
840
+ if (aliasMatch) {
841
+ alias = aliasMatch[0];
842
+ pathWithoutAlias = basePath.slice(alias.length);
843
+ }
844
+ }
845
+ const isAbsolute2 = IS_ABSOLUTE_RE.test(pathWithoutAlias);
846
+ const root = preserveRoot && isAbsolute2 ? SLASH : "";
847
+ const pathWithoutRoot = isAbsolute2 ? pathWithoutAlias.slice(1) : pathWithoutAlias;
848
+ const joinedSegments = validSegments.join(SLASH);
849
+ let result;
850
+ if (position === "before") {
851
+ result = ensureSlash ? `${alias}${root}${joinedSegments}${SLASH}${pathWithoutRoot}` : `${alias}${root}${joinedSegments}${pathWithoutRoot}`;
852
+ } else {
853
+ result = ensureSlash ? `${alias}${root}${pathWithoutRoot}${SLASH}${joinedSegments}` : `${alias}${root}${pathWithoutRoot}${joinedSegments}`;
854
+ }
855
+ return shouldNormalize ? normalize(result) : result;
856
+ }
857
+ async function attachPathSegmentsInDirectory({
858
+ targetDir,
859
+ segments,
860
+ options = {},
861
+ extensionsToProcess = EXTENSIONS
862
+ }) {
863
+ try {
864
+ const entries = await fs.readdir(targetDir, { withFileTypes: true });
865
+ const results = [];
866
+ await Promise.all(
867
+ entries.map(async (entry) => {
868
+ const fullPath = join(targetDir, entry.name);
869
+ if (entry.isDirectory()) {
870
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) {
871
+ return;
872
+ }
873
+ const subdirResults = await attachPathSegmentsInDirectory({
874
+ targetDir: fullPath,
875
+ segments,
876
+ options,
877
+ extensionsToProcess
878
+ });
879
+ results.push(...subdirResults);
880
+ } else if (extensionsToProcess.includes(extname(entry.name))) {
881
+ const content = await fs.readFile(fullPath, "utf-8");
882
+ let updated = content;
883
+ const changes = [];
884
+ const matches = Array.from(content.matchAll(IMPORT_REGEX));
885
+ for (const match of matches) {
886
+ const originalQuote = match[1];
887
+ const importPath = match[2];
888
+ if (!importPath.includes(SLASH)) continue;
889
+ const modifiedPath = attachPathSegments(
890
+ importPath,
891
+ segments,
892
+ options
893
+ );
894
+ if (importPath === modifiedPath) continue;
895
+ changes.push({ from: importPath, to: modifiedPath });
896
+ const searchStr = `${originalQuote}${importPath}${originalQuote}`;
897
+ const replaceStr = `${originalQuote}${modifiedPath}${originalQuote}`;
898
+ updated = replaceAllInString(updated, searchStr, replaceStr);
899
+ }
900
+ if (content !== updated) {
901
+ await fs.writeFile(fullPath, updated);
902
+ logInternal(`\u2713 processed: ${fullPath}`);
903
+ if (changes.length > 0) {
904
+ results.push({ file: fullPath, changes });
905
+ }
906
+ }
907
+ } else {
908
+ logInternal(` - skipping non-matching file: ${entry.name}`);
909
+ }
910
+ })
911
+ );
912
+ if (results.length > 0) {
913
+ log("\n[attachPathSegmentsInDirectory] Summary of changes:");
914
+ for (const { file, changes } of results) {
915
+ const displayPath = relative(targetDir, file) || basename(file);
916
+ log(` in ${displayPath}:`);
917
+ for (const { from, to } of changes) {
918
+ log(` - ${from} \u2192 ${to}`);
919
+ }
920
+ }
921
+ }
922
+ return results;
923
+ } catch (error) {
924
+ log(
925
+ `error processing directory ${targetDir}: ${error instanceof Error ? error.message : String(error)}`
926
+ );
927
+ return [];
928
+ }
929
+ }
930
+ const _pathBase = {
3
931
  sep,
4
932
  normalize,
5
933
  join,
6
934
  resolve,
7
- normalizeString,
8
935
  isAbsolute,
9
- toNamespacedPath,
10
- extname,
11
- relative,
12
936
  dirname,
13
- format,
14
- basename,
15
- parse
16
- } from "./pathkit-impl/internal/path.js";
17
- import { normalizeWindowsPath } from "./pathkit-impl/internal/win.js";
18
- import {
19
- normalizeAliases,
20
- resolveAlias,
21
- reverseResolveAlias,
22
- filename
23
- } from "./pathkit-impl/utils.js";
24
- export {
25
937
  basename,
26
- delimiter,
27
- dirname,
28
938
  extname,
29
- filename,
30
939
  format,
31
- isAbsolute,
32
- join,
33
- normalize,
34
- normalizeAliases,
35
- normalizeString,
36
- normalizeWindowsPath,
37
940
  parse,
38
- posix,
39
- relative,
40
- resolve,
41
- resolveAlias,
42
- reverseResolveAlias,
43
- sep,
44
941
  toNamespacedPath,
45
- win32
942
+ relative,
943
+ filename
944
+ };
945
+ const _platforms = {
946
+ posix: { ..._pathBase },
947
+ win32: {
948
+ ..._pathBase,
949
+ sep: BACK_SLASH,
950
+ delimiter: ";",
951
+ isAbsolute: (p) => {
952
+ if (typeof p !== "string") return false;
953
+ return /^[a-zA-Z]:[/\\]/.test(p) || /^[/\\]{2}/.test(p);
954
+ },
955
+ toNamespacedPath: (p) => {
956
+ if (typeof p !== "string" || p.length === 0) return p;
957
+ const resolved = resolve(p);
958
+ if (/^[a-zA-Z]:/.test(resolved)) {
959
+ return `\\\\?\\${resolved.replace(/\//g, BACK_SLASH)}`;
960
+ }
961
+ if (/^[/\\]{2}/.test(resolved)) {
962
+ return `\\\\?\\UNC\\${resolved.substring(2).replace(/\//g, BACK_SLASH)}`;
963
+ }
964
+ return p.replace(/\//g, BACK_SLASH);
965
+ }
966
+ }
967
+ };
968
+ const mix = (platformDefault = "currentSystem") => {
969
+ const actualDefault = platformDefault === "currentSystem" ? globalThis.process?.platform === "win32" ? "win32" : "posix" : platformDefault;
970
+ const defaultPathObject = actualDefault === "win32" ? _platforms.win32 : _platforms.posix;
971
+ return new Proxy(defaultPathObject, {
972
+ get(target, prop) {
973
+ if (prop === "delimiter") return actualDefault === "win32" ? ";" : ":";
974
+ if (prop === "posix") return _platforms.posix;
975
+ if (prop === "win32") return _platforms.win32;
976
+ if (prop in target) {
977
+ return target[prop];
978
+ }
979
+ if (prop in _pathBase) {
980
+ return _pathBase[prop];
981
+ }
982
+ return void 0;
983
+ }
984
+ });
46
985
  };
47
- const pathObj = {
986
+ const path = mix();
987
+ const win32 = _platforms.win32;
988
+ const delimiter = globalThis.process?.platform === "win32" ? ";" : ":";
989
+ export {
990
+ _pathBase as posix,
991
+ win32,
48
992
  basename,
49
993
  delimiter,
50
994
  dirname,
@@ -54,17 +998,23 @@ const pathObj = {
54
998
  isAbsolute,
55
999
  join,
56
1000
  normalize,
57
- normalizeAliases,
58
- normalizeString,
59
- normalizeWindowsPath,
60
1001
  parse,
61
- posix,
62
1002
  relative,
63
1003
  resolve,
64
- resolveAlias,
65
- reverseResolveAlias,
66
1004
  sep,
67
1005
  toNamespacedPath,
68
- win32
1006
+ normalizeAliases,
1007
+ resolveAlias,
1008
+ reverseResolveAlias,
1009
+ normalizeWindowsPath,
1010
+ cleanDirs,
1011
+ copyDir,
1012
+ convertStringAliasRelative,
1013
+ convertImportsAliasToRelative,
1014
+ convertImportsExt,
1015
+ stripPathSegments,
1016
+ stripPathSegmentsInDirectory,
1017
+ attachPathSegments,
1018
+ attachPathSegmentsInDirectory
69
1019
  };
70
- export default pathObj;
1020
+ export default path;