codekingpro/portable-devtools
114k
1const relpath = require('./relpath.js')
2const Node = require('./node.js')
3const _loadDeps = Symbol.for('Arborist.Node._loadDeps')
4const _target = Symbol.for('_target')
5const { dirname } = require('node:path')
6// defined by Node class
7const _delistFromMeta = Symbol.for('_delistFromMeta')
8const _refreshLocation = Symbol.for('_refreshLocation')
9class Link extends Node {
10 constructor (options) {
11 const { root, realpath, target, parent, fsParent, isStoreLink } = options
12
13 if (!realpath && !(target && target.path)) {
14 throw new TypeError('must provide realpath for Link node')
15 }
16
17 super({
18 ...options,
19 realpath: realpath || target.path,
20 root: root || (parent ? parent.root
21 : fsParent ? fsParent.root
22 : target ? target.root
23 : null),
24 })
25
26 this.isStoreLink = isStoreLink || false
27
28 if (target) {
29 this.target = target
30 } else if (this.realpath === this.root.path) {
31 this.target = this.root
32 } else {
33 this.target = new Node({
34 ...options,
35 path: realpath,
36 parent: null,
37 fsParent: null,
38 root: this.root,
39 })
40 }
41 }
42
43 get version () {
44 return this.target ? this.target.version : this.package.version || ''
45 }
46
47 get target () {
48 return this[_target]
49 }
50
51 set target (target) {
52 const current = this[_target]
53 if (target === current) {
54 return
55 }
56
57 if (!target) {
58 if (current && current.linksIn) {
59 current.linksIn.delete(this)
60 }
61 if (this.path) {
62 this[_delistFromMeta]()
63 this[_target] = null
64 this.package = {}
65 this[_refreshLocation]()
66 } else {
67 this[_target] = null
68 }
69 return
70 }
71
72 if (!this.path) {
73 // temp node pending assignment to a tree
74 // we know it's not in the inventory yet, because no path.
75 if (target.path) {
76 this.realpath = target.path
77 } else {
78 target.path = target.realpath = this.realpath
79 }
80 target.root = this.root
81 this[_target] = target
82 target.linksIn.add(this)
83 this.package = target.package
84 return
85 }
86
87 // have to refresh metadata, because either realpath or package
88 // is very likely changing.
89 this[_delistFromMeta]()
90 this.package = target.package
91 this.realpath = target.path
92 this[_refreshLocation]()
93
94 target.root = this.root
95 }
96
97 // a link always resolves to the relative path to its target
98 get resolved () {
99 // the path/realpath guard is there for the benefit of setting
100 // these things in the "wrong" order
101 return this.path && this.realpath
102 ? `file:${relpath(dirname(this.path), this.realpath)}`
103 : null
104 }
105
106 set resolved (r) {}
107
108 // deps are resolved on the target, not the Link
109 // so this is a no-op
110 [_loadDeps] () {}
111
112 // links can't have children, only their targets can
113 // fix it to an empty list so that we can still call
114 // things that iterate over them, just as a no-op
115 get children () {
116 return new Map()
117 }
118
119 set children (c) {}
120
121 get isLink () {
122 return true
123 }
124}
125
126module.exports = Link
127 