codekingpro/portable-devtools
115k
1const { resolve, relative } = require('node: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 