@npmcli/arborist 0.0.33 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/arborist/build-ideal-tree.js +344 -197
- package/lib/edge.js +24 -0
- package/lib/node.js +11 -15
- package/lib/reset-dep-flags.js +15 -0
- package/package.json +2 -2
|
@@ -70,7 +70,7 @@ const _queueNamedUpdates = Symbol('queueNamedUpdates')
|
|
|
70
70
|
const _queueVulnDependents = Symbol('queueVulnDependents')
|
|
71
71
|
const _avoidRange = Symbol('avoidRange')
|
|
72
72
|
const _shouldUpdateNode = Symbol('shouldUpdateNode')
|
|
73
|
-
const
|
|
73
|
+
const resetDepFlags = require('../reset-dep-flags.js')
|
|
74
74
|
const _loadFailures = Symbol('loadFailures')
|
|
75
75
|
const _pruneFailedOptional = Symbol('pruneFailedOptional')
|
|
76
76
|
const _linkNodes = Symbol('linkNodes')
|
|
@@ -89,10 +89,19 @@ const _strictPeerDeps = Symbol('strictPeerDeps')
|
|
|
89
89
|
const _checkEngineAndPlatform = Symbol('checkEngineAndPlatform')
|
|
90
90
|
const _checkEngine = Symbol('checkEngine')
|
|
91
91
|
const _checkPlatform = Symbol('checkPlatform')
|
|
92
|
+
const _virtualRoots = Symbol('virtualRoots')
|
|
93
|
+
const _virtualRoot = Symbol('virtualRoot')
|
|
92
94
|
|
|
93
95
|
// used for the ERESOLVE error to show the last peer conflict encountered
|
|
94
96
|
const _peerConflict = Symbol('peerConflict')
|
|
95
97
|
|
|
98
|
+
const _failPeerConflict = Symbol('failPeerConflict')
|
|
99
|
+
const _explainPeerConflict = Symbol('explainPeerConflict')
|
|
100
|
+
const _warnPeerConflict = Symbol('warnPeerConflict')
|
|
101
|
+
const _edgesOverridden = Symbol('edgesOverridden')
|
|
102
|
+
// exposed symbol for unit testing the placeDep method directly
|
|
103
|
+
const _peerSetSource = Symbol.for('peerSetSource')
|
|
104
|
+
|
|
96
105
|
// used by Reify mixin
|
|
97
106
|
const _force = Symbol.for('force')
|
|
98
107
|
const _explicitRequests = Symbol.for('explicitRequests')
|
|
@@ -142,6 +151,13 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
142
151
|
this[_linkNodes] = new Set()
|
|
143
152
|
this[_manifests] = new Map()
|
|
144
153
|
this[_peerConflict] = null
|
|
154
|
+
this[_edgesOverridden] = new Set()
|
|
155
|
+
|
|
156
|
+
// a map of each module in a peer set to the thing that depended on
|
|
157
|
+
// that set of peers in the first place. Use a WeakMap so that we
|
|
158
|
+
// don't hold onto references for nodes that are garbage collected.
|
|
159
|
+
this[_peerSetSource] = new WeakMap()
|
|
160
|
+
this[_virtualRoots] = new Map()
|
|
145
161
|
}
|
|
146
162
|
|
|
147
163
|
get explicitRequests () {
|
|
@@ -294,6 +310,7 @@ module.exports = cls => class IdealTreeBuilder extends cls {
|
|
|
294
310
|
await new this.constructor(this.options).loadActual({ root })
|
|
295
311
|
return root
|
|
296
312
|
})
|
|
313
|
+
|
|
297
314
|
.then(tree => {
|
|
298
315
|
// null the virtual tree, because we're about to hack away at it
|
|
299
316
|
// if you want another one, load another copy.
|
|
@@ -707,16 +724,42 @@ This is a one-time fix-up, please be patient...
|
|
|
707
724
|
// Set `preferDedupe: true` in the options to replace the shallower
|
|
708
725
|
// dep if allowed.
|
|
709
726
|
|
|
710
|
-
const tasks =
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
//
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
727
|
+
const tasks = []
|
|
728
|
+
const peerSource = this[_peerSetSource].get(node) || node
|
|
729
|
+
for (const edge of this[_problemEdges](node)) {
|
|
730
|
+
if (this[_edgesOverridden].has(edge))
|
|
731
|
+
continue
|
|
732
|
+
|
|
733
|
+
// peerSetSource is only relevant when we have a peerEntryEdge
|
|
734
|
+
// otherwise we're setting regular non-peer deps as if they have
|
|
735
|
+
// a virtual root of whatever brought in THIS node.
|
|
736
|
+
// so we VR the node itself if the edge is not a peer
|
|
737
|
+
const source = edge.peer ? peerSource : node
|
|
738
|
+
const virtualRoot = this[_virtualRoot](source, true)
|
|
739
|
+
// reuse virtual root if we already have one, but don't
|
|
740
|
+
// try to do the override ahead of time, since we MAY be able
|
|
741
|
+
// to create a more correct tree than the virtual root could.
|
|
742
|
+
const vrEdge = virtualRoot && virtualRoot.edgesOut.get(edge.name)
|
|
743
|
+
const vrDep = vrEdge && vrEdge.valid && vrEdge.to
|
|
744
|
+
// only re-use the virtualRoot if it's a peer edge we're placing.
|
|
745
|
+
// otherwise, we end up in situations where we override peer deps that
|
|
746
|
+
// we could have otherwise found homes for. Eg:
|
|
747
|
+
// xy -> (x, y)
|
|
748
|
+
// x -> PEER(z@1)
|
|
749
|
+
// y -> PEER(z@2)
|
|
750
|
+
// If xy is a dependency, we can resolve this like:
|
|
751
|
+
// project
|
|
752
|
+
// +-- xy
|
|
753
|
+
// | +-- y
|
|
754
|
+
// | +-- z@2
|
|
755
|
+
// +-- x
|
|
756
|
+
// +-- z@1
|
|
757
|
+
// But if x and y are loaded in the same virtual root, then they will
|
|
758
|
+
// be forced to agree on a version of z.
|
|
759
|
+
const dep = vrDep && vrDep.satisfies(edge) ? vrDep
|
|
760
|
+
: await this[_nodeFromEdge](edge, edge.peer ? virtualRoot : null)
|
|
761
|
+
tasks.push({edge, dep})
|
|
762
|
+
}
|
|
720
763
|
|
|
721
764
|
const placed = tasks
|
|
722
765
|
.sort((a, b) => a.edge.name.localeCompare(b.edge.name))
|
|
@@ -746,33 +789,45 @@ This is a one-time fix-up, please be patient...
|
|
|
746
789
|
|
|
747
790
|
// loads a node from an edge, and then loads its peer deps (and their
|
|
748
791
|
// peer deps, on down the line) into a virtual root parent.
|
|
749
|
-
[_nodeFromEdge] (edge,
|
|
792
|
+
[_nodeFromEdge] (edge, parent_) {
|
|
750
793
|
// create a virtual root node with the same deps as the node that
|
|
751
794
|
// is requesting this one, so that we can get all the peer deps in
|
|
752
795
|
// a context where they're likely to be resolvable.
|
|
753
|
-
const
|
|
754
|
-
parent = parent || new Node({
|
|
755
|
-
path: '/virtual-root',
|
|
756
|
-
sourceReference: edge.from,
|
|
757
|
-
legacyPeerDeps,
|
|
758
|
-
})
|
|
796
|
+
const parent = parent_ || this[_virtualRoot](edge.from)
|
|
759
797
|
|
|
760
798
|
const spec = npa.resolve(edge.name, edge.spec, edge.from.path)
|
|
761
799
|
return this[_nodeFromSpec](edge.name, spec, parent, edge)
|
|
762
800
|
.then(node => {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
801
|
+
// handle otherwise unresolvable dependency nesting loops by
|
|
802
|
+
// creating a symbolic link
|
|
803
|
+
// a1 -> b1 -> a2 -> b2 -> a1 -> ...
|
|
804
|
+
// instead of nesting forever, when the loop occurs, create
|
|
805
|
+
// a symbolic link to the earlier instance
|
|
768
806
|
for (let p = edge.from.resolveParent; p; p = p.resolveParent) {
|
|
769
807
|
if (p.matches(node) && !p.isRoot)
|
|
770
808
|
return new Link({ parent, target: p })
|
|
771
809
|
}
|
|
810
|
+
// keep track of the thing that caused this node to be included.
|
|
811
|
+
const src = parent.sourceReference
|
|
812
|
+
this[_peerSetSource].set(node, src)
|
|
772
813
|
return this[_loadPeerSet](node)
|
|
773
814
|
})
|
|
774
815
|
}
|
|
775
816
|
|
|
817
|
+
[_virtualRoot] (node, reuse = false) {
|
|
818
|
+
if (reuse && this[_virtualRoots].has(node))
|
|
819
|
+
return this[_virtualRoots].get(node)
|
|
820
|
+
|
|
821
|
+
const vr = new Node({
|
|
822
|
+
path: '/virtual-root',
|
|
823
|
+
sourceReference: node,
|
|
824
|
+
legacyPeerDeps: this.legacyPeerDeps,
|
|
825
|
+
})
|
|
826
|
+
|
|
827
|
+
this[_virtualRoots].set(node, vr)
|
|
828
|
+
return vr
|
|
829
|
+
}
|
|
830
|
+
|
|
776
831
|
[_problemEdges] (node) {
|
|
777
832
|
// skip over any bundled deps, they're not our problem.
|
|
778
833
|
// Note that this WILL fetch bundled meta-deps which are also dependencies
|
|
@@ -801,14 +856,14 @@ This is a one-time fix-up, please be patient...
|
|
|
801
856
|
if (edge.to && edge.to.inShrinkwrap)
|
|
802
857
|
return false
|
|
803
858
|
|
|
804
|
-
// If the edge has an error, there's a problem.
|
|
805
|
-
if (!edge.valid)
|
|
806
|
-
return true
|
|
807
|
-
|
|
808
859
|
// If the edge has no destination, that's a problem.
|
|
809
860
|
if (!edge.to)
|
|
810
861
|
return edge.type !== 'peerOptional'
|
|
811
862
|
|
|
863
|
+
// If the edge has an error, there's a problem.
|
|
864
|
+
if (!edge.valid)
|
|
865
|
+
return true
|
|
866
|
+
|
|
812
867
|
// If user has explicitly asked to update this package by name, it's a problem.
|
|
813
868
|
if (this[_updateNames].includes(edge.name))
|
|
814
869
|
return true
|
|
@@ -891,19 +946,100 @@ This is a one-time fix-up, please be patient...
|
|
|
891
946
|
// We prefer to get peer deps that meet the requiring node's dependency,
|
|
892
947
|
// if possible, since that almost certainly works (since that package was
|
|
893
948
|
// developed with this set of deps) and will typically be more restrictive.
|
|
894
|
-
|
|
949
|
+
// Note that the peers in the set can conflict either with each other,
|
|
950
|
+
// or with a direct dependency from the virtual root parent! In strict
|
|
951
|
+
// mode, this is always an error. In force mode, it never is, and we
|
|
952
|
+
// prefer the parent's non-peer dep over a peer dep, or the version that
|
|
953
|
+
// gets placed first. In non-strict mode, we behave strictly if the
|
|
954
|
+
// virtual root is based on the root project, and allow non-peer parent
|
|
955
|
+
// deps to override, but throw if no preference can be determined.
|
|
956
|
+
async [_loadPeerSet] (node) {
|
|
895
957
|
const peerEdges = [...node.edgesOut.values()]
|
|
896
|
-
|
|
897
|
-
.
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
958
|
+
// we only care about peers here, and don't install peerOptionals
|
|
959
|
+
.filter(e => e.peer && !e.valid && !e.optional)
|
|
960
|
+
.sort(({name: a}, {name: b}) => a.localeCompare(b))
|
|
961
|
+
|
|
962
|
+
for (const edge of peerEdges) {
|
|
963
|
+
// already placed this one, and we're happy with it.
|
|
964
|
+
if (edge.valid)
|
|
965
|
+
continue
|
|
966
|
+
|
|
967
|
+
const parentEdge = node.parent.edgesOut.get(edge.name)
|
|
968
|
+
const {isRoot, isWorkspace} = node.parent.sourceReference
|
|
969
|
+
const isMine = isRoot || isWorkspace
|
|
970
|
+
if (edge.missing) {
|
|
971
|
+
if (!parentEdge) {
|
|
972
|
+
// easy, just put the thing there
|
|
973
|
+
await this[_nodeFromEdge](edge, node.parent)
|
|
974
|
+
continue
|
|
975
|
+
} else {
|
|
976
|
+
// try to put the parent's preference, and make sure that satisfies.
|
|
977
|
+
// if so, we're good.
|
|
978
|
+
// if it does not, then we have a problem in strict mode, no problem
|
|
979
|
+
// in force mode, and a problem in non-strict mode if this isn't
|
|
980
|
+
// on behalf of the root node. In all such cases, we warn at least.
|
|
981
|
+
await this[_nodeFromEdge](parentEdge, node.parent)
|
|
982
|
+
|
|
983
|
+
// hooray! that worked!
|
|
984
|
+
if (edge.valid)
|
|
985
|
+
continue
|
|
986
|
+
|
|
987
|
+
// allow it
|
|
988
|
+
if (this[_force] || !isMine && !this[_strictPeerDeps])
|
|
989
|
+
continue
|
|
990
|
+
else
|
|
991
|
+
this[_failPeerConflict](edge)
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// at this point we know that there is a dep there, and
|
|
996
|
+
// we don't like it. always fail strictly, always allow forcibly or
|
|
997
|
+
// in non-strict mode if it's not our fault. don't warn here, because
|
|
998
|
+
// we are going to warn again when we place the deps, if we end up
|
|
999
|
+
// overriding for something else.
|
|
1000
|
+
if (this[_force] || !isMine && !this[_strictPeerDeps])
|
|
1001
|
+
continue
|
|
1002
|
+
|
|
1003
|
+
// ok, it's the root, or we're in unforced strict mode, so this is bad
|
|
1004
|
+
this[_failPeerConflict](edge)
|
|
1005
|
+
}
|
|
1006
|
+
return node
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
[_failPeerConflict] (edge) {
|
|
1010
|
+
const expl = this[_explainPeerConflict](edge)
|
|
1011
|
+
throw Object.assign(new Error('unable to resolve dependency tree'), expl)
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
[_explainPeerConflict] (edge) {
|
|
1015
|
+
const node = edge.from
|
|
1016
|
+
const curNode = node.resolve(edge.name)
|
|
1017
|
+
const pc = this[_peerConflict] || { peer: null, current: null }
|
|
1018
|
+
const current = curNode ? curNode.explain() : pc.current
|
|
1019
|
+
const peerConflict = pc.peer
|
|
1020
|
+
return {
|
|
1021
|
+
code: 'ERESOLVE',
|
|
1022
|
+
current,
|
|
1023
|
+
edge: edge.explain(),
|
|
1024
|
+
peerConflict,
|
|
1025
|
+
strictPeerDeps: this[_strictPeerDeps],
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
[_warnPeerConflict] (edge) {
|
|
1030
|
+
// track that we've overridden this edge, so that we don't keep trying
|
|
1031
|
+
// to re-resolve it in an infinite loop.
|
|
1032
|
+
this[_edgesOverridden].add(edge)
|
|
1033
|
+
const expl = this[_explainPeerConflict](edge)
|
|
1034
|
+
this.log.warn('ERESOLVE', 'overriding peer dependency', expl)
|
|
901
1035
|
}
|
|
902
1036
|
|
|
903
1037
|
// starting from either node, or in the case of non-root peer deps,
|
|
904
1038
|
// the node's parent, walk up the tree until we find the first spot
|
|
905
1039
|
// where this dep cannot be placed, and use the one right before that.
|
|
906
1040
|
// place dep, requested by node, to satisfy edge
|
|
1041
|
+
// XXX split this out into a separate method or mixin? It's quite a lot
|
|
1042
|
+
// of functionality that ought to have its own unit tests more conveniently.
|
|
907
1043
|
[_placeDep] (dep, node, edge, peerEntryEdge = null) {
|
|
908
1044
|
if (edge.to &&
|
|
909
1045
|
!edge.error &&
|
|
@@ -911,16 +1047,15 @@ This is a one-time fix-up, please be patient...
|
|
|
911
1047
|
!this[_isVulnerable](edge.to))
|
|
912
1048
|
return []
|
|
913
1049
|
|
|
914
|
-
// top nodes should still get peer deps from their
|
|
915
|
-
//
|
|
916
|
-
//
|
|
1050
|
+
// top nodes should still get peer deps from their fsParent if possible,
|
|
1051
|
+
// and only install locally if there's no other option, eg for a link
|
|
1052
|
+
// outside of the project root, or for a conflicted dep.
|
|
917
1053
|
const start = edge.peer && !node.isRoot
|
|
918
1054
|
? node.resolveParent || node
|
|
919
1055
|
: node
|
|
920
1056
|
|
|
921
1057
|
let target
|
|
922
1058
|
let canPlace = null
|
|
923
|
-
let warnPeer = false
|
|
924
1059
|
for (let check = start; check; check = check.resolveParent) {
|
|
925
1060
|
const cp = this[_canPlaceDep](dep, check, edge, peerEntryEdge)
|
|
926
1061
|
|
|
@@ -928,17 +1063,8 @@ This is a one-time fix-up, please be patient...
|
|
|
928
1063
|
if (cp !== CONFLICT) {
|
|
929
1064
|
canPlace = cp
|
|
930
1065
|
target = check
|
|
931
|
-
} else
|
|
932
|
-
if (check === start) {
|
|
933
|
-
// if it's a peer dep, and the first place we're putting it conflicts
|
|
934
|
-
// because the node has a direct dependency on the pkg in question,
|
|
935
|
-
// then we treat that as an override when --force is applied, and
|
|
936
|
-
// just warn about it.
|
|
937
|
-
const checkEdge = check.edgesOut.get(edge.name)
|
|
938
|
-
warnPeer = check === start && edge.peer && checkEdge
|
|
939
|
-
}
|
|
1066
|
+
} else
|
|
940
1067
|
break
|
|
941
|
-
}
|
|
942
1068
|
|
|
943
1069
|
// nest packages like npm v1 and v2
|
|
944
1070
|
// very disk-inefficient
|
|
@@ -951,38 +1077,16 @@ This is a one-time fix-up, please be patient...
|
|
|
951
1077
|
break
|
|
952
1078
|
}
|
|
953
1079
|
|
|
954
|
-
if (!target)
|
|
955
|
-
|
|
956
|
-
const pc = this[_peerConflict] || { peer: null, current: null }
|
|
957
|
-
// we'll only get one of these
|
|
958
|
-
const current = curNode ? curNode.explain() : pc.current
|
|
959
|
-
const peerConflict = pc.peer
|
|
960
|
-
const expl = {
|
|
961
|
-
code: 'ERESOLVE',
|
|
962
|
-
dep: dep.explain(edge),
|
|
963
|
-
current,
|
|
964
|
-
peerConflict,
|
|
965
|
-
fixWithForce: edge.peer && !!warnPeer,
|
|
966
|
-
type: edge.type,
|
|
967
|
-
isPeer: edge.peer,
|
|
968
|
-
}
|
|
969
|
-
const override = this[_force] || !this[_strictPeerDeps]
|
|
970
|
-
|
|
971
|
-
if (override && expl.fixWithForce) {
|
|
972
|
-
this.log.warn('ERESOLVE', 'overriding peer dependency', expl)
|
|
973
|
-
return []
|
|
974
|
-
} else {
|
|
975
|
-
const er = new Error('unable to resolve dependency tree')
|
|
976
|
-
throw Object.assign(er, expl)
|
|
977
|
-
}
|
|
978
|
-
}
|
|
1080
|
+
if (!target)
|
|
1081
|
+
this[_failPeerConflict](edge)
|
|
979
1082
|
|
|
980
1083
|
this.log.silly(
|
|
981
1084
|
'placeDep',
|
|
982
1085
|
target.location || 'ROOT',
|
|
983
|
-
`${
|
|
984
|
-
canPlace,
|
|
985
|
-
`for: ${node.package._id || node.location}
|
|
1086
|
+
`${dep.name}@${dep.version}`,
|
|
1087
|
+
canPlace.description || /* istanbul ignore next */ canPlace,
|
|
1088
|
+
`for: ${node.package._id || node.location}`,
|
|
1089
|
+
`want: ${edge.spec || '*'}`
|
|
986
1090
|
)
|
|
987
1091
|
|
|
988
1092
|
// it worked, so we clearly have no peer conflicts at this point.
|
|
@@ -1034,10 +1138,12 @@ This is a one-time fix-up, please be patient...
|
|
|
1034
1138
|
edge.to.parent = null
|
|
1035
1139
|
|
|
1036
1140
|
// visit any dependents who are upset by this change
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1141
|
+
// if it's an angry overridden peer edge, however, make sure we
|
|
1142
|
+
// skip over it!
|
|
1143
|
+
for (const edgeIn of dep.edgesIn) {
|
|
1144
|
+
if (edgeIn !== edge && !edgeIn.valid && !this[_depsSeen].has(edge.from)) {
|
|
1145
|
+
this.addTracker('idealTree', edgeIn.from.name, edgeIn.from.location)
|
|
1146
|
+
this[_depsQueue].push(edgeIn.from)
|
|
1041
1147
|
}
|
|
1042
1148
|
}
|
|
1043
1149
|
|
|
@@ -1073,28 +1179,30 @@ This is a one-time fix-up, please be patient...
|
|
|
1073
1179
|
// also place its unmet or invalid peer deps at this location
|
|
1074
1180
|
// note that dep has now been removed from the virtualRoot set
|
|
1075
1181
|
// by virtue of being placed in the target's node_modules.
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1182
|
+
const peers = []
|
|
1183
|
+
// double loop so that we don't yank things out and then fail to find
|
|
1184
|
+
// them in the virtualRoot's children.
|
|
1185
|
+
for (const peerEdge of dep.edgesOut.values()) {
|
|
1186
|
+
if (!peerEdge.peer || peerEdge.valid)
|
|
1187
|
+
continue
|
|
1188
|
+
const peer = virtualRoot.children.get(peerEdge.name)
|
|
1189
|
+
// since we re-use virtualRoots, it's possible that the node was
|
|
1190
|
+
// already placed somewhere in the tree, and thus plucked off the
|
|
1191
|
+
// virtual root. however, in that case, it should have been no
|
|
1192
|
+
// longer a missing/invalid peer dep, so something is messed up.
|
|
1193
|
+
if (peer)
|
|
1194
|
+
peers.push([peer, peerEdge])
|
|
1195
|
+
}
|
|
1090
1196
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
}
|
|
1197
|
+
for (const [peer, peerEdge] of peers) {
|
|
1198
|
+
const peerPlaced = this[_placeDep](
|
|
1199
|
+
peer, dep, peerEdge, peerEntryEdge || edge)
|
|
1200
|
+
placed.push(...peerPlaced)
|
|
1096
1201
|
}
|
|
1097
1202
|
|
|
1203
|
+
// we're done with this now, clean it up.
|
|
1204
|
+
this[_virtualRoots].delete(virtualRoot.sourceReference)
|
|
1205
|
+
|
|
1098
1206
|
return placed
|
|
1099
1207
|
}
|
|
1100
1208
|
|
|
@@ -1138,43 +1246,41 @@ This is a one-time fix-up, please be patient...
|
|
|
1138
1246
|
// When we check peers, we pass along the peerEntryEdge to track the
|
|
1139
1247
|
// original edge that caused us to load the family of peer dependencies.
|
|
1140
1248
|
[_canPlaceDep] (dep, target, edge, peerEntryEdge = null) {
|
|
1141
|
-
// peer deps of root deps are effectively root deps
|
|
1142
|
-
const isRootDep = target.isRoot && (
|
|
1143
|
-
// a direct dependency from the root node
|
|
1144
|
-
edge.from === target ||
|
|
1145
|
-
// a member of the peer set of a direct root dependency
|
|
1146
|
-
peerEntryEdge && peerEntryEdge.from === target
|
|
1147
|
-
)
|
|
1148
|
-
|
|
1149
1249
|
const entryEdge = peerEntryEdge || edge
|
|
1250
|
+
const source = this[_peerSetSource].get(dep)
|
|
1251
|
+
const virtualRoot = dep.parent
|
|
1252
|
+
const vrEdge = virtualRoot.edgesOut.get(edge.name)
|
|
1150
1253
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
// if the integrities match, then it's literally the same exact bytes,
|
|
1155
|
-
// even if it came from somewhere else.
|
|
1156
|
-
if (dep.integrity && dep.integrity === current.integrity)
|
|
1157
|
-
return KEEP
|
|
1254
|
+
const isSource = target === source
|
|
1255
|
+
const { isRoot, isWorkspace } = source || {}
|
|
1256
|
+
const isMine = isRoot || isWorkspace
|
|
1158
1257
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
return this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge)
|
|
1258
|
+
if (target.children.has(edge.name)) {
|
|
1259
|
+
const current = target.children.get(edge.name)
|
|
1162
1260
|
|
|
1163
|
-
//
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1261
|
+
// same thing = keep
|
|
1262
|
+
if (dep.matches(current))
|
|
1263
|
+
return KEEP
|
|
1264
|
+
|
|
1265
|
+
const { version: curVer } = current
|
|
1266
|
+
const { version: newVer } = dep
|
|
1167
1267
|
const tryReplace = curVer && newVer && semver.gte(newVer, curVer)
|
|
1168
|
-
if (tryReplace &&
|
|
1169
|
-
|
|
1268
|
+
if (tryReplace && dep.canReplace(current)) {
|
|
1269
|
+
const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge)
|
|
1270
|
+
/* istanbul ignore else - It's extremely rare that a replaceable
|
|
1271
|
+
* node would be a conflict, if the current one wasn't a conflict,
|
|
1272
|
+
* but it is theoretically possible if peer deps are pinned. In
|
|
1273
|
+
* that case we treat it like any other conflict, and keep trying */
|
|
1274
|
+
if (res !== CONFLICT)
|
|
1275
|
+
return res
|
|
1276
|
+
}
|
|
1170
1277
|
|
|
1171
|
-
// ok,
|
|
1278
|
+
// ok, can't replace the current with new one, but maybe current is ok?
|
|
1172
1279
|
if (edge.satisfiedBy(current))
|
|
1173
1280
|
return KEEP
|
|
1174
1281
|
|
|
1175
|
-
//
|
|
1176
|
-
|
|
1177
|
-
if (this[_preferDedupe] && current.canReplaceWith(dep)) {
|
|
1282
|
+
// if we prefer deduping, then try replacing newer with older
|
|
1283
|
+
if (this[_preferDedupe] && !tryReplace && dep.canReplace(current)) {
|
|
1178
1284
|
const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge)
|
|
1179
1285
|
/* istanbul ignore else - It's extremely rare that a replaceable
|
|
1180
1286
|
* node would be a conflict, if the current one wasn't a conflict,
|
|
@@ -1184,50 +1290,90 @@ This is a one-time fix-up, please be patient...
|
|
|
1184
1290
|
return res
|
|
1185
1291
|
}
|
|
1186
1292
|
|
|
1187
|
-
//
|
|
1188
|
-
//
|
|
1189
|
-
//
|
|
1190
|
-
//
|
|
1191
|
-
//
|
|
1192
|
-
//
|
|
1193
|
-
//
|
|
1194
|
-
|
|
1293
|
+
// check for conflict override cases.
|
|
1294
|
+
// first: is this the only place this thing can go? If the target is
|
|
1295
|
+
// the source, then one of these things are true.
|
|
1296
|
+
//
|
|
1297
|
+
// 1. the conflicted dep was deduped up to here from a lower dependency
|
|
1298
|
+
// w -> (x,y)
|
|
1299
|
+
// x -> (z)
|
|
1300
|
+
// y -> PEER(p@1)
|
|
1301
|
+
// z -> (q)
|
|
1302
|
+
// q -> (p@2)
|
|
1303
|
+
//
|
|
1304
|
+
// When building, let's say that x is fully placed, with all of its
|
|
1305
|
+
// deps, and we're _adding_ y. Since the peer on p@1 was not initially
|
|
1306
|
+
// present, it's been deduped up to w, and now needs to be pushed out.
|
|
1307
|
+
// Replace it, and potentially also replace its peer set (though that'll
|
|
1308
|
+
// be accomplished by making the same determination when we call
|
|
1309
|
+
// _canPlacePeers)
|
|
1310
|
+
//
|
|
1311
|
+
// 2. the dep we're TRYING to place here ought to be overridden by the
|
|
1312
|
+
// one that's here now, because current is (a) a direct dep of the
|
|
1313
|
+
// source, or (b) an already-placed peer in a conflicted peer set, or
|
|
1314
|
+
// (c) an already-placed peer in a different peer set at the same level.
|
|
1315
|
+
// If strict or ours, conflict. Otherwise, keep.
|
|
1316
|
+
if (isSource) {
|
|
1317
|
+
// check to see if the current module could go deeper in the tree
|
|
1195
1318
|
const peerSet = getPeerSet(current)
|
|
1196
|
-
|
|
1319
|
+
let canReplace = true
|
|
1320
|
+
OUTER: for (const p of peerSet) {
|
|
1197
1321
|
// if any have a non-peer dep from the target, or a peer dep if
|
|
1198
|
-
// the target is root, then
|
|
1322
|
+
// the target is root, then cannot safely replace and dupe deeper.
|
|
1199
1323
|
for (const edge of p.edgesIn) {
|
|
1200
|
-
if (edge.
|
|
1201
|
-
// root deps take precedence always.
|
|
1202
|
-
// in case this is an edge coming from a link it's also
|
|
1203
|
-
// going to conflict since deps are effectively relative
|
|
1204
|
-
// to its link node parent
|
|
1205
|
-
if (edge.from.isTop)
|
|
1206
|
-
return CONFLICT
|
|
1207
|
-
|
|
1208
|
-
// other peer deps on this node are irrelevant though.
|
|
1324
|
+
if (peerSet.has(edge.from))
|
|
1209
1325
|
continue
|
|
1326
|
+
|
|
1327
|
+
// only respect valid edges, however, since we're likely trying
|
|
1328
|
+
// to fix the very one that's currently broken!
|
|
1329
|
+
if (edge.from === target && edge.valid) {
|
|
1330
|
+
canReplace = false
|
|
1331
|
+
break OUTER
|
|
1210
1332
|
}
|
|
1211
|
-
// note that we MAY resolve this conflict by using the target's
|
|
1212
|
-
// conflicting dep on the peer, if --force is set.
|
|
1213
|
-
if (edge.from === target)
|
|
1214
|
-
return CONFLICT
|
|
1215
1333
|
}
|
|
1216
1334
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1335
|
+
if (canReplace) {
|
|
1336
|
+
const ret = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge)
|
|
1337
|
+
/* istanbul ignore else - extremely rare that the peer set would
|
|
1338
|
+
* conflict if we can replace the node in question, but theoretically
|
|
1339
|
+
* possible, if peer deps are pinned aggressively. */
|
|
1340
|
+
if (ret !== CONFLICT)
|
|
1341
|
+
return ret
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// so it's not a deeper dep that's been deduped. That means that the
|
|
1345
|
+
// only way it could have ended up here is if it's a conflicted peer.
|
|
1346
|
+
/* istanbul ignore else - would have already crashed if not forced,
|
|
1347
|
+
* and either mine or strict, when creating the peerSet. Keeping this
|
|
1348
|
+
* check so that we're not only relying on action at a distance. */
|
|
1349
|
+
if (!this[_strictPeerDeps] && !isMine || this[_force]) {
|
|
1350
|
+
this[_warnPeerConflict](edge, dep)
|
|
1351
|
+
return KEEP
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
if (vrEdge && vrEdge.satisfiedBy(current)) {
|
|
1356
|
+
/* istanbul ignore else - If the virtual root was satisfied, in
|
|
1357
|
+
* such a way that it was an override, and it's NOT forced, and is
|
|
1358
|
+
* ours, or is in strict mode, then it would have crashed during
|
|
1359
|
+
* the creation of the peerSet. Nevertheless, this is a good check
|
|
1360
|
+
* to ensure we're not warning when we should be conflicting. */
|
|
1361
|
+
if (this[_force] || !isMine && !this[_strictPeerDeps]) {
|
|
1362
|
+
this[_warnPeerConflict](edge)
|
|
1363
|
+
return KEEP
|
|
1364
|
+
}
|
|
1220
1365
|
}
|
|
1221
1366
|
|
|
1222
|
-
// no
|
|
1367
|
+
// no justification for overriding, and no agreement possible.
|
|
1223
1368
|
return CONFLICT
|
|
1224
1369
|
}
|
|
1225
1370
|
|
|
1226
|
-
//
|
|
1227
|
-
//
|
|
1228
|
-
//
|
|
1371
|
+
// no existing node at this location!
|
|
1372
|
+
// check to see if the target doesn't have a child by that name,
|
|
1373
|
+
// but WANTS one, and won't be happy with this one. if this is the
|
|
1374
|
+
// edge we're looking to resolve, then not relevant, of course.
|
|
1229
1375
|
if (target !== entryEdge.from && target.edgesOut.has(dep.name)) {
|
|
1230
|
-
const
|
|
1376
|
+
const targetEdge = target.edgesOut.get(dep.name)
|
|
1231
1377
|
// It might be that the dep would not be valid here, BUT some other
|
|
1232
1378
|
// version would. Could to try to resolve that, but that makes this no
|
|
1233
1379
|
// longer a pure synchronous function. ugh.
|
|
@@ -1240,15 +1386,28 @@ This is a one-time fix-up, please be patient...
|
|
|
1240
1386
|
// a specific name, however, or if a dep makes an incompatible change
|
|
1241
1387
|
// to its peer dep in a non-semver-major version bump, or if the parent
|
|
1242
1388
|
// is unbounded in its dependency list.
|
|
1243
|
-
if (!
|
|
1389
|
+
if (!targetEdge.satisfiedBy(dep)) {
|
|
1390
|
+
if (isSource) {
|
|
1391
|
+
// conflicted peer dep. accept what's there, if overriding
|
|
1392
|
+
/* istanbul ignore else - If it's the source, and the source's edge
|
|
1393
|
+
* is not valid, then either we crashed when creating the peer set,
|
|
1394
|
+
* or it's forced, or it's not ours and not strict. Keep this check
|
|
1395
|
+
* to avoid relying on action at a distance, however. */
|
|
1396
|
+
if (this[_force] || !isMine && !this[_strictPeerDeps]) {
|
|
1397
|
+
this[_warnPeerConflict](edge)
|
|
1398
|
+
return KEEP
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1244
1402
|
return CONFLICT
|
|
1403
|
+
}
|
|
1245
1404
|
}
|
|
1246
1405
|
|
|
1247
|
-
// check to see what
|
|
1248
|
-
//
|
|
1249
|
-
// at this point that it's not the target's direct child node.
|
|
1250
|
-
//
|
|
1251
|
-
//
|
|
1406
|
+
// check to see what that name resolves to here, and who may depend on
|
|
1407
|
+
// being able to reach it by crawling up past this parent. we know
|
|
1408
|
+
// at this point that it's not the target's direct child node. if it's
|
|
1409
|
+
// a direct dep of the target, we just make the invalid edge and
|
|
1410
|
+
// resolve it later.
|
|
1252
1411
|
const current = target !== entryEdge.from && target.resolve(dep.name)
|
|
1253
1412
|
if (current) {
|
|
1254
1413
|
for (const edge of current.edgesIn.values()) {
|
|
@@ -1259,6 +1418,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1259
1418
|
}
|
|
1260
1419
|
}
|
|
1261
1420
|
|
|
1421
|
+
// no objections! ok to place here
|
|
1262
1422
|
return this[_canPlacePeers](dep, target, edge, OK, peerEntryEdge)
|
|
1263
1423
|
}
|
|
1264
1424
|
|
|
@@ -1271,25 +1431,28 @@ This is a one-time fix-up, please be patient...
|
|
|
1271
1431
|
return ret
|
|
1272
1432
|
|
|
1273
1433
|
for (const peer of dep.parent.children.values()) {
|
|
1274
|
-
if (peer
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1434
|
+
if (peer === dep)
|
|
1435
|
+
continue
|
|
1436
|
+
|
|
1437
|
+
const peerEdge = dep.edgesOut.get(peer.name) ||
|
|
1438
|
+
[...peer.edgesIn].find(e => e.peer)
|
|
1439
|
+
|
|
1440
|
+
/* istanbul ignore if - pretty sure this is impossible, but just
|
|
1441
|
+
being cautious */
|
|
1442
|
+
if (!peerEdge)
|
|
1443
|
+
continue
|
|
1444
|
+
|
|
1445
|
+
const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, edge)
|
|
1446
|
+
if (canPlacePeer !== CONFLICT)
|
|
1447
|
+
continue
|
|
1448
|
+
|
|
1449
|
+
const current = target.resolve(peer.name)
|
|
1450
|
+
this[_peerConflict] = {
|
|
1451
|
+
peer: peer.explain(peerEdge),
|
|
1452
|
+
current: current && current.explain(),
|
|
1290
1453
|
}
|
|
1454
|
+
return CONFLICT
|
|
1291
1455
|
}
|
|
1292
|
-
|
|
1293
1456
|
return ret
|
|
1294
1457
|
}
|
|
1295
1458
|
|
|
@@ -1362,7 +1525,7 @@ This is a one-time fix-up, please be patient...
|
|
|
1362
1525
|
// nothing to prune, because we built it from scratch. if we didn't
|
|
1363
1526
|
// add or remove anything, then also nothing to do.
|
|
1364
1527
|
if (metaFromDisk && mutateTree)
|
|
1365
|
-
this
|
|
1528
|
+
resetDepFlags(this.idealTree)
|
|
1366
1529
|
|
|
1367
1530
|
// update all the dev/optional/etc flags in the tree
|
|
1368
1531
|
// either we started with a fresh tree, or we
|
|
@@ -1397,22 +1560,6 @@ This is a one-time fix-up, please be patient...
|
|
|
1397
1560
|
node.parent = null
|
|
1398
1561
|
}
|
|
1399
1562
|
|
|
1400
|
-
// we'll need to actually do a walk from the root, because you can have
|
|
1401
|
-
// a cycle of deps that all depend on each other, but no path from root.
|
|
1402
|
-
// Also, since the ideal tree is loaded from the shrinkwrap, it had
|
|
1403
|
-
// extraneous flags set false that might now be actually extraneous, and
|
|
1404
|
-
// dev/optional flags that are also now incorrect. This method sets
|
|
1405
|
-
// all flags to true, so we can find the set that is actually extraneous.
|
|
1406
|
-
[_resetDepFlags] () {
|
|
1407
|
-
for (const node of this.idealTree.inventory.values()) {
|
|
1408
|
-
node.extraneous = true
|
|
1409
|
-
node.dev = true
|
|
1410
|
-
node.devOptional = true
|
|
1411
|
-
node.peer = true
|
|
1412
|
-
node.optional = true
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
1563
|
[_pruneFailedOptional] () {
|
|
1417
1564
|
for (const node of this[_loadFailures]) {
|
|
1418
1565
|
if (!node.optional)
|
package/lib/edge.js
CHANGED
|
@@ -12,6 +12,8 @@ const _name = Symbol('_name')
|
|
|
12
12
|
const _error = Symbol('_error')
|
|
13
13
|
const _loadError = Symbol('_loadError')
|
|
14
14
|
const _setFrom = Symbol('_setFrom')
|
|
15
|
+
const _explain = Symbol('_explain')
|
|
16
|
+
const _explanation = Symbol('_explanation')
|
|
15
17
|
|
|
16
18
|
const types = new Set([
|
|
17
19
|
'prod',
|
|
@@ -60,6 +62,25 @@ class Edge {
|
|
|
60
62
|
return depValid(node, this.spec, this.accept, this.from)
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
explain (seen = []) {
|
|
66
|
+
if (this[_explanation])
|
|
67
|
+
return this[_explanation]
|
|
68
|
+
|
|
69
|
+
return this[_explanation] = this[_explain](seen)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// return the edge data, and an explanation of how that edge came to be here
|
|
73
|
+
[_explain] (seen) {
|
|
74
|
+
const { error, from } = this
|
|
75
|
+
return {
|
|
76
|
+
type: this.type,
|
|
77
|
+
name: this.name,
|
|
78
|
+
spec: this.spec,
|
|
79
|
+
...(error ? { error } : {}),
|
|
80
|
+
...(from ? { from: from.explain(null, seen) } : {}),
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
63
84
|
get workspace () {
|
|
64
85
|
return this[_type] === 'workspace'
|
|
65
86
|
}
|
|
@@ -125,6 +146,7 @@ class Edge {
|
|
|
125
146
|
}
|
|
126
147
|
|
|
127
148
|
reload (hard = false) {
|
|
149
|
+
this[_explanation] = null
|
|
128
150
|
const newTo = this[_from].resolve(this.name)
|
|
129
151
|
if (newTo !== this[_to]) {
|
|
130
152
|
if (this[_to])
|
|
@@ -138,6 +160,7 @@ class Edge {
|
|
|
138
160
|
}
|
|
139
161
|
|
|
140
162
|
detach () {
|
|
163
|
+
this[_explanation] = null
|
|
141
164
|
if (this[_to])
|
|
142
165
|
this[_to].edgesIn.delete(this)
|
|
143
166
|
this[_from].edgesOut.delete(this.name)
|
|
@@ -147,6 +170,7 @@ class Edge {
|
|
|
147
170
|
}
|
|
148
171
|
|
|
149
172
|
[_setFrom] (node) {
|
|
173
|
+
this[_explanation] = null
|
|
150
174
|
this[_from] = node
|
|
151
175
|
if (node.edgesOut.has(this.name))
|
|
152
176
|
node.edgesOut.get(this.name).detach()
|
package/lib/node.js
CHANGED
|
@@ -57,7 +57,6 @@ const _delistFromMeta = Symbol('_delistFromMeta')
|
|
|
57
57
|
const _global = Symbol.for('global')
|
|
58
58
|
const _workspaces = Symbol('_workspaces')
|
|
59
59
|
const _explain = Symbol('_explain')
|
|
60
|
-
const _explainEdge = Symbol('_explainEdge')
|
|
61
60
|
const _explanation = Symbol('_explanation')
|
|
62
61
|
|
|
63
62
|
const relpath = require('./relpath.js')
|
|
@@ -340,9 +339,8 @@ class Node {
|
|
|
340
339
|
why.whileInstalling = {
|
|
341
340
|
name,
|
|
342
341
|
version,
|
|
342
|
+
path: this.root.sourceReference.path,
|
|
343
343
|
}
|
|
344
|
-
if (edge)
|
|
345
|
-
this[_explainEdge](edge, seen)
|
|
346
344
|
}
|
|
347
345
|
|
|
348
346
|
if (this.sourceReference)
|
|
@@ -358,7 +356,7 @@ class Node {
|
|
|
358
356
|
|
|
359
357
|
why.dependents = []
|
|
360
358
|
if (edge)
|
|
361
|
-
why.dependents.push(
|
|
359
|
+
why.dependents.push(edge.explain(seen))
|
|
362
360
|
else {
|
|
363
361
|
// if we have an edge from the root, just show that, and stop there
|
|
364
362
|
// no need to go deeper, because it doesn't provide much more value.
|
|
@@ -376,21 +374,11 @@ class Node {
|
|
|
376
374
|
edges.push(edge)
|
|
377
375
|
}
|
|
378
376
|
for (const edge of edges)
|
|
379
|
-
why.dependents.push(
|
|
377
|
+
why.dependents.push(edge.explain(seen))
|
|
380
378
|
}
|
|
381
379
|
return why
|
|
382
380
|
}
|
|
383
381
|
|
|
384
|
-
// return the edge data, and an explanation of how that edge came to be here
|
|
385
|
-
[_explainEdge] (edge, seen) {
|
|
386
|
-
return {
|
|
387
|
-
type: edge.type,
|
|
388
|
-
spec: edge.spec,
|
|
389
|
-
...(edge.error ? { error: edge.error } : {}),
|
|
390
|
-
from: edge.from.explain(null, seen),
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
382
|
isDescendantOf (node) {
|
|
395
383
|
for (let p = this; p; p = p.parent) {
|
|
396
384
|
if (p === node)
|
|
@@ -448,6 +436,14 @@ class Node {
|
|
|
448
436
|
return !!bundler && bundler !== this.root
|
|
449
437
|
}
|
|
450
438
|
|
|
439
|
+
get isWorkspace () {
|
|
440
|
+
if (this.isRoot)
|
|
441
|
+
return false
|
|
442
|
+
const { root } = this
|
|
443
|
+
const { type, to } = root.edgesOut.get(this.package.name) || {}
|
|
444
|
+
return type === 'workspace' && to && (to.target === this || to === this)
|
|
445
|
+
}
|
|
446
|
+
|
|
451
447
|
get isRoot () {
|
|
452
448
|
return this === this.root
|
|
453
449
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Sometimes we need to actually do a walk from the root, because you can
|
|
2
|
+
// have a cycle of deps that all depend on each other, but no path from root.
|
|
3
|
+
// Also, since the ideal tree is loaded from the shrinkwrap, it had extraneous
|
|
4
|
+
// flags set false that might now be actually extraneous, and dev/optional
|
|
5
|
+
// flags that are also now incorrect. This method sets all flags to true, so
|
|
6
|
+
// we can find the set that is actually extraneous.
|
|
7
|
+
module.exports = tree => {
|
|
8
|
+
for (const node of tree.inventory.values()) {
|
|
9
|
+
node.extraneous = true
|
|
10
|
+
node.dev = true
|
|
11
|
+
node.devOptional = true
|
|
12
|
+
node.peer = true
|
|
13
|
+
node.optional = true
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/arborist",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Manage node_modules trees",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@npmcli/installed-package-contents": "^1.0.5",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"@npmcli/metavuln-calculator": "^1.0.0",
|
|
9
9
|
"@npmcli/name-from-folder": "^1.0.1",
|
|
10
10
|
"@npmcli/node-gyp": "^1.0.0",
|
|
11
|
-
"@npmcli/run-script": "^1.7.
|
|
11
|
+
"@npmcli/run-script": "^1.7.2",
|
|
12
12
|
"bin-links": "^2.2.1",
|
|
13
13
|
"cacache": "^15.0.3",
|
|
14
14
|
"common-ancestor-path": "^1.0.1",
|