From 2f77c6ebb4a0997251b63cada0979f0eb1c957eb Mon Sep 17 00:00:00 2001 From: Lexus Drumgold Date: Thu, 19 Dec 2024 20:16:38 -0500 Subject: [PATCH] refactor(lib): `toRelativeSpecifier` - check if `url` is inside of `parent` directory Signed-off-by: Lexus Drumgold --- package.json | 2 +- .../__snapshots__/to-relative-specifier.snap | 9 ---- .../__tests__/to-relative-specifier.spec.mts | 31 ++++++++++--- src/lib/to-relative-specifier.mts | 43 +++++++++++++------ 4 files changed, 55 insertions(+), 30 deletions(-) delete mode 100644 src/lib/__snapshots__/to-relative-specifier.snap diff --git a/package.json b/package.json index b8e054c1..4af4e600 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,7 @@ "prepublishOnly": "toggle-scripts -prepack", "release": "bash ./scripts/release.sh", "remark": "remark .", - "test": "cross-env NODE_OPTIONS=\"--conditions mlly --experimental-strip-types --experimental-transform-types\" vitest run", + "test": "yarn clean:build; cross-env NODE_OPTIONS=\"--conditions mlly --experimental-strip-types --experimental-transform-types\" vitest run", "test:cov": "yarn test --coverage", "test:cov:reports": "yarn test:cov --merge-reports --mode=reports", "test:cov:ui": "yarn test:ui --coverage", diff --git a/src/lib/__snapshots__/to-relative-specifier.snap b/src/lib/__snapshots__/to-relative-specifier.snap deleted file mode 100644 index a8877621..00000000 --- a/src/lib/__snapshots__/to-relative-specifier.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`unit:lib/toRelativeSpecifier > should return relative specifier (0) 1`] = `"."`; - -exports[`unit:lib/toRelativeSpecifier > should return relative specifier (1) 1`] = `"./cwd"`; - -exports[`unit:lib/toRelativeSpecifier > should return relative specifier (2) 1`] = `"../to-relative-specifier"`; - -exports[`unit:lib/toRelativeSpecifier > should return relative specifier (3) 1`] = `"."`; diff --git a/src/lib/__tests__/to-relative-specifier.spec.mts b/src/lib/__tests__/to-relative-specifier.spec.mts index 6838fd2b..437a8f34 100644 --- a/src/lib/__tests__/to-relative-specifier.spec.mts +++ b/src/lib/__tests__/to-relative-specifier.spec.mts @@ -4,18 +4,35 @@ */ import testSubject from '#lib/to-relative-specifier' +import type { ModuleId } from '@flex-development/mlly' import pathe from '@flex-development/pathe' describe('unit:lib/toRelativeSpecifier', () => { - it.each>([ + it.each<[...Parameters, (ModuleId)?]>([ + [import.meta.url, import.meta.url], + [ + pathe.pathToFileURL('__fixtures__/conditions.mts'), + pathe.pathToFileURL('src/lib/__tests__/resolver.spec.mts') + ], [ pathe.pathToFileURL('src/lib'), - pathe.pathToFileURL('src/lib/resolve-alias.mts') + pathe.pathToFileURL('src/lib/to-relative-specifier.mts'), + pathe.pathToFileURL('src/lib/') + ], + [ + pathe.pathToFileURL('src/lib/to-relative-specifier.mts'), + pathe.pathToFileURL('src/lib/index.mts') ], - [pathe.pathToFileURL('src/lib/cwd'), pathe.pathToFileURL('src/lib')], - [pathe.pathToFileURL('src/lib/to-relative-specifier'), import.meta.url], - [pathe.pathToFileURL('src/utils'), pathe.pathToFileURL('src/utils')] - ])('should return relative specifier (%#)', (url, parent) => { - expect(testSubject(url, parent)).toMatchSnapshot() + [pathe.pathToFileURL('src/lib/to-relative-specifier.mts'), import.meta.url], + [ + pathe.pathToFileURL('src/lib/to-relative-specifier.mts'), + pathe.pathToFileURL('src/lib/') + ] + ])('should return relative specifier (%#)', (url, parent, expected = url) => { + // Act + const result = testSubject(url, parent) + + // Expect + expect(String(new URL(result, parent))).to.eq(String(expected)) }) }) diff --git a/src/lib/to-relative-specifier.mts b/src/lib/to-relative-specifier.mts index 3adfad91..c80bebe2 100644 --- a/src/lib/to-relative-specifier.mts +++ b/src/lib/to-relative-specifier.mts @@ -3,9 +3,9 @@ * @module mlly/lib/toRelativeSpecifier */ -import toUrl from '#lib/to-url' import type { ModuleId } from '@flex-development/mlly' import pathe from '@flex-development/pathe' +import { ok } from 'devlop' /** * Turn `url` into a *relative specifier*. @@ -26,24 +26,41 @@ import pathe from '@flex-development/pathe' * Relative specifier */ function toRelativeSpecifier(url: ModuleId, parent: ModuleId): string { + parent = pathe.fileURLToPath(parent) + url = pathe.fileURLToPath(url) + + /** + * Directory name of {@linkcode parent} path. + * + * @const {string} dirname + */ + const dirname: string = pathe.dirname(parent) + /** * Relative specifier. * * @var {string} specifier */ - let specifier: string = pathe.relative( - pathe.fileURLToPath(toUrl(parent)), - pathe.fileURLToPath(toUrl(url)) - ) - - if (/(?:\.\.\/){2,}/.test(specifier)) { - specifier = specifier.slice(specifier.indexOf(pathe.sep) + 1) - } else if (specifier.startsWith(pathe.dot.repeat(2))) { - specifier = specifier.slice(1) - } else if (specifier) { - specifier = pathe.dot + pathe.sep + specifier + let specifier: string + + if (url.startsWith(parent) && parent.endsWith(pathe.sep)) { + // url is inside same directory as parent + specifier = pathe.dot + pathe.sep + url.slice(parent.length) + } else if (url === dirname || url.startsWith(dirname + pathe.sep)) { + // url is directory name of parent or inside same directory as parent + specifier = pathe.dot + pathe.sep + url.slice(dirname.length + 1) } else { - specifier = pathe.dot + // url is outside directory of parent + specifier = pathe.relative(parent, url) + ok(specifier.startsWith(pathe.dot), 'expected result to start with "."') + + if (specifier !== pathe.dot && specifier !== pathe.dot.repeat(2)) { + if (/(?:\.\.\/){2,}/.test(specifier)) { + // remove first '../' segment: + // pathe.relative backs out of an extra directory + specifier = specifier.slice(specifier.indexOf(pathe.sep) + 1) + } + } } return specifier