Skip to content

Commit ca0bf18

Browse files
authoredMar 10, 2022
fix: evaluate all patterns before throwing EDUPLICATEWORKSPACE (#32)
1 parent e4e0262 commit ca0bf18

File tree

3 files changed

+186
-18
lines changed

3 files changed

+186
-18
lines changed
 

‎lib/index.js

+41-17
Original file line numberDiff line numberDiff line change
@@ -117,28 +117,52 @@ async function mapWorkspaces (opts = {}) {
117117

118118
const name = getPackageName(pkg, packagePathname)
119119

120+
let seenPackagePathnames = seen.get(name)
121+
if (!seenPackagePathnames) {
122+
seenPackagePathnames = new Set()
123+
seen.set(name, seenPackagePathnames)
124+
}
120125
if (item.negate) {
121-
results.delete(packagePathname, name)
126+
seenPackagePathnames.delete(packagePathname)
122127
} else {
123-
if (seen.has(name) && seen.get(name) !== packagePathname) {
124-
throw getError({
125-
Type: Error,
126-
message: [
127-
'must not have multiple workspaces with the same name',
128-
`package '${name}' has conflicts in the following paths:`,
129-
' ' + seen.get(name),
130-
' ' + packagePathname,
131-
].join('\n'),
132-
code: 'EDUPLICATEWORKSPACE',
133-
})
134-
}
135-
136-
seen.set(name, packagePathname)
137-
results.set(packagePathname, name)
128+
seenPackagePathnames.add(packagePathname)
138129
}
139130
}
140131
}
141-
return reverseResultMap(results)
132+
133+
const errorMessageArray = ['must not have multiple workspaces with the same name']
134+
for (const [packageName, seenPackagePathnames] of seen) {
135+
if (seenPackagePathnames.size === 0) {
136+
continue
137+
}
138+
if (seenPackagePathnames.size > 1) {
139+
addDuplicateErrorMessages(errorMessageArray, packageName, seenPackagePathnames)
140+
} else {
141+
results.set(packageName, seenPackagePathnames.values().next().value)
142+
}
143+
}
144+
145+
if (errorMessageArray.length > 1) {
146+
throw getError({
147+
Type: Error,
148+
message: errorMessageArray.join('\n'),
149+
code: 'EDUPLICATEWORKSPACE',
150+
})
151+
}
152+
153+
return results
154+
}
155+
156+
function addDuplicateErrorMessages (messageArray, packageName, packagePathnames) {
157+
messageArray.push(
158+
`package '${packageName}' has conflicts in the following paths:`
159+
)
160+
161+
for (const packagePathname of packagePathnames) {
162+
messageArray.push(
163+
' ' + packagePathname
164+
)
165+
}
142166
}
143167

