diff --git a/packages/nx/src/utils/find-matching-projects.spec.ts b/packages/nx/src/utils/find-matching-projects.spec.ts index 72c2b57bfe7a8a..23cef77330f0d0 100644 --- a/packages/nx/src/utils/find-matching-projects.spec.ts +++ b/packages/nx/src/utils/find-matching-projects.spec.ts @@ -78,7 +78,7 @@ describe('findMatchingProjects', () => { 'c', 'nested', ]); - expect(findMatchingProjects(['!*', 'a'], projectGraph)).toEqual([]); + expect(findMatchingProjects(['a', '!*'], projectGraph)).toEqual([]); }); it('should expand generic glob patterns', () => { @@ -124,10 +124,14 @@ describe('findMatchingProjects', () => { }); it('should support negation "!" for tags', () => { - expect(findMatchingProjects(['*', '!tag:api'], projectGraph)).toEqual([ - 'b', - 'nested', - ]); + // Picks everything, except things tagged API, unless those also + // have the tag theme2 in which case we still want them. + const matches = findMatchingProjects( + ['*', '!tag:api', 'tag:theme2'], + projectGraph + ); + expect(matches).toEqual(expect.arrayContaining(['a', 'b', 'nested'])); + expect(matches.length).toEqual(3); }); it('should expand generic glob patterns for tags', () => { diff --git a/packages/nx/src/utils/find-matching-projects.ts b/packages/nx/src/utils/find-matching-projects.ts index 9f2c85c23b7da4..e6e3103dda0887 100644 --- a/packages/nx/src/utils/find-matching-projects.ts +++ b/packages/nx/src/utils/find-matching-projects.ts @@ -37,8 +37,7 @@ export function findMatchingProjects( const projectNames = Object.keys(projects); - const selectedProjects: Set = new Set(); - const excludedProjects: Set = new Set(); + const matchedProjects: Set = new Set(); for (const stringPattern of patterns) { if (!stringPattern.length) { @@ -52,9 +51,9 @@ export function findMatchingProjects( if (pattern.value === '*') { for (const projectName of projectNames) { if (pattern.exclude) { - excludedProjects.add(projectName); + matchedProjects.delete(projectName); } else { - selectedProjects.add(projectName); + matchedProjects.add(projectName); } } continue; @@ -66,8 +65,7 @@ export function findMatchingProjects( projectNames, projects, pattern, - excludedProjects, - selectedProjects + matchedProjects ); continue; } @@ -76,8 +74,7 @@ export function findMatchingProjects( projectNames, projects, pattern, - excludedProjects, - selectedProjects + matchedProjects ); continue; } @@ -86,8 +83,7 @@ export function findMatchingProjects( projectNames, projects, pattern, - excludedProjects, - selectedProjects + matchedProjects ); continue; } @@ -97,15 +93,14 @@ export function findMatchingProjects( // The size of the selected and excluded projects set, before we // start updating it with this pattern. If the size changes, we // know we found a match and can skip the other types. - const originalSize = selectedProjects.size + excludedProjects.size; + const originalSize = matchedProjects.size; addMatchingProjectsByName( projectNames, projects, pattern, - excludedProjects, - selectedProjects + matchedProjects ); - if (selectedProjects.size + excludedProjects.size > originalSize) { + if (matchedProjects.size !== originalSize) { // There was some match by name, don't check other types continue; } @@ -113,10 +108,9 @@ export function findMatchingProjects( projectNames, projects, pattern, - excludedProjects, - selectedProjects + matchedProjects ); - if (selectedProjects.size + excludedProjects.size > originalSize) { + if (matchedProjects.size !== originalSize) { // There was some match by directory, don't check other types // Note - this doesn't do anything currently, but preps for future // types @@ -126,24 +120,23 @@ export function findMatchingProjects( } } - for (const project of excludedProjects) { - selectedProjects.delete(project); - } - - return Array.from(selectedProjects); + return Array.from(matchedProjects); } function addMatchingProjectsByDirectory( projectNames: string[], projects: Record, pattern: ProjectPattern, - excludedProjects: Set, - selectedProjects: Set + matchedProjects: Set ) { for (const projectName of projectNames) { const root = projects[projectName].data.root; if (getMatchingStringsWithCache(pattern.value, [root]).length > 0) { - (pattern.exclude ? excludedProjects : selectedProjects).add(projectName); + if (pattern.exclude) { + matchedProjects.delete(projectName); + } else { + matchedProjects.add(projectName); + } } } } @@ -152,11 +145,14 @@ function addMatchingProjectsByName( projectNames: string[], projects: Record, pattern: ProjectPattern, - excludedProjects: Set, - selectedProjects: Set + matchedProjects: Set ) { if (projects[pattern.value]) { - (pattern.exclude ? excludedProjects : selectedProjects).add(pattern.value); + if (pattern.exclude) { + matchedProjects.delete(pattern.value); + } else { + matchedProjects.add(pattern.value); + } return; } @@ -170,9 +166,9 @@ function addMatchingProjectsByName( ); for (const projectName of matchedProjectNames) { if (pattern.exclude) { - excludedProjects.add(projectName); + matchedProjects.delete(projectName); } else { - selectedProjects.add(projectName); + matchedProjects.add(projectName); } } } @@ -181,14 +177,18 @@ function addMatchingProjectsByTag( projectNames: string[], projects: Record, pattern: ProjectPattern, - excludedProjects: Set, - selectedProjects: Set + matchedProjects: Set ) { for (const projectName of projectNames) { const tags = projects[projectName].data.tags || []; if (tags.includes(pattern.value)) { - (pattern.exclude ? excludedProjects : selectedProjects).add(projectName); + console.log('Processed', pattern, projectName); + if (pattern.exclude) { + matchedProjects.delete(projectName); + } else { + matchedProjects.add(projectName); + } continue; } @@ -197,7 +197,11 @@ function addMatchingProjectsByTag( } if (getMatchingStringsWithCache(pattern.value, tags).length) { - (pattern.exclude ? excludedProjects : selectedProjects).add(projectName); + if (pattern.exclude) { + matchedProjects.delete(projectName); + } else { + matchedProjects.add(projectName); + } } } }