From b19e56c2e54c035518165470c10480201cefa997 Mon Sep 17 00:00:00 2001
From: Ruy Adorno <ruyadorno@hotmail.com>
Date: Wed, 16 Jun 2021 15:52:57 -0400
Subject: [PATCH] fix(ls): respect prod config for workspaces

`npm ls --prod` is currently not omitting devDependencies for configured
workspaces, this changes it by properly checking for the tweaked
`currentDepth` value instead of root check that was in place.

Fixes: https://github.com/npm/cli/issues/3382

PR-URL: https://github.com/npm/cli/pull/3429
Credit: @ruyadorno
Close: #3429
Reviewed-by: @wraithgar
---
 lib/ls.js                             |  8 +++++---
 tap-snapshots/test/lib/ls.js.test.cjs | 17 +++++++++++++++++
 test/lib/ls.js                        | 21 +++++++++++++++++++++
 3 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/lib/ls.js b/lib/ls.js
index b425bd620b38e..f146928a96b41 100644
--- a/lib/ls.js
+++ b/lib/ls.js
@@ -141,6 +141,7 @@ class LS extends ArboristWorkspaceCmd {
           : [...(node.target || node).edgesOut.values()]
             .filter(filterBySelectedWorkspaces)
             .filter(filterByEdgesTypes({
+              currentDepth,
               dev,
               development,
               link,
@@ -387,6 +388,7 @@ const getJsonOutputItem = (node, { global, long }) => {
 }
 
 const filterByEdgesTypes = ({
+  currentDepth,
   dev,
   development,
   link,
@@ -398,11 +400,11 @@ const filterByEdgesTypes = ({
 }) => {
   // filter deps by type, allows for: `npm ls --dev`, `npm ls --prod`,
   // `npm ls --link`, `npm ls --only=dev`, etc
-  const filterDev = node === tree &&
+  const filterDev = currentDepth === 0 &&
     (dev || development || /^dev(elopment)?$/.test(only))
-  const filterProd = node === tree &&
+  const filterProd = currentDepth === 0 &&
     (prod || production || /^prod(uction)?$/.test(only))
-  const filterLink = node === tree && link
+  const filterLink = currentDepth === 0 && link
 
   return (edge) =>
     (filterDev ? edge.dev : true) &&
diff --git a/tap-snapshots/test/lib/ls.js.test.cjs b/tap-snapshots/test/lib/ls.js.test.cjs
index 2ed0b4b001376..3d56d1f432731 100644
--- a/tap-snapshots/test/lib/ls.js.test.cjs
+++ b/tap-snapshots/test/lib/ls.js.test.cjs
@@ -496,6 +496,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac
 exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should filter using workspace config 1`] = `
 workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
 \`-- a@1.0.0 -> ./a
+  +-- baz@1.0.0
   +-- c@1.0.0
   \`-- d@1.0.0 -> ./d
     \`-- foo@1.1.1
@@ -506,6 +507,21 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac
 exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list --all workspaces properly 1`] = `
 workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
 +-- a@1.0.0 -> ./a
+| +-- baz@1.0.0
+| +-- c@1.0.0
+| \`-- d@1.0.0 deduped -> ./d
++-- b@1.0.0 -> ./b
++-- d@1.0.0 -> ./d
+| \`-- foo@1.1.1
+|   \`-- bar@1.0.0
++-- e@1.0.0 -> ./group/e
+\`-- f@1.0.0 -> ./group/f
+
+`
+
+exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list only prod deps of workspaces 1`] = `
+workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
++-- a@1.0.0 -> ./a
 | +-- c@1.0.0
 | \`-- d@1.0.0 deduped -> ./d
 +-- b@1.0.0 -> ./b
@@ -520,6 +536,7 @@ workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspac
 exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list workspaces properly with default configs 1`] = `
 workspaces-tree@1.0.0 {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
 +-- a@1.0.0 -> ./a
+| +-- baz@1.0.0
 | +-- c@1.0.0
 | \`-- d@1.0.0 deduped -> ./d
 +-- b@1.0.0 -> ./b
diff --git a/test/lib/ls.js b/test/lib/ls.js
index 582416f4aa2d2..64ece6bd8a3fd 100644
--- a/test/lib/ls.js
+++ b/test/lib/ls.js
@@ -1449,6 +1449,9 @@ t.test('ls', (t) => {
         bar: {
           'package.json': JSON.stringify({ name: 'bar', version: '1.0.0' }),
         },
+        baz: {
+          'package.json': JSON.stringify({ name: 'baz', version: '1.0.0' }),
+        },
       },
       a: {
         'package.json': JSON.stringify({
@@ -1458,6 +1461,9 @@ t.test('ls', (t) => {
             c: '^1.0.0',
             d: '^1.0.0',
           },
+          devDependencies: {
+            baz: '^1.0.0',
+          },
         }),
       },
       b: {
@@ -1520,6 +1526,21 @@ t.test('ls', (t) => {
       })
     })
 
+    // --production
+    await new Promise((res, rej) => {
+      config.production = true
+      ls.exec([], (err) => {
+        if (err)
+          rej(err)
+
+        t.matchSnapshot(redactCwd(result),
+          'should list only prod deps of workspaces')
+
+        config.production = false
+        res()
+      })
+    })
+
     // filter out a single workspace using args
     await new Promise((res, rej) => {
       ls.exec(['d'], (err) => {