@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.
sponsor âą discord âą npm âą repo
- đč drop in and replace
node:pathandunjs/patheinstantly - â
unjs/patheon steroids â alias resolution, import parsing, and more - đ always
/â posix separators 100% of the time (buhâbye\\) - âïž node.js api compatible â familiar methods, no learning curve
- đ modern & fast â typescript, pure esm, bun & nodeâready
- đ§ predictable & testable â deterministic output across windows / macos / linux
- đ§Œ no dependencies â just better path api + couple of cool utilities = 4kB
# bun âą pnpm âą yarn âą npm
bun add @reliverse/pathkitMigrate:
# soon:
# bun add -D @reliverse/dler
# bun dler migrate --lib path-to-pathkit
# bun dler migrate --lib pathe-to-pathkit| Package | What you get | When to use |
|---|---|---|
pathe |
Path API only (with POSIX everywhere) | You only need a dropâin for node:path |
pathkit |
Everything in pathe + advanced utilities |
You need alias resolution, import transforms, etc. |
Native node:path flips behavior between operating systems, spurring subtle bugs and OS checks.
// With node:path â the same call may yield different separators on each OS
import path from "node:path";
const project = "users/blefnk/project";
const full = path.join("C:\\", project);
console.log(full); // "C:\\users\\blefnk\\project" (Windows) vs ??? (others)import { join } from "@reliverse/pathkit";
const full = join("C:", "users", "blefnk", "project");
console.log(full); // "C:/users/blefnk/project" on **every** OS đ| Pain Point | @reliverse/pathkit Solution |
|---|---|
| Inconsistent separators | â
Always / |
| OSâspecific workâarounds | â One code path |
| Needs TypeScript + ESM | â Builtâin |
| Works in Bun / Deno / Node | â Out of the box |
import { resolve, join, normalize } from "@reliverse/pathkit";
// Mixed slashes & dotâsegments? No problem.
const messy = "src\\..\\./dist///file.js";
console.log(resolve(messy)); // â "dist/file.js"
// Join is predictable everywhere:
console.log(join("users", "blefnk")); // â "users/blefnk"SideâbyâSide Demo:
| Code | Windows Output | macOS / Linux Output |
|---|---|---|
join("a", "b") |
a/b |
a/b |
resolve("..", "x") |
x |
x |
Say goodbye to process.platform conditionals đ.
@reliverse/pathkit extends the core functionality of node:path with powerful utilities for working with imports, aliases, and more.
The getFileImportsExports function provides detailed analysis of ES module imports and exports in your code:
import { getFileImportsExports } from "@reliverse/pathkit";
const code = `
import { ref } from "vue";
import utils from "@/utils";
import type { Config } from "./types";
import * as React from "react";
import { Button as UIButton } from "./components";
export { default as MyComponent } from "./MyComponent";
export type { Props } from "./types";
`;
const analysis = getFileImportsExports(code, {
kind: "all", // "import" | "export" | "all"
pathTypes: ["alias"], // Filter by path types: "alias" | "relative" | "absolute" | "bare" | "module"
limitPerType: 2 // Limit results per type
});The analysis provides rich information about each import/export statement:
interface ImportExportInfo {
statement: string; // Full original statement
type: "static" | "dynamic"; // Import type (static or dynamic import())
kind: "import" | "export"; // Statement kind
source?: string; // Import/export source path
pathType?: "alias" | "relative" | "absolute" | "bare" | "module";
pathTypeSymbol?: string; // Path prefix (e.g., "@/", "~/")
isTypeOnly?: boolean; // Type-only import/export
specifiers?: { // Imported/exported items
type: "named" | "default" | "namespace" | "all";
name: string;
alias?: string;
isType?: boolean;
}[];
start: number; // Position in source
end: number;
importExt?: string; // Extension as written in import/export statement
realFileExt?: string; // Likely actual file extension (e.g., .ts for .js imports)
}Features:
-
âš Comprehensive Syntax Support
- Static imports (
import x from "y") - Dynamic imports (
import("y")) - Named imports/exports (
import { x } from "y") - Default imports/exports (
import x from "y") - Namespace imports (
import * as x from "y") - Re-exports (
export * from "y") - Type imports/exports (
import type { x } from "y")
- Static imports (
-
đ Path Analysis
- Detects path types (alias, relative, absolute, bare, module)
- Extracts path prefixes (e.g.,
@/,~/) - Preserves original path format
- Tracks both import statement extensions and likely real file extensions
- Handles TypeScript/JavaScript extension conversion (e.g.,
.jsâ.ts)
-
đŻ Specifier Details
- Named imports/exports with aliases
- Default imports/exports
- Namespace imports
- Type-only imports/exports
- Mixed type and value imports
-
đ Filtering Options
- Filter by statement kind (import/export)
- Filter by path types
- Limit results per type
- Preserve statement order
-
đĄïž Type Safety
- Full TypeScript support
- Detailed type definitions
- Null-safe operations
Example output:
[
{
statement: 'import { ref } from "vue"',
type: "static",
kind: "import",
source: "vue",
pathType: "bare",
specifiers: [{
type: "named",
name: "ref"
}],
start: 0,
end: 24,
importExt: "",
realFileExt: ""
},
{
statement: 'import type { Config } from "./types.js"',
type: "static",
kind: "import",
source: "./types.js",
pathType: "relative",
isTypeOnly: true,
specifiers: [{
type: "named",
name: "Config",
isType: true
}],
start: 45,
end: 85,
importExt: ".js",
realFileExt: ".ts"
}
]Convert between different path formats:
import { convertImportPaths } from "@reliverse/pathkit";
await convertImportPaths({
baseDir: "./src",
fromType: "relative", // "./components/Button"
toType: "alias", // "@/components/Button"
aliasPrefix: "@/",
generateSourceMap: true
});import { convertImportsExt } from "@reliverse/pathkit";
// Basic usage - convert all relative imports to .ts
await convertImportsExt({
targetDir: "./src",
extFrom: "none",
extTo: "ts"
});
// Convert .js to .ts
await convertImportsExt({
targetDir: "./src",
extFrom: "js",
extTo: "ts"
});
// Remove extensions
await convertImportsExt({
targetDir: "./src",
extFrom: "ts",
extTo: "none"
});
// Handle alias paths (e.g. @/components)
await convertImportsExt({
targetDir: "./src",
extFrom: "none",
extTo: "ts",
alias: "@" // or "@/*"
});The function intelligently handles different import types:
- â
Relative imports (
./file,../file) - â Alias imports (when alias is specified)
- â
Package imports (
lodash,@scope/pkg) - â
Node built-ins (
node:path,node:fs) - â
URLs (
http://,https://) - â Already processed paths
Features:
- đ Recursively processes directories
- đŻ Preserves package imports
- đĄïž Safe for code generation
- đ Detailed change logging
- đš Supports custom aliases
Manipulate path segments in import statements:
import {
stripPathSegments,
stripPathSegmentsInDirectory,
attachPathSegments,
attachPathSegmentsInDirectory
} from "@reliverse/pathkit";
// Strip segments from a path
stripPathSegments("src/components/Button.tsx", 1); // "components/Button.tsx"
// Strip segments from imports in a directory
await stripPathSegmentsInDirectory({
targetDir: "./src",
segmentsToStrip: 1,
alias: "@" // Optional: preserve alias prefix
});
// Attach segments to a path
attachPathSegments("Button.tsx", "components", {
position: "before", // "before" | "after"
normalize: true, // Normalize the path
ensureSlash: true, // Ensure slash between segments
preserveRoot: true, // Preserve root in absolute paths
preserveAlias: "@" // Optional: preserve alias prefix
});
// Attach segments to imports in a directory
await attachPathSegmentsInDirectory({
targetDir: "./src",
segments: "components",
options: {
position: "before",
preserveAlias: "@"
}
});Advanced alias handling and resolution:
import {
normalizeAliases,
resolveAlias,
reverseResolveAlias
} from "@reliverse/pathkit";
const aliases = { "@/": "/src/", "~/": "/home/user/" };
// Normalize alias config
console.log(normalizeAliases(aliases));
// Resolve alias to absolute path
console.log(resolveAlias("@/components", aliases)); // "/src/components"
// Convert absolute path back to alias
console.log(reverseResolveAlias("/src/utils", aliases)); // "@/utils"import {
normalizeAliases,
resolveAlias,
reverseResolveAlias,
findAliasMatch
} from "@reliverse/pathkit";
// Normalize and optimize alias configurations
const aliases = {
"@/": "/src/",
"~/": "/home/user/",
"@/components/": "/src/components/" // Nested alias
};
const normalized = normalizeAliases(aliases);
// Resolve aliased paths
resolveAlias("@/components/Button", aliases); // "/src/components/Button"
// Convert absolute paths back to aliases
reverseResolveAlias("/src/utils", aliases); // ["@/utils"]
// Find matching alias in tsconfig-style paths
const paths = {
"@/*": ["./src/*"],
"~/*": ["./home/*"]
};
findAliasMatch("@/components/Button", paths);Convert between different path formats:
import {
convertStringAliasRelative,
convertImportsAliasToRelative
} from "@reliverse/pathkit";
// Convert a single aliased path to relative
await convertStringAliasRelative({
importPath: "@/components/Button",
importerFile: "src/pages/Home.tsx",
pathPattern: "@/*",
targetDir: "src"
});
// Convert all aliased imports to relative in a directory
await convertImportsAliasToRelative({
targetDir: "./src",
aliasToReplace: "@",
pathExtFilter: "js-ts-none" // "js" | "ts" | "none" | "js-ts-none"
});Handle platform-specific path operations:
import { posix, win32 } from "@reliverse/pathkit";
// Use platform-specific path handling
const path = process.platform === "win32" ? win32 : posix;
// Windows-specific features
win32.toNamespacedPath("C:\\path\\to\\file"); // "\\\\?\\C:\\path\\to\\file"
win32.delimiter; // ";"
// POSIX-specific features
posix.delimiter; // ":"import {
filename, // Strip extension
normalizeQuotes, // Standardize quote style
matchesGlob // Test glob patterns
} from "@reliverse/pathkit";
console.log(filename("/path/component.vue")); // "component"
console.log(normalizeQuotes("import 'pkg'")); // 'import "pkg"'
console.log(matchesGlob("file.ts", "**/*.ts")); // trueimport {
filename,
normalizeWindowsPath,
replaceAllInString
} from "@reliverse/pathkit";
// Get filename without extension
filename("/path/to/file.ts"); // "file"
// Normalize Windows paths
normalizeWindowsPath("C:\\path\\to\\file"); // "C:/path/to/file"
// Replace strings while tracking position
replaceAllInString("import x from 'y'", "'y'", "'z'");The library supports the following file extensions by default:
const EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];type PathExtFilter = "js" | "ts" | "none" | "js-ts-none";
type ImportExtType = "js" | "ts" | "none";- đ ïž CLI tools
- đ Crossâplatform dev environments
- đ Bundlers, linters, compilers
- đïž Framework & library authors
- đ Scripts / test runners
- âŠanywhere fileâpaths roam!
git clone https://github.com/reliverse/pathkit.git
cd pathkit
bun install
bun devBug reports & PRs are warmly welcomeâcome on in!
@reliverse/remptsâ Terminal Prompts Engine
- â Star the repo if this helped you.
- đ Sponsor @blefnk to keep the lights on.
- đŹ Chat with us on Discord.