diff --git a/.changeset/brave-ants-double.md b/.changeset/brave-ants-double.md new file mode 100644 index 0000000000..bb8465eef8 --- /dev/null +++ b/.changeset/brave-ants-double.md @@ -0,0 +1,5 @@ +--- +"dependency-path": major +--- + +Add a unique prefix to any directory name inside the virtual store that has non-lowercase characters. This is important to avoid conflicts in case insensitive filesystems. diff --git a/packages/dependency-path/src/index.ts b/packages/dependency-path/src/index.ts index b18c1e2026..892f6604c4 100644 --- a/packages/dependency-path/src/index.ts +++ b/packages/dependency-path/src/index.ts @@ -132,7 +132,7 @@ export function parse (dependencyPath: string) { export function depPathToFilename (depPath: string, lockfileDir: string) { const filename = depPathToFilenameUnescaped(depPath, lockfileDir).replace(/\//g, '+') - if (filename.length > 120) { + if (filename.length > 120 || filename !== filename.toLowerCase() && !filename.startsWith('local+')) { return `${filename.substring(0, 50)}_${crypto.createHash('md5').update(filename).digest('hex')}` } return filename diff --git a/packages/dependency-path/test/index.ts b/packages/dependency-path/test/index.ts index 7aac57faab..d5b9e975f4 100644 --- a/packages/dependency-path/test/index.ts +++ b/packages/dependency-path/test/index.ts @@ -128,4 +128,5 @@ test('depPathToFilename()', () => { expect(filename).not.toContain(':') expect(depPathToFilename('abcd/'.repeat(200), process.cwd())).toBe('abcd+abcd+abcd+abcd+abcd+abcd+abcd+abcd+abcd+abcd+_27524303f1ddd808db67f175ff83606e') + expect(depPathToFilename('/JSONSteam/1.0.0', process.cwd())).toBe('JSONSteam@1.0.0_4b2567ab922fbdf01171f59fab8f6fef') }) diff --git a/packages/supi/test/install/misc.ts b/packages/supi/test/install/misc.ts index cf37352675..fc911da4ec 100644 --- a/packages/supi/test/install/misc.ts +++ b/packages/supi/test/install/misc.ts @@ -1261,7 +1261,32 @@ test('installing dependencies with the same name in different case', async () => }, rootDir: path.resolve('project-1'), }, - ], await testDefaults({ fastUnpack: false, hoistPattern: '*' })) + ], await testDefaults({ fastUnpack: false })) // if it did not fail, it is fine -}) \ No newline at end of file +}) + +test('two dependencies have the same version and name. The only difference is the casing in the name', async () => { + prepareEmpty() + + await mutateModules([ + { + buildIndex: 0, + mutation: 'install', + manifest: { + dependencies: { + a: 'npm:JSONStream@1.0.3', + b: 'npm:jsonstream@1.0.3', + }, + }, + rootDir: process.cwd(), + }, + ], await testDefaults({ + fastUnpack: false, + registries: { + default: 'https://registry.npmjs.org/', + }, + })) + + expect((await fs.readdir(path.resolve('node_modules/.pnpm'))).length).toBe(5) +})