Skip to content

Commit 7d0671b

Browse files
committed
ls: show relative paths from root, not absolute
Change the output in `npm ls` for symlink dependencies (including workspaces) to show the relative path from the project root, rather than the absolute path of the link target. This makes the output much less noisy and more ergonomic when many workspaces and link dependencies are in use, especially when paths are long. It is arguable that this output might be slightly misleading, since the _actual_ workspace symlink from `${root}/node_modules/b` to `${root}/packages/b` has a link value of `../packages/b`, not just `packages/b`. (Or on Windows, always the full absolute path, because junctions.) Thus, `npm ls b` will not show the same output as `ls -l node_modules/b`. However, `npm ls` shows the logical tree, not the physical tree, so presenting the user with a path that they can use and interpret is more important than presenting them with the strictly accurate details of their filesystem.
1 parent 671fa42 commit 7d0671b

File tree

2 files changed

+32
-25
lines changed

2 files changed

+32
-25
lines changed

lib/ls.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { resolve } = require('path')
1+
const { resolve, relative } = require('path')
22
const { EOL } = require('os')
33

44
const archy = require('archy')
@@ -298,6 +298,9 @@ const getHumanOutputItem = (node, { args, color, global, long }) => {
298298
? chalk.yellow.bgBlack
299299
: chalk.red.bgBlack
300300
const missingMsg = `UNMET ${isOptional(node) ? 'OPTIONAL ' : ''}DEPENDENCY`
301+
const targetLocation = node.root
302+
? relative(node.root.realpath, node.realpath)
303+
: node.targetLocation
301304
const label =
302305
(
303306
node[_missing]
@@ -321,7 +324,7 @@ const getHumanOutputItem = (node, { args, color, global, long }) => {
321324
: ''
322325
) +
323326
(isGitNode(node) ? ` (${node.resolved})` : '') +
324-
(node.isLink ? ` -> ${node.realpath}` : '') +
327+
(node.isLink ? ` -> ${targetLocation}` : '') +
325328
(long ? `${EOL}${node.package.description || ''}` : '')
326329

327330
return augmentItemWithIncludeMetadata(node, { label, nodes: [] })
@@ -445,6 +448,9 @@ const augmentNodesWithMetadata = ({
445448
// revisit that node in tree traversal logic, so we make it so that
446449
// we have a diff obj for deduped nodes:
447450
if (seenNodes.has(node.path)) {
451+
const { realpath, root } = node
452+
const targetLocation = root ? relative(root.realpath, realpath)
453+
: node.targetLocation
448454
node = {
449455
name: node.name,
450456
version: node.version,
@@ -453,6 +459,7 @@ const augmentNodesWithMetadata = ({
453459
path: node.path,
454460
isLink: node.isLink,
455461
realpath: node.realpath,
462+
targetLocation,
456463
[_type]: node[_type],
457464
[_invalid]: node[_invalid],
458465
[_missing]: node[_missing],

tap-snapshots/test/lib/ls.js.test.cjs

+23-23
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ [email protected] {CWD}/tap-testdir-ls-ls---dev
7070

7171
exports[`test/lib/ls.js TAP ls --link > should output tree containing linked deps 1`] = `
7272
[email protected] {CWD}/tap-testdir-ls-ls---link
73-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls---link/linked-dep
73+
\`-- [email protected] -> linked-dep
7474
7575
`
7676

@@ -480,59 +480,59 @@ exports[`test/lib/ls.js TAP ls json read problems > should print empty result 1`
480480

481481
exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should filter by parent folder workspace config 1`] = `
482482
[email protected] {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
483-
+-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/group/e
484-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/group/f
483+
+-- [email protected] -> group/e
484+
\`-- [email protected] -> group/f
485485
486486
`
487487

488488
exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should filter single workspace 1`] = `
489489
[email protected] {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
490-
+-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/a
491-
| \`-- [email protected] deduped -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d
492-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d
490+
491+
| \`-- [email protected] deduped -> d
492+
493493
494494
`
495495

496496
exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should filter using workspace config 1`] = `
497497
[email protected] {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
498-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/a
498+
499499
500-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d
500+
501501
502502
503503
504504
`
505505

506506
exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list --all workspaces properly 1`] = `
507507
[email protected] {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
508-
+-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/a
508+
509509
510-
| \`-- [email protected] deduped -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d
511-
+-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/b
512-
+-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d
510+
| \`-- [email protected] deduped -> d
511+
512+
513513
514514
515-
+-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/group/e
516-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/group/f
515+
+-- [email protected] -> group/e
516+
\`-- [email protected] -> group/f
517517
518518
`
519519

520520
exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should list workspaces properly with default configs 1`] = `
521521
[[email protected] {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
522-
[0m+-- [[email protected][39m -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/a[0m
522+
[0m+-- [[email protected][39m -> a[0m
523523
| +-- [email protected]
524-
[0m| \`-- [email protected] [90mdeduped[39m -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d[0m
525-
[0m+-- [[email protected][39m -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/b[0m
526-
[0m+-- [[email protected][39m -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d[0m
524+
[0m| \`-- [email protected] [90mdeduped[39m -> d[0m
525+
[0m+-- [[email protected][39m -> b[0m
526+
[0m+-- [[email protected][39m -> d[0m
527527
| \`-- [email protected]
528-
[0m+-- [[email protected][39m -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/group/e[0m
529-
[0m\`-- [[email protected][39m -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/group/f[0m
528+
[0m+-- [[email protected][39m -> group/e[0m
529+
[0m\`-- [[email protected][39m -> group/f[0m
530530

531531
`
532532

533533
exports[`test/lib/ls.js TAP ls loading a tree containing workspaces > should print all tree and filter by dep within only the ws subtree 1`] = `
534534
[email protected] {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces
535-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls-loading-a-tree-containing-workspaces/d
535+
536536
537537
538538
@@ -567,8 +567,8 @@ [email protected] {CWD}/tap-testdir-ls-ls-no-args
567567
exports[`test/lib/ls.js TAP ls print deduped symlinks > should output tree containing linked deps 1`] = `
568568
[email protected] {CWD}/tap-testdir-ls-ls-print-deduped-symlinks
569569
570-
| \`-- [email protected] deduped -> {CWD}/tap-testdir-ls-ls-print-deduped-symlinks/b
571-
\`-- [email protected] -> {CWD}/tap-testdir-ls-ls-print-deduped-symlinks/b
570+
| \`-- [email protected] deduped -> b
571+
572572
573573
`
574574

0 commit comments

Comments
 (0)