@@ -313,3 +313,150 @@ describe('pnpm-lock-v9 catalogs support tests', () => {
313313 ) ;
314314 } ) ;
315315} ) ;
316+
317+ describe ( 'pnpm workspaces with exclude option' , ( ) => {
318+ describe . each ( [ 'pnpm-lock-v5' , 'pnpm-lock-v6' , 'pnpm-lock-v9' ] ) (
319+ '%s' ,
320+ ( lockFileVersionPath ) => {
321+ it ( 'excludes single directory' , async ( ) => {
322+ const fixtureName = 'workspace-cyclic' ;
323+ const result = await parsePnpmWorkspace (
324+ __dirname ,
325+ join ( __dirname , `./fixtures/${ lockFileVersionPath } /${ fixtureName } ` ) ,
326+ {
327+ includeDevDeps : false ,
328+ includeOptionalDeps : true ,
329+ pruneWithinTopLevelDeps : true ,
330+ strictOutOfSync : false ,
331+ exclude : 'backend' ,
332+ } ,
333+ ) ;
334+
335+ expect ( result ) . toHaveLength ( 2 ) ;
336+
337+ const targetFiles = result . map ( ( r ) => r . targetFile . replace ( / \\ / g, '/' ) ) ;
338+ expect ( targetFiles ) . toContain (
339+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /package.json` ,
340+ ) ;
341+ expect ( targetFiles ) . toContain (
342+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /shared/react/package.json` ,
343+ ) ;
344+ expect ( targetFiles ) . not . toContain (
345+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /shared/backend/package.json` ,
346+ ) ;
347+ } ) ;
348+
349+ it ( 'excludes multiple directories' , async ( ) => {
350+ const fixtureName = 'workspace-cyclic' ;
351+ const result = await parsePnpmWorkspace (
352+ __dirname ,
353+ join ( __dirname , `./fixtures/${ lockFileVersionPath } /${ fixtureName } ` ) ,
354+ {
355+ includeDevDeps : false ,
356+ includeOptionalDeps : true ,
357+ pruneWithinTopLevelDeps : true ,
358+ strictOutOfSync : false ,
359+ exclude : 'backend,react' ,
360+ } ,
361+ ) ;
362+
363+ expect ( result ) . toHaveLength ( 1 ) ;
364+
365+ const targetFiles = result . map ( ( r ) => r . targetFile . replace ( / \\ / g, '/' ) ) ;
366+ expect ( targetFiles ) . toContain (
367+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /package.json` ,
368+ ) ;
369+ expect ( targetFiles ) . not . toContain (
370+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /shared/backend/package.json` ,
371+ ) ;
372+ expect ( targetFiles ) . not . toContain (
373+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /shared/react/package.json` ,
374+ ) ;
375+ } ) ;
376+
377+ it ( 'matches any path segment' , async ( ) => {
378+ const fixtureName = 'workspace-cyclic' ;
379+ const result = await parsePnpmWorkspace (
380+ __dirname ,
381+ join ( __dirname , `./fixtures/${ lockFileVersionPath } /${ fixtureName } ` ) ,
382+ {
383+ includeDevDeps : false ,
384+ includeOptionalDeps : true ,
385+ pruneWithinTopLevelDeps : true ,
386+ strictOutOfSync : false ,
387+ exclude : 'shared' ,
388+ } ,
389+ ) ;
390+
391+ expect ( result ) . toHaveLength ( 1 ) ;
392+
393+ const targetFiles = result . map ( ( r ) => r . targetFile . replace ( / \\ / g, '/' ) ) ;
394+ expect ( targetFiles ) . toContain (
395+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /package.json` ,
396+ ) ;
397+ expect ( targetFiles ) . not . toContain (
398+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /shared/backend/package.json` ,
399+ ) ;
400+ expect ( targetFiles ) . not . toContain (
401+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /shared/react/package.json` ,
402+ ) ;
403+ } ) ;
404+
405+ it ( 'handles spaces in comma-separated list' , async ( ) => {
406+ const fixtureName = 'workspace-cyclic' ;
407+ const result = await parsePnpmWorkspace (
408+ __dirname ,
409+ join ( __dirname , `./fixtures/${ lockFileVersionPath } /${ fixtureName } ` ) ,
410+ {
411+ includeDevDeps : false ,
412+ includeOptionalDeps : true ,
413+ pruneWithinTopLevelDeps : true ,
414+ strictOutOfSync : false ,
415+ exclude : ' backend , react ' ,
416+ } ,
417+ ) ;
418+
419+ expect ( result ) . toHaveLength ( 1 ) ;
420+
421+ const targetFiles = result . map ( ( r ) => r . targetFile . replace ( / \\ / g, '/' ) ) ;
422+ expect ( targetFiles ) . toContain (
423+ `fixtures/${ lockFileVersionPath } /${ fixtureName } /package.json` ,
424+ ) ;
425+ } ) ;
426+
427+ it ( 'works normally when exclude is undefined' , async ( ) => {
428+ const fixtureName = 'workspace-cyclic' ;
429+ const result = await parsePnpmWorkspace (
430+ __dirname ,
431+ join ( __dirname , `./fixtures/${ lockFileVersionPath } /${ fixtureName } ` ) ,
432+ {
433+ includeDevDeps : false ,
434+ includeOptionalDeps : true ,
435+ pruneWithinTopLevelDeps : true ,
436+ strictOutOfSync : false ,
437+ exclude : undefined ,
438+ } ,
439+ ) ;
440+
441+ expect ( result ) . toHaveLength ( 3 ) ;
442+ } ) ;
443+
444+ it ( 'works normally when exclude is empty string' , async ( ) => {
445+ const fixtureName = 'workspace-cyclic' ;
446+ const result = await parsePnpmWorkspace (
447+ __dirname ,
448+ join ( __dirname , `./fixtures/${ lockFileVersionPath } /${ fixtureName } ` ) ,
449+ {
450+ includeDevDeps : false ,
451+ includeOptionalDeps : true ,
452+ pruneWithinTopLevelDeps : true ,
453+ strictOutOfSync : false ,
454+ exclude : '' ,
455+ } ,
456+ ) ;
457+
458+ expect ( result ) . toHaveLength ( 3 ) ;
459+ } ) ;
460+ } ,
461+ ) ;
462+ } ) ;
0 commit comments