• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1const { resolve, relative } = require('path')
2const mapWorkspaces = require('@npmcli/map-workspaces')
3const { minimatch } = require('minimatch')
4const pkgJson = require('@npmcli/package-json')
5
6// minimatch wants forward slashes only for glob patterns
7const globify = pattern => pattern.split('\\').join('/')
8
9// Returns an Map of paths to workspaces indexed by workspace name
10// { foo => '/path/to/foo' }
11const getWorkspaces = async (filters, { path, includeWorkspaceRoot, relativeFrom }) => {
12  // TODO we need a better error to be bubbled up here if this call fails
13  const { content: pkg } = await pkgJson.normalize(path)
14  const workspaces = await mapWorkspaces({ cwd: path, pkg })
15  let res = new Map()
16  if (includeWorkspaceRoot) {
17    res.set(pkg.name, path)
18  }
19
20  if (!filters.length) {
21    res = new Map([...res, ...workspaces])
22  }
23
24  for (const filterArg of filters) {
25    for (const [workspaceName, workspacePath] of workspaces.entries()) {
26      let relativePath = relative(relativeFrom, workspacePath)
27      if (filterArg.startsWith('./')) {
28        relativePath = `./${relativePath}`
29      }
30      const relativeFilter = relative(path, filterArg)
31      if (filterArg === workspaceName
32        || resolve(relativeFrom, filterArg) === workspacePath
33        || minimatch(relativePath, `${globify(relativeFilter)}/*`)
34        || minimatch(relativePath, `${globify(filterArg)}/*`)
35      ) {
36        res.set(workspaceName, workspacePath)
37      }
38    }
39  }
40
41  if (!res.size) {
42    let msg = '!'
43    if (filters.length) {
44      msg = `:\n ${filters.reduce(
45        (acc, filterArg) => `${acc} --workspace=${filterArg}`, '')}`
46    }
47
48    throw new Error(`No workspaces found${msg}`)
49  }
50
51  return res
52}
53
54module.exports = getWorkspaces
55