Skip to content

Commit 0d0dafd

Browse files
committed
fix(arborist): handle directories named yarn.lock
1 parent dc43591 commit 0d0dafd

2 files changed

Lines changed: 62 additions & 1 deletion

File tree

workspaces/arborist/lib/shrinkwrap.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,9 @@ class Shrinkwrap {
412412
get loadFiles () {
413413
return Promise.all(
414414
this.#filenameSet.map(file => file && readFile(file, 'utf8').then(d => d, er => {
415+
const optionalYarnLock = basename(file) === 'yarn.lock' && er.code === 'EISDIR'
415416
/* istanbul ignore else - can't test without breaking module itself */
416-
if (er.code === 'ENOENT') {
417+
if (er.code === 'ENOENT' || optionalYarnLock) {
417418
return ''
418419
} else {
419420
throw er

workspaces/arborist/test/shrinkwrap.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,66 @@ t.test('ignore yarn lock file parse errors', async t => {
732732
t.equal(s.yarnLock.entries.size, 0, 'did not get any entries out of it')
733733
})
734734

735+
t.test('ignore a yarn.lock directory', async t => {
736+
const packageLock = {
737+
name: 'yarn-lock-directory',
738+
version: '1.0.0',
739+
lockfileVersion: 3,
740+
requires: true,
741+
packages: {
742+
'': {
743+
name: 'yarn-lock-directory',
744+
version: '1.0.0',
745+
},
746+
},
747+
}
748+
const path = t.testdir({
749+
'package-lock.json': JSON.stringify(packageLock),
750+
'yarn.lock': {},
751+
})
752+
const s = await Shrinkwrap.load({ path })
753+
754+
t.equal(
755+
s.loadingError,
756+
null,
757+
'does not treat an optional yarn.lock directory as a load error'
758+
)
759+
t.equal(s.filename, resolve(path, 'package-lock.json'), 'selects package-lock.json for saving')
760+
t.equal(s.loadedFromDisk, true, 'loads the existing package-lock')
761+
t.match(s.get(''), { name: packageLock.name }, 'preserves the existing package-lock data')
762+
763+
await s.save()
764+
t.equal(
765+
fs.statSync(resolve(path, 'yarn.lock')).isDirectory(),
766+
true,
767+
'leaves yarn.lock directory intact'
768+
)
769+
t.strictSame(
770+
JSON.parse(fs.readFileSync(s.filename, 'utf8')),
771+
packageLock,
772+
'saves the existing package-lock'
773+
)
774+
})
775+
776+
t.test('save with a yarn.lock directory and no package-lock', async t => {
777+
const path = t.testdir({ 'yarn.lock': {} })
778+
const s = await Shrinkwrap.load({ path })
779+
780+
await s.save()
781+
t.equal(s.filename, resolve(path, 'package-lock.json'), 'selects package-lock.json for saving')
782+
t.equal(fs.statSync(s.filename).isFile(), true, 'creates package-lock.json')
783+
t.strictSame(JSON.parse(fs.readFileSync(s.filename, 'utf8')), {
784+
lockfileVersion: 3,
785+
requires: true,
786+
packages: {},
787+
}, 'writes a valid package-lock')
788+
t.equal(
789+
fs.statSync(resolve(path, 'yarn.lock')).isDirectory(),
790+
true,
791+
'leaves yarn.lock directory intact'
792+
)
793+
})
794+
735795
t.test('load a resolution from yarn.lock if we do not have our own', async t => {
736796
const path = t.testdir({
737797
'yarn.lock': `

0 commit comments

Comments
 (0)