• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

npm / arborist / #139

Build:
Build:
LAST BUILD BRANCH:
DEFAULT BRANCH: master
Ran 02 Jun 2020 05:18PM UTC
Jobs 1
Files 31
Run time 5s
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

pending completion
#139

push

ruyadorno
Resolve infinite dependency nesting with a symlink

Fix #96

In a case like http://npm.im/@isaacs/pathological-dep-nesting-a we have
a dependency cycle that would nest infinitely:

```
a@1 -> b@1
a@2 -> b@2
b@1 -> a@2
b@2 -> a@1
```

When trying to reify this, we have to nest another a@2 under b@1,
because it would otherwise resolve to a@1.  Then that a@2 needs a b@2,
which has to nest or otherwise resolve to b@1, and the cycle goes on.

The actual (deduped) reified tree looks like:

```
root
+-- a@1
+-- b@1 (deduped from a@1's dep)
    +-- a@2 (overriding a@1 one level up)
    +-- b@2 (deduped from a@2's dep)
        +-- a@1 (overriding a@2 from one level up)
        +-- b@1 (deduped from a@1's dep)
            +-- a@2 (loop forever...)
```

With this commit, the loop is cut by detecting in buildIdealTree that a
node being added to resolve a problemEdge is satisfying an edge that
already has an identical node in its ancestor set.

Ie, in this example, when we get to the second a@1, we need to place b@1
to satisfy its dependency, or else it will resolve to b@2 (its parent).
Since the edge is a problem, we know that the nearest resolution is
_not_ a match (or else we wouldn't be bothering to add it).  Thus, any
node in the ancestry that matches the node we're attempting to add to
the tree is certainly going to cause an infinite regress, because its
presence has caused it to need to load another identical copy of itself.

While we could throw in this situation (and it'd certainly be better
than spinning forever trying to build an infinitely large tree), we can
do better, by instead creating a symbolic link to the matching node
further up the tree.  This is almost as efficient as throwing, and
produces a correct dependency resolution.

Thus, instead of growing infinitely, the resulting tree looks like:

```
root
+-- a@1
+-- b@1
    +-- a@2
    +-- b@2
        +-- a@1
        +-- b@1 (symlink to root/node_modules/b)
```

When using legacyBundling, the tre... (continued)

1953 of 1953 branches covered (100.0%)

Branch coverage included in aggregate %.

2872 of 2872 relevant lines covered (100.0%)

311.95 hits per line

Jobs
ID Job ID Ran Files Coverage
1 #139.1 02 Jun 2020 05:18PM UTC 0
100.0
Source Files on build #139
Detailed source file information is not available for this build.
  • Back to Repo
  • 48e075fc on github
  • Prev Build on
  • Next Build on
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc