@@ -1722,3 +1722,120 @@ t.test('setting lockfileVersion from the file contents', async t => {
17221722 }
17231723 } )
17241724} )
1725+
1726+ t . test ( 'removes deleted extraneous workspaces from lockfile' , async t => {
1727+ // Simulate a workspace that was removed from disk but still in lockfile
1728+ const path = t . testdir ( {
1729+ 'package.json' : JSON . stringify ( {
1730+ name : 'root' ,
1731+ version : '1.0.0' ,
1732+ workspaces : [ 'packages/*' ] ,
1733+ } ) ,
1734+ 'package-lock.json' : JSON . stringify ( {
1735+ name : 'root' ,
1736+ version : '1.0.0' ,
1737+ lockfileVersion : 3 ,
1738+ requires : true ,
1739+ packages : {
1740+ '' : {
1741+ name : 'root' ,
1742+ version : '1.0.0' ,
1743+ workspaces : [ 'packages/*' ] ,
1744+ } ,
1745+ 'packages/a' : {
1746+ name : 'a' ,
1747+ version : '1.0.0' ,
1748+ } ,
1749+ 'packages/deleted-ws' : {
1750+ name : 'deleted-ws' ,
1751+ version : '1.0.0' ,
1752+ } ,
1753+ } ,
1754+ } ) ,
1755+ packages : {
1756+ a : {
1757+ 'package.json' : JSON . stringify ( {
1758+ name : 'a' ,
1759+ version : '1.0.0' ,
1760+ } ) ,
1761+ } ,
1762+ // Note: 'deleted-ws' folder does NOT exist on disk
1763+ } ,
1764+ } )
1765+
1766+ const arb = new Arborist ( { path } )
1767+ const tree = await arb . loadActual ( )
1768+ await calcDepFlags ( tree )
1769+
1770+ // The deleted workspace should be marked extraneous
1771+ const deletedWs = tree . children . get ( 'packages/deleted-ws' )
1772+ t . notOk ( deletedWs , 'deleted workspace should not be in tree children' )
1773+
1774+ // Now commit the lockfile
1775+ const lockData = tree . meta . commit ( )
1776+
1777+ // The deleted workspace should be removed from lockfile packages
1778+ t . notOk ( lockData . packages [ 'packages/deleted-ws' ] ,
1779+ 'deleted extraneous workspace should be removed from lockfile' )
1780+ // But the existing workspace should remain
1781+ t . ok ( lockData . packages [ 'packages/a' ] ,
1782+ 'existing workspace should remain in lockfile' )
1783+ } )
1784+
1785+ t . test ( 'keeps extraneous workspaces that exist on disk' , async t => {
1786+ // Simulate a workspace that exists on disk but is extraneous (e.g., not matched by the workspaces glob pattern)
1787+ const path = t . testdir ( {
1788+ 'package.json' : JSON . stringify ( {
1789+ name : 'root' ,
1790+ version : '1.0.0' ,
1791+ workspaces : [ 'packages/a' ] , // Only 'a' is in workspaces
1792+ } ) ,
1793+ 'package-lock.json' : JSON . stringify ( {
1794+ name : 'root' ,
1795+ version : '1.0.0' ,
1796+ lockfileVersion : 3 ,
1797+ requires : true ,
1798+ packages : {
1799+ '' : {
1800+ name : 'root' ,
1801+ version : '1.0.0' ,
1802+ workspaces : [ 'packages/a' , 'packages/b' ] ,
1803+ } ,
1804+ 'packages/a' : {
1805+ name : 'a' ,
1806+ version : '1.0.0' ,
1807+ } ,
1808+ 'packages/b' : {
1809+ name : 'b' ,
1810+ version : '1.0.0' ,
1811+ } ,
1812+ } ,
1813+ } ) ,
1814+ packages : {
1815+ a : {
1816+ 'package.json' : JSON . stringify ( {
1817+ name : 'a' ,
1818+ version : '1.0.0' ,
1819+ } ) ,
1820+ } ,
1821+ b : {
1822+ // This workspace exists on disk but is extraneous (not in workspaces config)
1823+ 'package.json' : JSON . stringify ( {
1824+ name : 'b' ,
1825+ version : '1.0.0' ,
1826+ } ) ,
1827+ } ,
1828+ } ,
1829+ } )
1830+
1831+ const arb = new Arborist ( { path } )
1832+ const tree = await arb . loadActual ( )
1833+ await calcDepFlags ( tree )
1834+
1835+ // Now commit the lockfile
1836+ const lockData = tree . meta . commit ( )
1837+
1838+ // Both workspaces should remain since 'b' exists on disk
1839+ t . ok ( lockData . packages [ 'packages/a' ] ,
1840+ 'configured workspace should remain in lockfile' )
1841+ } )
0 commit comments