Skip to content

Commit

Permalink
feat: add support to filtering by workspaces
Browse files Browse the repository at this point in the history
Adds support to a new `workspaces` option, that accepts an array of
strings, allowing users to filter the resulting fund info to a specific
set of workspaces and their dependencies.

Relates to: npm/statusboard#301
  • Loading branch information
ruyadorno committed May 12, 2021
1 parent 4ec0c7c commit 3a82335
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 3 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ Options:
- `countOnly`: Uses the tree-traversal logic from **npm fund** but skips over
any obj definition and just returns an obj containing `{ length }` - useful for
things such as printing a `6 packages are looking for funding` msg.
- `path`: Location to current working directory
- `workspaces`: `Array<String>` List of workspaces names to filter for,
the result will only include a subset of the resulting tree that includes
only the nodes that are children of the listed workspaces names.
- `path`, `registry` and more [Arborist](https://github.com/npm/arborist/) options.

##### <a name="fund.readTree"></a> `> fund.readTree(tree, [opts]) -> Promise<Object>`

Expand Down
24 changes: 22 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const URL = require('url').URL
const Arborist = require('@npmcli/arborist')
const { resolve } = require('path')

// supports object funding and string shorthand, or an array of these
// if original was an array, returns an array; else returns the lone item
Expand Down Expand Up @@ -38,7 +39,27 @@ function isValidFunding (funding) {

const empty = () => Object.create(null)

const filterWorkspaces = (tree, opts) => {
if (opts && opts.workspaces && opts.workspaces.length) {
const workspaces = new Set(opts.workspaces)
const workspacesPaths =
new Set(opts.workspaces.map(w => resolve(opts.path, w)))

const isFiltered = node =>
workspaces.has(node.name) || workspacesPaths.has(node.target.path)

for (const edge of tree.edgesOut.values()) {
const node = edge.to

if (!node.isWorkspace || !isFiltered(node))
node.parent = null
}
}
return tree
}

function readTree (tree, opts) {
tree = filterWorkspaces(tree, opts)
let packageWithFundingCount = 0
const seen = new Set()
const { countOnly } = opts || {}
Expand Down Expand Up @@ -174,8 +195,7 @@ function readTree (tree, opts) {

async function read (opts) {
const arb = new Arborist(opts)
const tree = await arb.loadActual()

const tree = await arb.loadActual(opts)
return readTree(tree, opts)
}

Expand Down
108 changes: 108 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use strict'

const { resolve } = require('path')
const t = require('tap')
const {
read,
Expand Down Expand Up @@ -1261,3 +1262,110 @@ t.test('invalid funding objects', (t) => {
)
t.end()
})

t.test('workspaces', t => {
t.test('filter by workspace', async t => {
const path = t.testdir({
'package.json': JSON.stringify({
name: 'root',
version: '1.0.0',
workspaces: [
'packages/*',
],
dependencies: {
'@npmcli/baz': '^1.0.0',
},
}),
packages: {
a: {
'package.json': JSON.stringify({
name: 'a',
version: '1.0.0',
funding: 'http://example.com/a',
dependencies: {
'@npmcli/foo': '^1.0.0',
},
}),
},
b: {
'package.json': JSON.stringify({
name: 'b',
version: '1.0.0',
devDependencies: {
'@npmcli/bar': '^1.0.0',
},
}),
},
},
node_modules: {
a: t.fixture('symlink', '../packages/a'),
b: t.fixture('symlink', '../packages/b'),
'@npmcli': {
foo: {
'package.json': JSON.stringify({
name: '@npmcli/foo',
version: '1.0.0',
funding: 'http://example.com/foo',
}),
},
bar: {
'package.json': JSON.stringify({
name: '@npmcli/bar',
version: '1.0.0',
funding: 'http://example.com/bar',
}),
},
baz: {
'package.json': JSON.stringify({
name: '@npmcli/baz',
version: '1.0.0',
funding: 'http://example.com/baz',
}),
},
},
},
})

const expected = {
dependencies: {
a: {
funding: {
url: 'http://example.com/a',
},
version: '1.0.0',
dependencies: {
'@npmcli/foo': {
funding: {
url: 'http://example.com/foo',
},
version: '1.0.0',
},
},
},
},
length: 2,
name: 'root',
version: '1.0.0',
}

t.same(
await read({ path, workspaces: ['a'] }),
expected,
'should filter by workspace name'
)

t.same(
await read({ path, workspaces: ['./packages/a'] }),
expected,
'should filter by workspace path'
)

t.same(
await read({ path, workspaces: [resolve(path, 'packages/a')] }),
expected,
'should filter by workspace full path'
)
})

t.end()
})

0 comments on commit 3a82335

Please sign in to comment.