diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1061a4..6347ebf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,8 @@ jobs: - run: corepack enable - uses: actions/setup-node@v4 with: - node-version: 16 - cache: "pnpm" + node-version: "18" + cache: pnpm - run: pnpm install - run: pnpm lint - run: pnpm build diff --git a/README.md b/README.md index 0737c9e..956e991 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Pathe exports some extra utilities that do not exist in standard Node.js [path m In order to use them, you can import from `pathe/utils` subpath: ```js -import { filename, normalizeAliases, resolveAlias } from 'pathe/utils' +import { filename, normalizeAliases, resolveAlias, reverseResolveAlias } from 'pathe/utils' ``` ## License diff --git a/src/utils.ts b/src/utils.ts index 887ca5f..999623c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -57,6 +57,28 @@ export function resolveAlias(path: string, aliases: Record) { return _path; } +export function reverseResolveAlias( + path: string, + aliases: Record, +) { + const _path = normalizeWindowsPath(path); + aliases = normalizeAliases(aliases); + + for (const [to, alias] of Object.entries(aliases).reverse()) { + if (!_path.startsWith(alias)) { + continue; + } + + // Strip trailing slash from alias for check + const _alias = hasTrailingSlash(alias) ? alias.slice(0, -1) : alias; + + if (hasTrailingSlash(_path[_alias.length])) { + return join(to, _path.slice(alias.length)); + } + } + return _path; +} + const FILENAME_RE = /(^|[/\\])([^/\\]+?)(?=(\.[^.]+)?$)/; export function filename(path: string) { diff --git a/test/utils.spec.ts b/test/utils.spec.ts index 71a9fd9..5f1f545 100644 --- a/test/utils.spec.ts +++ b/test/utils.spec.ts @@ -1,6 +1,11 @@ import { describe, expect, it } from "vitest"; -import { normalizeAliases, filename, resolveAlias } from "../src/utils"; +import { + normalizeAliases, + filename, + resolveAlias, + reverseResolveAlias, +} from "../src/utils"; describe("alias", () => { const _aliases = { @@ -56,6 +61,33 @@ describe("alias", () => { expect(resolveAlias("~win/foo/bar", aliases)).toBe("C:/src/foo/bar"); }); }); + + describe("reverseResolveAlias", () => { + for (const [to, from] of Object.entries(aliases)) { + it(from, () => { + expect(reverseResolveAlias(from, aliases)).toBe(to); + }); + } + it("respects path separators", () => { + const aliases = { + "~": "/root", + "~assets": "/root/some/assets", + }; + expect( + reverseResolveAlias("/root/some/assets/smth.jpg", aliases), + ).toMatchInlineSnapshot('"~assets/smth.jpg"'); + }); + it("unchanged", () => { + expect(reverseResolveAlias("foo/bar.js", aliases)).toBe("foo/bar.js"); + expect(reverseResolveAlias("./bar.js", aliases)).toBe("./bar.js"); + }); + it("respect ending with /", () => { + expect(reverseResolveAlias("/src/foo/bar", aliases)).toBe("~/foo/bar"); + expect(reverseResolveAlias("C:/src/foo/bar", aliases)).toBe( + "~win/foo/bar", + ); + }); + }); }); describe("filename", () => {