From 65f1e2cc2f02343ccc2fa8da91177982532ee960 Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Tue, 25 Aug 2026 08:24:34 +0800
Subject: [PATCH 1/6] fix(license): resolve wrong version and missing license
text
---
.../__snapshots__/license.spec.ts.snap | 12 +++++++++
.../build/esm/index.js | 4 +++
.../build/esm/package.json | 4 +++
.../license/dep-license-type-marker/license | 3 +++
.../dep-license-type-marker/package.json | 9 +++++++
.../plugins/fixtures/license/index.html | 3 ++-
.../plugins/fixtures/license/package.json | 1 +
packages/vite/src/node/plugins/license.ts | 27 ++++++++++++++++---
pnpm-lock.yaml | 12 +++++++++
9 files changed, 71 insertions(+), 4 deletions(-)
create mode 100644 packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js
create mode 100644 packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/package.json
create mode 100644 packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/license
create mode 100644 packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/package.json
diff --git a/packages/vite/src/node/__tests__/plugins/__snapshots__/license.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/__snapshots__/license.spec.ts.snap
index d93b6c9515daa3..1546143e444a75 100644
--- a/packages/vite/src/node/__tests__/plugins/__snapshots__/license.spec.ts.snap
+++ b/packages/vite/src/node/__tests__/plugins/__snapshots__/license.spec.ts.snap
@@ -14,6 +14,12 @@ exports[`json 1`] = `
"identifier": "MIT",
"text": "MIT License\\n\\nCopyright (c) ..."
},
+ {
+ "name": "@vitejs/test-dep-license-type-marker",
+ "version": "1.0.0",
+ "identifier": "MIT",
+ "text": "MIT License\\n\\nCopyright (c) ..."
+ },
{
"name": "@vitejs/test-dep-nested-license-isc",
"version": "0.0.0",
@@ -40,6 +46,12 @@ MIT License
Copyright (c) ...
+## @vitejs/test-dep-license-type-marker - 1.0.0 (MIT)
+
+MIT License
+
+Copyright (c) ...
+
## @vitejs/test-dep-nested-license-isc - 0.0.0 (ISC)
Copyright (c) ...
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js
new file mode 100644
index 00000000000000..b33537e2d6da91
--- /dev/null
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js
@@ -0,0 +1,4 @@
+// Avoid to be inlined completely: https://github.com/rolldown/rolldown/issues/8100
+console.log()
+
+export default 'ok'
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/package.json
new file mode 100644
index 00000000000000..8b9091d41e41b5
--- /dev/null
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/package.json
@@ -0,0 +1,4 @@
+{
+ "name": "@vitejs/test-dep-license-type-marker",
+ "type": "module"
+}
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/license b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/license
new file mode 100644
index 00000000000000..1732da241e5252
--- /dev/null
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/license
@@ -0,0 +1,3 @@
+MIT License
+
+Copyright (c) ...
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/package.json
new file mode 100644
index 00000000000000..5db5607a1f9c68
--- /dev/null
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@vitejs/test-dep-license-type-marker",
+ "private": true,
+ "version": "1.0.0",
+ "license": "MIT",
+ "exports": {
+ ".": "./build/esm/index.js"
+ }
+}
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/index.html b/packages/vite/src/node/__tests__/plugins/fixtures/license/index.html
index b0825ecb300d5b..cf1dd5f1e85b1e 100644
--- a/packages/vite/src/node/__tests__/plugins/fixtures/license/index.html
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/index.html
@@ -1,5 +1,6 @@
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/package.json
index 4e06638e94f0cc..1f2a8eaa73484f 100644
--- a/packages/vite/src/node/__tests__/plugins/fixtures/license/package.json
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/package.json
@@ -5,6 +5,7 @@
"type": "module",
"dependencies": {
"@vitejs/test-dep-license-mit": "file:./dep-license-mit",
+ "@vitejs/test-dep-license-type-marker": "file:./dep-license-type-marker",
"@vitejs/test-dep-licence-cc0": "file:./dep-licence-cc0"
}
}
diff --git a/packages/vite/src/node/plugins/license.ts b/packages/vite/src/node/plugins/license.ts
index 2eb389ef94d455..354e2b91f4f4fe 100644
--- a/packages/vite/src/node/plugins/license.ts
+++ b/packages/vite/src/node/plugins/license.ts
@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
-import type { PackageCache } from '../packages'
-import { findNearestMainPackageData } from '../packages'
+import type { PackageCache, PackageData } from '../packages'
+import { findNearestPackageData } from '../packages'
import type { Plugin } from '../plugin'
import { isInNodeModules, sortObjectKeys } from '../utils'
@@ -41,6 +41,21 @@ const licenseConfigDefaults = Object.freeze({
// https://github.com/npm/npm-packlist/blob/53b2a4f42b7fef0f63e8f26a3ea4692e23a58fed/lib/index.js#L284-L286
const licenseFiles = [/^license/i, /^licence/i, /^copying/i]
+// Unlike `findNearestMainPackageData`, a manifest is only accepted when it has both a `name` and a `version`. Dual ESM/CJS packages ship type-marker
+// package.json files (e.g. `build/esm/package.json`) that carry a `name` but no `version` or license information, so the walk must continue up to the real package root to produce a complete license entry.
+function findLicensePackageData(
+ basedir: string,
+ packageCache: PackageCache,
+): PackageData | null {
+ let pkgData = findNearestPackageData(basedir, packageCache)
+ while (pkgData && !(pkgData.data.name && pkgData.data.version)) {
+ const parentDir = path.dirname(pkgData.dir)
+ if (parentDir === pkgData.dir) return null
+ pkgData = findNearestPackageData(parentDir, packageCache)
+ }
+ return pkgData
+}
+
export function licensePlugin(): Plugin {
return {
name: 'vite:license',
@@ -62,7 +77,7 @@ export function licensePlugin(): Plugin {
if (moduleId.startsWith('\0') || !isInNodeModules(moduleId)) continue
// Find the dependency package.json
- const pkgData = findNearestMainPackageData(
+ const pkgData = findLicensePackageData(
path.dirname(moduleId),
packageCache,
)
@@ -82,6 +97,12 @@ export function licensePlugin(): Plugin {
if (licenseFile) {
entry.text = fs.readFileSync(licenseFile, 'utf-8').trim()
}
+ if (!entry.identifier && !entry.text) {
+ this.warn(
+ `Could not find any license information for "${key}". ` +
+ `Its entry in the license file will be incomplete.`,
+ )
+ }
licenses[key] = entry
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f7891f1b8b62fb..0261a2a8ec693c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -506,6 +506,9 @@ importers:
'@vitejs/test-dep-license-mit':
specifier: file:./dep-license-mit
version: file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit
+ '@vitejs/test-dep-license-type-marker':
+ specifier: file:./dep-license-type-marker
+ version: file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker
packages/vite/src/node/__tests__/plugins/fixtures/license/dep-licence-cc0: {}
@@ -515,6 +518,10 @@ importers:
specifier: file:../dep-nested-license-isc
version: file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc
+ packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker: {}
+
+ packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm: {}
+
packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc: {}
packages/vite/src/node/server/__tests__/fixtures/deno/nested: {}
@@ -4396,6 +4403,9 @@ packages:
'@vitejs/test-dep-license-mit@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit':
resolution: {directory: packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-mit, type: directory}
+ '@vitejs/test-dep-license-type-marker@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker':
+ resolution: {directory: packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker, type: directory}
+
'@vitejs/test-dep-lodash-es@file:playground/optimize-deps/dep-lodash-es':
resolution: {directory: playground/optimize-deps/dep-lodash-es, type: directory}
@@ -10299,6 +10309,8 @@ snapshots:
dependencies:
'@vitejs/test-dep-nested-license-isc': file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc
+ '@vitejs/test-dep-license-type-marker@file:packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker': {}
+
'@vitejs/test-dep-lodash-es@file:playground/optimize-deps/dep-lodash-es': {}
'@vitejs/test-dep-lodash.clonedeep@file:playground/optimize-deps/dep-lodash-clonedeep': {}
From b8668fe7db98264f07dff2a443a340157190dc3f Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Tue, 25 Aug 2026 08:26:13 +0800
Subject: [PATCH 2/6] chore: reset warn
---
packages/vite/src/node/plugins/license.ts | 6 ------
1 file changed, 6 deletions(-)
diff --git a/packages/vite/src/node/plugins/license.ts b/packages/vite/src/node/plugins/license.ts
index 354e2b91f4f4fe..aacf4894d63772 100644
--- a/packages/vite/src/node/plugins/license.ts
+++ b/packages/vite/src/node/plugins/license.ts
@@ -97,12 +97,6 @@ export function licensePlugin(): Plugin {
if (licenseFile) {
entry.text = fs.readFileSync(licenseFile, 'utf-8').trim()
}
- if (!entry.identifier && !entry.text) {
- this.warn(
- `Could not find any license information for "${key}". ` +
- `Its entry in the license file will be incomplete.`,
- )
- }
licenses[key] = entry
}
}
From a9bc3dd5997bce3ec708522428887a7fdd2d020f Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Tue, 25 Aug 2026 22:35:30 +0800
Subject: [PATCH 3/6] fix: update
---
.../build/devtools/index.js | 4 ++
.../build/devtools/package.json | 6 +++
.../build/esm/index.js | 1 +
packages/vite/src/node/packages.ts | 38 ++++++++++++++-----
packages/vite/src/node/plugins/license.ts | 21 ++--------
5 files changed, 43 insertions(+), 27 deletions(-)
create mode 100644 packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/index.js
create mode 100644 packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/package.json
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/index.js b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/index.js
new file mode 100644
index 00000000000000..e11c75b1f19d50
--- /dev/null
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/index.js
@@ -0,0 +1,4 @@
+// Avoid to be inlined completely: https://github.com/rolldown/rolldown/issues/8100
+console.log()
+
+export default 'devtools'
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/package.json b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/package.json
new file mode 100644
index 00000000000000..2bbae143ba4199
--- /dev/null
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "@vitejs/test-dep-license-type-marker-devtools",
+ "version": "1.0.0",
+ "private": true,
+ "main": "index.js"
+}
diff --git a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js
index b33537e2d6da91..053d82cc7498eb 100644
--- a/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js
+++ b/packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm/index.js
@@ -1,4 +1,5 @@
// Avoid to be inlined completely: https://github.com/rolldown/rolldown/issues/8100
console.log()
+export { default as devtools } from '../devtools/index.js'
export default 'ok'
diff --git a/packages/vite/src/node/packages.ts b/packages/vite/src/node/packages.ts
index 2021af272c77ab..457aea0a07b544 100644
--- a/packages/vite/src/node/packages.ts
+++ b/packages/vite/src/node/packages.ts
@@ -158,20 +158,40 @@ export function findNearestPackageData(
return null
}
-// Finds the nearest package.json with a `name` field
+function isNodeModulesPackageRoot(pkgDir: string): boolean {
+ const parent = path.dirname(pkgDir)
+ if (path.basename(parent) === 'node_modules') {
+ return !path.basename(pkgDir).startsWith('@')
+ }
+ // scoped package root: `node_modules/@scope/pkg`
+ return (
+ path.basename(parent).startsWith('@') &&
+ path.basename(path.dirname(parent)) === 'node_modules'
+ )
+}
+
+// Finds the nearest package.json with a `name` field. For paths inside
+// `node_modules`, the manifest at the package root is returned instead, which
+// may be further up than the nearest manifest.
export function findNearestMainPackageData(
basedir: string,
packageCache?: PackageCache,
): PackageData | null {
const nearestPackage = findNearestPackageData(basedir, packageCache)
- return (
- nearestPackage &&
- (nearestPackage.data.name
- ? nearestPackage
- : findNearestMainPackageData(
- path.dirname(nearestPackage.dir),
- packageCache,
- ))
+ if (!nearestPackage) return null
+ if (
+ isInNodeModules(nearestPackage.dir) &&
+ !isNodeModulesPackageRoot(nearestPackage.dir)
+ ) {
+ return findNearestMainPackageData(
+ path.dirname(nearestPackage.dir),
+ packageCache,
+ )
+ }
+ if (nearestPackage.data.name) return nearestPackage
+ return findNearestMainPackageData(
+ path.dirname(nearestPackage.dir),
+ packageCache,
)
}
diff --git a/packages/vite/src/node/plugins/license.ts b/packages/vite/src/node/plugins/license.ts
index aacf4894d63772..2eb389ef94d455 100644
--- a/packages/vite/src/node/plugins/license.ts
+++ b/packages/vite/src/node/plugins/license.ts
@@ -1,7 +1,7 @@
import fs from 'node:fs'
import path from 'node:path'
-import type { PackageCache, PackageData } from '../packages'
-import { findNearestPackageData } from '../packages'
+import type { PackageCache } from '../packages'
+import { findNearestMainPackageData } from '../packages'
import type { Plugin } from '../plugin'
import { isInNodeModules, sortObjectKeys } from '../utils'
@@ -41,21 +41,6 @@ const licenseConfigDefaults = Object.freeze({
// https://github.com/npm/npm-packlist/blob/53b2a4f42b7fef0f63e8f26a3ea4692e23a58fed/lib/index.js#L284-L286
const licenseFiles = [/^license/i, /^licence/i, /^copying/i]
-// Unlike `findNearestMainPackageData`, a manifest is only accepted when it has both a `name` and a `version`. Dual ESM/CJS packages ship type-marker
-// package.json files (e.g. `build/esm/package.json`) that carry a `name` but no `version` or license information, so the walk must continue up to the real package root to produce a complete license entry.
-function findLicensePackageData(
- basedir: string,
- packageCache: PackageCache,
-): PackageData | null {
- let pkgData = findNearestPackageData(basedir, packageCache)
- while (pkgData && !(pkgData.data.name && pkgData.data.version)) {
- const parentDir = path.dirname(pkgData.dir)
- if (parentDir === pkgData.dir) return null
- pkgData = findNearestPackageData(parentDir, packageCache)
- }
- return pkgData
-}
-
export function licensePlugin(): Plugin {
return {
name: 'vite:license',
@@ -77,7 +62,7 @@ export function licensePlugin(): Plugin {
if (moduleId.startsWith('\0') || !isInNodeModules(moduleId)) continue
// Find the dependency package.json
- const pkgData = findLicensePackageData(
+ const pkgData = findNearestMainPackageData(
path.dirname(moduleId),
packageCache,
)
From fcb7821aab62129132faf14f1d3a808d0f7911cd Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Thu, 27 Aug 2026 09:12:21 +0800
Subject: [PATCH 4/6] chore: update
---
pnpm-lock.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 0261a2a8ec693c..c1797c1bef9a3c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -520,6 +520,8 @@ importers:
packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker: {}
+ packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/devtools: {}
+
packages/vite/src/node/__tests__/plugins/fixtures/license/dep-license-type-marker/build/esm: {}
packages/vite/src/node/__tests__/plugins/fixtures/license/dep-nested-license-isc: {}
From 11bb6f271b726edb985a1fd098a9be47a64a3095 Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Thu, 27 Aug 2026 17:58:53 +0800
Subject: [PATCH 5/6] chore: add test
---
.../vite/src/node/__tests__/packages.spec.ts | 86 +++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100644 packages/vite/src/node/__tests__/packages.spec.ts
diff --git a/packages/vite/src/node/__tests__/packages.spec.ts b/packages/vite/src/node/__tests__/packages.spec.ts
new file mode 100644
index 00000000000000..1e7fa55561c791
--- /dev/null
+++ b/packages/vite/src/node/__tests__/packages.spec.ts
@@ -0,0 +1,86 @@
+import fs from 'node:fs'
+import os from 'node:os'
+import path from 'node:path'
+import { afterEach, expect, test } from 'vitest'
+import { findNearestMainPackageData } from '../packages'
+
+let tempDir: string | undefined
+
+afterEach(() => {
+ if (tempDir) fs.rmSync(tempDir, { recursive: true, force: true })
+ tempDir = undefined
+})
+
+function createFixtures(files: Record): string {
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vite-packages-'))
+ for (const [file, content] of Object.entries(files)) {
+ const target = path.join(tempDir, file)
+ fs.mkdirSync(path.dirname(target), { recursive: true })
+ fs.writeFileSync(
+ target,
+ typeof content === 'string' ? content : JSON.stringify(content),
+ )
+ }
+ return tempDir
+}
+
+const projectManifest = { name: 'project' }
+
+// paths after realpath resolution under pnpm:
+// `/node_modules/.pnpm/dep@1.0.0/node_modules/dep/...`
+test('resolves the package root for the pnpm store layout', () => {
+ const root = createFixtures({
+ 'package.json': projectManifest,
+ 'node_modules/.pnpm/dep@1.0.0/node_modules/dep/package.json': {
+ name: 'dep',
+ version: '1.0.0',
+ license: 'MIT',
+ },
+ // nested type-marker manifest with a `name` but no `version`
+ 'node_modules/.pnpm/dep@1.0.0/node_modules/dep/build/esm/package.json': {
+ name: 'dep',
+ type: 'module',
+ },
+ })
+ const pkg = findNearestMainPackageData(
+ path.join(root, 'node_modules/.pnpm/dep@1.0.0/node_modules/dep/build/esm'),
+ )
+ expect(pkg?.data).toMatchObject({ name: 'dep', version: '1.0.0' })
+})
+
+// packages hoisted by pnpm to `node_modules/.pnpm/node_modules/`
+test('resolves the package root for packages hoisted by pnpm', () => {
+ const root = createFixtures({
+ 'package.json': projectManifest,
+ 'node_modules/.pnpm/node_modules/hoisted/package.json': {
+ name: 'hoisted',
+ version: '1.0.0',
+ },
+ 'node_modules/.pnpm/node_modules/hoisted/build/esm/package.json': {
+ name: 'hoisted',
+ type: 'module',
+ },
+ })
+ const pkg = findNearestMainPackageData(
+ path.join(root, 'node_modules/.pnpm/node_modules/hoisted/build/esm'),
+ )
+ expect(pkg?.data).toMatchObject({ name: 'hoisted', version: '1.0.0' })
+})
+
+test('resolves the package root for scoped packages', () => {
+ const root = createFixtures({
+ 'package.json': projectManifest,
+ 'node_modules/@scope/dep/package.json': {
+ name: '@scope/dep',
+ version: '2.0.0',
+ },
+ 'node_modules/@scope/dep/dist/esm/package.json': {
+ name: '@scope/dep',
+ type: 'module',
+ },
+ })
+ const pkg = findNearestMainPackageData(
+ path.join(root, 'node_modules/@scope/dep/dist/esm'),
+ )
+ expect(pkg?.data).toMatchObject({ name: '@scope/dep', version: '2.0.0' })
+})
From 51d9e0cd639464c02ea5fa324984f80948f40923 Mon Sep 17 00:00:00 2001
From: btea <2356281422@qq.com>
Date: Thu, 27 Aug 2026 21:26:53 +0800
Subject: [PATCH 6/6] test: add yarn test
---
.../vite/src/node/__tests__/packages.spec.ts | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/packages/vite/src/node/__tests__/packages.spec.ts b/packages/vite/src/node/__tests__/packages.spec.ts
index 1e7fa55561c791..159c7fa4110252 100644
--- a/packages/vite/src/node/__tests__/packages.spec.ts
+++ b/packages/vite/src/node/__tests__/packages.spec.ts
@@ -84,3 +84,29 @@ test('resolves the package root for scoped packages', () => {
)
expect(pkg?.data).toMatchObject({ name: '@scope/dep', version: '2.0.0' })
})
+
+// under Yarn PnP, packages are hosted inside zip archives at
+// `.../cache/-npm--.zip/node_modules//...` (the cache
+// may live outside the project, e.g. in `~/.yarn/berry/cache`). The path
+// contains a synthesized `node_modules/` segment, so the layout-based
+// resolution covers PnP without any PnP-specific handling
+test('resolves the package root for the Yarn PnP zip layout', () => {
+ const root = createFixtures({
+ 'package.json': projectManifest,
+ 'cache/engine.io-client-npm-6.6.6-fd14f4b531-10c0.zip/node_modules/engine.io-client/package.json':
+ { name: 'engine.io-client', version: '6.6.6', license: 'MIT' },
+ // nested type-marker manifest with a `name` but no `version`
+ 'cache/engine.io-client-npm-6.6.6-fd14f4b531-10c0.zip/node_modules/engine.io-client/build/esm/package.json':
+ { name: 'engine.io-client', type: 'module' },
+ })
+ const pkg = findNearestMainPackageData(
+ path.join(
+ root,
+ 'cache/engine.io-client-npm-6.6.6-fd14f4b531-10c0.zip/node_modules/engine.io-client/build/esm',
+ ),
+ )
+ expect(pkg?.data).toMatchObject({
+ name: 'engine.io-client',
+ version: '6.6.6',
+ })
+})