144168
mapWorkspaces.virtual = function (opts = {}) {

‎tap-snapshots/test/test.js.test.cjs

+29
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ Map {
4141
}
4242
`
4343

44+
exports[`test/test.js TAP match duplicates then exclude one > should include the non-excluded item on returned Map 1`] = `
45+
Map {
46+
"a" => "{CWD}/test/tap-testdir-test-match-duplicates-then-exclude-one/packages/a",
47+
}
48+
`
49+
50+
exports[`test/test.js TAP matched then negated then match again > should include item on returned Map 1`] = `
51+
Map {
52+
"a" => "{CWD}/test/tap-testdir-test-matched-then-negated-then-match-again/packages/b/a",
53+
}
54+
`
55+
56+
exports[`test/test.js TAP matched then negated then match again with wildcards > should exclude item on returned Map 1`] = `
57+
Map {}
58+
`
59+
4460
exports[`test/test.js TAP missing pkg info > should return an empty map 1`] = `
4561
Array [
4662
Map {},
@@ -49,6 +65,19 @@ Array [
4965
]
5066
`
5167

68+
exports[`test/test.js TAP multiple duplicated workspaces config > should throw an error listing all duplicates 1`] = `
69+
Error: must not have multiple workspaces with the same name
70+
package 'a' has conflicts in the following paths:
71+
{CWD}/test/tap-testdir-test-multiple-duplicated-workspaces-config/packages/a
72+
{CWD}/test/tap-testdir-test-multiple-duplicated-workspaces-config/packages/b
73+
{CWD}/test/tap-testdir-test-multiple-duplicated-workspaces-config/packages/c
74+
package 'b' has conflicts in the following paths:
75+
{CWD}/test/tap-testdir-test-multiple-duplicated-workspaces-config/packages/d
76+
{CWD}/test/tap-testdir-test-multiple-duplicated-workspaces-config/packages/e {
77+
"code": "EDUPLICATEWORKSPACE",
78+
}
79+
`
80+
5281
exports[`test/test.js TAP multiple negate patterns > should not include any negated pattern 1`] = `
5382
Map {}
5483
`

‎test/test.js

+116-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ tap.cleanSnapshot = str => {
77
const cleanPath = path => path
88
.replace(/\\+/g, '/') // normalize slashes
99
.replace(/"\w:/g, '"') // gets rid of drive letter in snapshot
10-
.replace(/^\w:/g, '') // gets rid of drive letter in cwd/paths
10+
.replace(/^(\s*)\w:/gm, '$1') // gets rid of drive letter in cwd/paths
1111
const cwd = cleanPath(process.cwd())
1212
const pathname = cleanPath(str)
1313
return pathname.split(cwd).join('{CWD}')
@@ -229,6 +229,42 @@ test('duplicated workspaces glob pattern', t => {
229229
)
230230
})
231231

232+
test('multiple duplicated workspaces config', t => {
233+
const cwd = t.testdir({
234+
packages: {
235+
a: {
236+
'package.json': '{ "name": "a" }',
237+
},
238+
b: {
239+
'package.json': '{ "name": "a" }',
240+
},
241+
c: {
242+
'package.json': '{ "name": "a" }',
243+
},
244+
d: {
245+
'package.json': '{ "name": "b" }',
246+
},
247+
e: {
248+
'package.json': '{ "name": "b" }',
249+
},
250+
},
251+
})
252+
253+
return t.resolveMatchSnapshot(
254+
mapWorkspaces({
255+
cwd,
256+
pkg: {
257+
workspaces: {
258+
packages: [
259+
'packages/*',
260+
],
261+
},
262+
},
263+
}).catch(error => Promise.resolve(error)),
264+
'should throw an error listing all duplicates'
265+
)
266+
})
267+
232268
test('empty packages declaration', t => {
233269
const cwd = t.testdir({
234270
packages: {
@@ -793,3 +829,82 @@ test('backslashes are normalized', t => {
793829
'matches with backslashes'
794830
)
795831
})
832+
833+
test('matched then negated then match again with wildcards', t => {
834+
const cwd = t.testdir({
835+
packages: {
836+
b: {
837+
a: {
838+
'package.json': '{ "name": "a" }',
839+
},
840+
},
841+
},
842+
})
843+
844+
return t.resolveMatchSnapshot(
845+
mapWorkspaces({
846+
cwd,
847+
pkg: {
848+
workspaces: [
849+
'packages/**',
850+
'!packages/b/**',
851+
],
852+
},
853+
}),
854+
'should exclude item on returned Map'
855+
)
856+
})
857+
858+
test('matched then negated then match again', t => {
859+
const cwd = t.testdir({
860+
packages: {
861+
b: {
862+
a: {
863+
'package.json': '{ "name": "a" }',
864+
},
865+
},
866+
},
867+
})
868+
869+
return t.resolveMatchSnapshot(
870+
mapWorkspaces({
871+
cwd,
872+
pkg: {
873+
workspaces: [
874+
'packages/**',
875+
'!packages/b/**',
876+
'packages/b/a',
877+
],
878+
},
879+
}),
880+
'should include item on returned Map'
881+
)
882+
})
883+
884+
test('match duplicates then exclude one', t => {
885+
const cwd = t.testdir({
886+
packages: {
887+
a: {
888+
'package.json': '{ "name": "a" }',
889+
},
890+
b: {
891+
a: {
892+
'package.json': '{ "name": "a" }',
893+
},
894+
},
895+
},
896+
})
897+
898+
return t.resolveMatchSnapshot(
899+
mapWorkspaces({
900+
cwd,
901+
pkg: {
902+
workspaces: [
903+
'packages/**',
904+
'!packages/b/**',
905+
],
906+
},
907+
}),
908+
'should include the non-excluded item on returned Map'
909+
)
910+
})

0 commit comments

Comments
 (0)
Please sign in to comment.