Welcome to mirror list, hosted at ThFree Co, Russian Federation.

inventory.js « test « arborist « workspaces - github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1b087fe70eb3560881232999d56f1df901880866 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// this test depends on debug stuff, so force it on, even if the test env
// does not enable it.
process.env.ARBORIST_DEBUG = '1'
const Inventory = require('../lib/inventory.js')
const localeCompare = require('@isaacs/string-locale-compare')('en')

const t = require('tap')

t.test('basic operations', t => {
  const i = new Inventory()
  t.equal(i.primaryKey, 'location')
  t.same(i.indexes, ['name', 'license', 'funding', 'realpath', 'packageName'])

  // uk spelling
  i.add({ location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } })
  // old-style multi-license array
  i.add({ location: 'y', name: 'x', package: { licenses: [{ type: 'ISC' }], funding: { url: 'foo' } } })
  i.add({ location: 'z', name: 'z', package: { license: { type: 'MIT' }, funding: 'bar' } })
  i.add({ location: 'a', name: 'a', package: {} })

  t.same(i.filter(node => /[xy]/.test(node.name)), [
    i.get('x'),
    i.get('y'),
  ], 'filter returns an iterable of all matching nodes')

  t.same([...i.query('license')].sort((a, b) => localeCompare(String(a), String(b))),
    ['ISC', 'MIT', undefined])
  t.same([...i.query('license', 'MIT')], [
    { location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } },
    { location: 'z', name: 'z', package: { license: { type: 'MIT' }, funding: 'bar' } },
  ], 'can query by license')
  t.same(i.query('license', 'blerg'), new Set(),
    'empty query returns empty set')
  t.same([...i.query('name', 'x')], [
    { location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } },
    { location: 'y', name: 'x', package: { licenses: [{ type: 'ISC' }], funding: { url: 'foo' } } },
  ], 'can query by name')
  t.same([...i.query('funding')].sort((a, b) => localeCompare(String(a), String(b))),
    ['bar', 'foo', undefined])
  t.same([...i.query('funding', 'foo')], [
    { location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } },
    { location: 'y', name: 'x', package: { licenses: [{ type: 'ISC' }], funding: { url: 'foo' } } },
  ], 'can query by funding url')

  const x = i.get('x')
  t.same(x, { location: 'x', name: 'x', package: { licence: 'MIT', funding: 'foo' } }, 'get by location')
  i.add(x)
  t.same(i.get('x'), x, 'adding a second time has no effect')
  t.equal(i.has(x), true, 'has a node')
  i.add({ location: 'x', name: 'a', package: { licences: [{ type: 'ABC' }] } })
  t.same(i.get('x'), { location: 'x', name: 'a', package: { licences: [{ type: 'ABC' }] } },
    'new node at same location overwrites')
  t.equal(i.has(x), false, 'node has been overwritten')

  const a = i.get('a')
  t.same([...i.query('license', undefined)], [a], 'can query by missing license')

  t.throws(() => i.set('a', 'b'), {
    message: 'direct set() not supported, use inventory.add(node)',
  })
  const y = i.get('y')
  i.delete({ location: 'y' })
  t.equal(i.get('y'), y, 'deleting other node with same key has no effect')
  i.delete(y)
  t.equal(i.has(y), false, 'no longer has the y node')
  t.equal(i.get('y'), undefined, 'get returns undefined')

  // no name or license!
  const z = { location: 'z' }
  i.add(z)
  t.equal(i.get('z'), z, 'can add and retrieve node without secondary keys')
  // oops!  mutated out of band, that's weird, but shouldn't throw anyway
  // though, of course, this makes the secondary indexes incomplete.
  // don't do this.  but probably not worth making the package immutable.
  z.package = { name: 'z' }
  t.doesNotThrow(() => i.delete(z), 'doesnt try to delete from nonexistent sets')
  t.equal(i.get('z'), undefined, 'node is not here')
  t.equal(i.has(z), false, 'i does not have z any more')

  t.doesNotThrow(() =>
    i.add({
      location: 'f',
      name: 'f',
      package: {
        license: 'MIT',
        funding: null,
      },
    }), 'doesnt throw on falsy funding info')

  t.doesNotThrow(() =>
    i.add({
      location: 'l',
      name: 'l',
      package: {
        license: null,
      },
    }), 'doesnt throw on falsy license info')

  // inherited properties and getters are allowed
  const n = Object.assign(Object.create({
    location: 'n',
    get packageName () {
      return this.package.name
    },
    get package () {
      return this._pkg
    },
  }), { _pkg: { name: 'n' } })
  i.add(n)
  t.equal(i.get('n'), n, 'found by inherited location')
  t.same([...i.query('packageName', 'n')], [n], 'found by packageName query')

  t.end()
})

t.test('dont allow external nodes to be added to inventory', t => {
  const i = new Inventory()
  const root = { location: '', path: 'rootpath' }
  i.add(root)
  t.throws(() => i.add({ root: { path: 'otherroot' }, location: 'adsf', path: 'nodepath' }), {
    message: 'adding external node to inventory',
    root: 'rootpath',
    node: 'nodepath',
    nodeRoot: 'otherroot',
  })
  t.end()
})

t.test('adding external nodes is no-op outside debug mode', t => {
  const Inventory = t.mock('../lib/inventory.js', {
    '../lib/debug.js': () => {},
  })
  const i = new Inventory()
  const root = { location: '', path: 'rootpath' }
  i.add(root)
  const other = { root: { path: 'otherroot' }, location: 'adsf', path: 'nodepath' }
  i.add(other)
  t.equal(i.has(other), false, 'did not add external node to inventory')
  t.end()
})