@toptal/davinci-cli-shared 1.5.2-alpha-fx-2755-codebase-specific-workflows.131 → 1.5.2-alpha-feature-comm-833-reusing-graphql-fragments-2d4dd9c0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,69 @@
1
1
  # Change Log
2
2
 
3
+ ## 1.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1731](https://github.com/toptal/davinci/pull/1731) [`1c422aae`](https://github.com/toptal/davinci/commit/1c422aae676d25cd2216c8a24af4b7e208728931) Thanks [@separatio](https://github.com/separatio)! - ---
8
+
9
+ - added data collection to Davinci commands
10
+
11
+ ## 1.8.1
12
+
13
+ ### Patch Changes
14
+
15
+ - [#1634](https://github.com/toptal/davinci/pull/1634) [`b12d1d19`](https://github.com/toptal/davinci/commit/b12d1d19af02104b9076a53b6e516198e6cda141) Thanks [@OndrejTuma](https://github.com/OndrejTuma)! - ---
16
+
17
+ ### checkPrerequirement()
18
+
19
+ - add coersion to semver check of package version
20
+
21
+ ## 1.8.0
22
+
23
+ ### Minor Changes
24
+
25
+ - [#1578](https://github.com/toptal/davinci/pull/1578) [`e602ae7e`](https://github.com/toptal/davinci/commit/e602ae7edc7d075a4192052d6c04868f08fea0a7) Thanks [@augustobmoura](https://github.com/augustobmoura)! - ---
26
+
27
+ - add cyan command to print
28
+
29
+ ## 1.7.0
30
+
31
+ ### Minor Changes
32
+
33
+ - [#1543](https://github.com/toptal/davinci/pull/1543) [`9b67beb3`](https://github.com/toptal/davinci/commit/9b67beb3aaf0e24193b2deaba3126c41e3ec9280) Thanks [@denieler](https://github.com/denieler)! - ---
34
+ - add package utils to check package prerequisites (peer dependencies packages to be installed)
35
+ - add yarn list command adapter
36
+
37
+ * [#1542](https://github.com/toptal/davinci/pull/1542) [`04fe7ffa`](https://github.com/toptal/davinci/commit/04fe7ffa161027d081c6ae870716bb06a2fcf73f) Thanks [@LashaJini](https://github.com/LashaJini)! - - Add `getDirectories` function to list directories relative to path
38
+ - Add `getPackageDirectories` function to list davinci package directories
39
+
40
+ ## 1.6.0
41
+
42
+ ### Minor Changes
43
+
44
+ - [#1517](https://github.com/toptal/davinci/pull/1517) [`fa3423f1`](https://github.com/toptal/davinci/commit/fa3423f1f9211b4d8899064aa4afdf5ca2198483) Thanks [@LashaJini](https://github.com/LashaJini)! - ---
45
+
46
+ - Do not load Jest related eslint rules if project is not using Jest
47
+ - [BREAKING CHANGE] Rename `.eslintrc` to `.eslintrc.js`
48
+
49
+ ## 1.5.4
50
+
51
+ ### Patch Changes
52
+
53
+ - [#1344](https://github.com/toptal/davinci/pull/1344) [`64c000c2`](https://github.com/toptal/davinci/commit/64c000c25d97df2c8853a6cf80b7ca81461dae24) Thanks [@dmaklygin](https://github.com/dmaklygin)! - - implement workflow documentation generator
54
+
55
+ ## 1.5.3
56
+
57
+ ### Patch Changes
58
+
59
+ - [#1378](https://github.com/toptal/davinci/pull/1378) [`3013b76d`](https://github.com/toptal/davinci/commit/3013b76d7f957924885f3e5933f5227ff42a09e1) Thanks [@augustobmoura](https://github.com/augustobmoura)! - - fix support for boolean options in convertToCLIParameters
60
+
61
+ ## 1.5.2
62
+
63
+ ### Patch Changes
64
+
65
+ - [#1343](https://github.com/toptal/davinci/pull/1343) [`1212e098`](https://github.com/toptal/davinci/commit/1212e098c668fc1c87ee9b1824edf0bc80509bc4) Thanks [@dmaklygin](https://github.com/dmaklygin)! - - implement custom helper for davinci workflow package
66
+
3
67
  ## 1.5.1
4
68
 
5
69
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toptal/davinci-cli-shared",
3
- "version": "1.5.2-alpha-fx-2755-codebase-specific-workflows.131+b2bc74b6",
3
+ "version": "1.5.2-alpha-feature-comm-833-reusing-graphql-fragments-2d4dd9c0.9+2d4dd9c0",
4
4
  "description": "Shared CLI code and CLI engine for davinci",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -14,11 +14,16 @@
14
14
  "author": "Toptal",
15
15
  "license": "ISC",
16
16
  "dependencies": {
17
+ "analytics-node": "^6.2.0",
17
18
  "chalk": "^4.1.2",
18
19
  "execa": "^5.1.1",
20
+ "find-yarn-workspace-root": "^2.0.0",
19
21
  "inquirer": "^8.2.0",
20
22
  "js-yaml": "^4.1.0",
23
+ "read-pkg-up": "7.0.1",
24
+ "semver": "^7.3.7",
25
+ "uuid": "^9.0.0",
21
26
  "vorpal": "^1.12.0"
22
27
  },
23
- "gitHead": "b2bc74b6947156d1489a42f820be1832f53b870d"
28
+ "gitHead": "2d4dd9c0609199490b7112909eb97cbe1b037717"
24
29
  }
@@ -1,6 +1,20 @@
1
+ const metrics = require('./utils/metrics/metrics')
2
+ const { gatherUsageData } = require('./utils/metrics/usage-data')
1
3
  const toVorpalArgs = require('./utils/to-vorpal-args')
2
4
 
3
- const commandsLoader = (commandCreators, vorpalInstance) => {
5
+ const sendMetrics = async (commandIdentifier, packageCommand) => {
6
+ try {
7
+ // Run identify and metrics in parallel
8
+ await Promise.all([
9
+ metrics.identify(),
10
+ gatherUsageData(commandIdentifier, packageCommand).then(metrics.track),
11
+ ])
12
+ } catch (err) {
13
+ // Metrics can fail, we still need to continue the execution
14
+ }
15
+ }
16
+
17
+ const commandsLoader = (commandCreators, vorpalInstance, packageCommand) => {
4
18
  commandCreators.forEach(commandCreator => {
5
19
  const {
6
20
  command,
@@ -8,7 +22,7 @@ const commandsLoader = (commandCreators, vorpalInstance) => {
8
22
  options = [],
9
23
  allowUnknownOptions = false,
10
24
  action,
11
- help
25
+ help,
12
26
  } = commandCreator
13
27
 
14
28
  const commandInstance = vorpalInstance
@@ -27,7 +41,15 @@ const commandsLoader = (commandCreators, vorpalInstance) => {
27
41
  commandInstance.allowUnknownOptions()
28
42
  }
29
43
 
30
- commandInstance.description(description).action(action)
44
+ commandInstance.description(description).action(async (...args) => {
45
+ // Run metrics and the action in parallel
46
+ const [result] = await Promise.all([
47
+ action(...args),
48
+ sendMetrics(command, packageCommand),
49
+ ])
50
+
51
+ return result
52
+ })
31
53
  })
32
54
  }
33
55
 
package/src/index.js CHANGED
@@ -1,13 +1,15 @@
1
1
  const vorpal = require('vorpal')
2
2
 
3
+ const { identify, track } = require('../src/utils/metrics/metrics')
3
4
  const print = require('../src/utils/print')
4
5
  const { run, runSync } = require('../src/utils/run')
5
6
  const prompt = require('../src/utils/prompt')
6
7
  const {
7
- convertToCLIParameters
8
+ convertToCLIParameters,
8
9
  } = require('../src/utils/convert-to-cli-parameters')
9
10
  const davinciProjectConfig = require('./utils/davinci-project-config')
10
11
  const files = require('./utils/files')
12
+ const packageUtils = require('./utils/package')
11
13
 
12
14
  const vorpalInstance = vorpal()
13
15
 
@@ -32,10 +34,10 @@ const catchErrorCommand = callback => {
32
34
  })
33
35
  }
34
36
 
35
- const loadCommands = commandCreators => {
37
+ const loadCommands = (commandCreators, packageCommand) => {
36
38
  const commandsLoader = require('./commands.loader')
37
39
 
38
- commandsLoader(commandCreators, vorpalInstance)
40
+ commandsLoader(commandCreators, vorpalInstance, packageCommand)
39
41
  }
40
42
 
41
43
  module.exports = {
@@ -50,5 +52,10 @@ module.exports = {
50
52
  convertToCLIParameters,
51
53
  execCommand,
52
54
  catchErrorCommand,
53
- help
55
+ help,
56
+ packageUtils,
57
+ metrics: {
58
+ identify,
59
+ track,
60
+ },
54
61
  }
@@ -1,16 +1,10 @@
1
- const convertToCLIParameters = options => {
2
- const result = []
1
+ const convertToCLIParameters = options =>
2
+ Object.entries(options).flatMap(([option, value]) => {
3
+ if (typeof value === 'boolean') {
4
+ return [`--${!value ? 'no-' : ''}${option}`]
5
+ }
3
6
 
4
- Object.keys(options).forEach(key => {
5
- result.push(`--${key}`)
6
-
7
- const hasTrueValue = options[key] === true
8
- const optionValue = hasTrueValue ? '' : String(options[key])
9
-
10
- result.push(optionValue)
7
+ return [`--${option}`, String(value)]
11
8
  })
12
9
 
13
- return result
14
- }
15
-
16
10
  module.exports = { convertToCLIParameters }
@@ -14,14 +14,14 @@ const davinciProjectConfig = {
14
14
  conventionalCommits: resolve('master', 'conventional_commits'),
15
15
  deploy: resolve('master', 'deploy'),
16
16
  deployStaging: resolve('master', 'deploy_staging'),
17
- publishAsPackage: resolve('master', 'publish_as_package')
17
+ publishAsPackage: resolve('master', 'publish_as_package'),
18
18
  },
19
19
  pr: {
20
- contractTesting: resolve('pr', 'contract_testing')
20
+ contractTesting: resolve('pr', 'contract_testing'),
21
21
  },
22
22
  isProgressiveWebApp: Boolean(resolveKey(data, 'is_progressive_web_app')),
23
23
  serviceWorkerFileName: resolveKey(data, 'service_worker_filename'),
24
- safetyWorkers: resolveKey(data, 'safety_workers')
24
+ safetyWorkers: resolveKey(data, 'safety_workers'),
25
25
  }
26
26
 
27
27
  module.exports = davinciProjectConfig
@@ -1,4 +1,5 @@
1
1
  const path = require('path')
2
+ const { readdirSync } = require('fs')
2
3
 
3
4
  const getPackageFileContent = (davinciPackageName, filename) =>
4
5
  require(getPackageFilePath(davinciPackageName, filename))
@@ -19,9 +20,26 @@ const getProjectRootFilePath = filename => {
19
20
  return path.join(currentRunningDir, filename)
20
21
  }
21
22
 
23
+ const projectHasPackage = pkg => {
24
+ try {
25
+ require.resolve(pkg)
26
+
27
+ return true
28
+ } catch {
29
+ return false
30
+ }
31
+ }
32
+
33
+ const getDirectories = source =>
34
+ readdirSync(source, { withFileTypes: true })
35
+ .filter(dirent => dirent.isDirectory())
36
+ .map(dirent => dirent.name)
37
+
22
38
  module.exports = {
23
39
  getPackageFileContent,
24
40
  getPackageFilePath,
25
41
  getProjectRootFilePath,
26
- getProjectRootFileContent
42
+ getProjectRootFileContent,
43
+ projectHasPackage,
44
+ getDirectories,
27
45
  }
@@ -0,0 +1,63 @@
1
+ const os = require('os')
2
+ const path = require('path')
3
+ const fs = require('fs')
4
+ const yaml = require('js-yaml')
5
+ const { v1: uuid } = require('uuid')
6
+
7
+ const homeDir = os.homedir()
8
+ const configDir = path.join(homeDir, '.davinci-metrics')
9
+ const configFile = path.join(configDir, 'auth.yml')
10
+ const DEFAULT_FILE_CONTENT = 'allow_tracking: "yes"'
11
+
12
+ const readConfig = () => {
13
+ let configFileContent = DEFAULT_FILE_CONTENT
14
+
15
+ try {
16
+ configFileContent = fs.readFileSync(configFile)
17
+ } catch (error) {
18
+ if (error.code === 'ENOENT') {
19
+ // File doesn't exist, lets create a new one automatically
20
+ fs.mkdirSync(configDir, { recursive: true })
21
+ fs.writeFileSync(configFile, configFileContent)
22
+ }
23
+ }
24
+
25
+ return yaml.load(configFileContent)
26
+ }
27
+
28
+ const updateConfig = config => {
29
+ const originalConfig = readConfig()
30
+ const newConfig = {
31
+ ...originalConfig,
32
+ ...config,
33
+ }
34
+
35
+ fs.writeFileSync(configFile, yaml.dump(newConfig))
36
+ }
37
+
38
+ const isTrackingEnabled = () => {
39
+ const config = readConfig()
40
+
41
+ return config.allow_tracking !== 'no' && !process.env.CI
42
+ }
43
+
44
+ const getDeviceId = () => {
45
+ const config = readConfig()
46
+
47
+ if (config && typeof config.uuid === 'string') {
48
+ return config.uuid
49
+ }
50
+
51
+ const id = uuid()
52
+
53
+ updateConfig({
54
+ uuid: id,
55
+ })
56
+
57
+ return id
58
+ }
59
+
60
+ module.exports = {
61
+ getDeviceId,
62
+ isTrackingEnabled,
63
+ }
@@ -0,0 +1,37 @@
1
+ const Analytics = require('analytics-node')
2
+
3
+ const { getDeviceId, isTrackingEnabled } = require('./id-config')
4
+ const SEGMENT_WRITE_KEY = 'cwNYguEVVqdxFj5NyTKOhlrvaNQjlsXV'
5
+ const anonymousId = getDeviceId()
6
+
7
+ const analytics = new Analytics(SEGMENT_WRITE_KEY, {
8
+ enable: process.env.DAVINCI_SKIP_ANALYTICS !== 'true' && isTrackingEnabled(),
9
+ flushAt: 1,
10
+ })
11
+
12
+ const identify = () =>
13
+ new Promise((resolve, reject) => {
14
+ analytics.identify(
15
+ {
16
+ anonymousId,
17
+ },
18
+ err => (err ? reject(err) : resolve())
19
+ )
20
+ })
21
+
22
+ const track = properties =>
23
+ new Promise((resolve, reject) => {
24
+ analytics.track(
25
+ {
26
+ anonymousId,
27
+ event: 'davinci-command',
28
+ properties,
29
+ },
30
+ err => (err ? reject(err) : resolve())
31
+ )
32
+ })
33
+
34
+ module.exports = {
35
+ identify,
36
+ track,
37
+ }
@@ -0,0 +1,126 @@
1
+ const path = require('path')
2
+ const os = require('os')
3
+ const fs = require('fs')
4
+ const execa = require('execa')
5
+ const readPackageUp = require('read-pkg-up')
6
+ const findYarnWorkspaceRoot = require('find-yarn-workspace-root')
7
+
8
+ const TOPTAL_SSH_REPO_URL_REGEX =
9
+ /^git@github\.com:\/?toptal\/([A-Za-z0-9_.-]+)\.git$/
10
+
11
+ const TOPTAL_HTTPS_REPO_URL_REGEX =
12
+ /^https:\/\/github\.com\/toptal\/([A-Za-z0-9_.-]+)\.git$/
13
+
14
+ const UNKNOWN = '<unknown>'
15
+
16
+ const getProjectName = async () => {
17
+ const gitProcess = await execa('git', ['remote', 'get-url', 'origin'])
18
+ const repoOriginUrl = gitProcess.stdout
19
+
20
+ // Not matching with a pattern means that either:
21
+ // 1. Project is not from toptal, so not relevant information
22
+ // 2. Project is not on github, unlikely for toptal
23
+ // 3. User is using an ssh alias, in this case we cannot catch it in a sane way otherwise
24
+ const toptalRepoFound = [
25
+ TOPTAL_SSH_REPO_URL_REGEX,
26
+ TOPTAL_HTTPS_REPO_URL_REGEX,
27
+ ]
28
+ .map(pattern => repoOriginUrl.match(pattern))
29
+ .find(Boolean)
30
+
31
+ return toptalRepoFound?.[1] ?? UNKNOWN
32
+ }
33
+
34
+ const getGitBranch = async () => {
35
+ const gitProcess = await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'])
36
+
37
+ return gitProcess.stdout
38
+ }
39
+
40
+ const getOsInfo = () => [os.platform(), os.release(), os.arch()].join(' ')
41
+
42
+ const getPackageManagerFromLockfiles = () => {
43
+ const lockFiles = {
44
+ npm: 'package-lock.json',
45
+ yarn: 'yarn.lock',
46
+ pnpm: 'pnpm-lock.yaml',
47
+ }
48
+
49
+ const workspaceRoot = findYarnWorkspaceRoot() ?? process.cwd()
50
+
51
+ for (const [packageManager, lockFile] of Object.entries(lockFiles)) {
52
+ if (fs.existsSync(path.resolve(workspaceRoot, lockFile))) {
53
+ return packageManager
54
+ }
55
+ }
56
+
57
+ return UNKNOWN
58
+ }
59
+
60
+ const getPackageManager = () => {
61
+ const userAgent = process.env.npm_config_user_agent ?? ''
62
+ const possiblePackageManagers = ['pnpm', 'yarn', 'npm']
63
+
64
+ // Should find a package manager when executed as a package.json script
65
+ const foundPackageManager = possiblePackageManagers.find(packageManager =>
66
+ userAgent.includes(packageManager)
67
+ )
68
+
69
+ return foundPackageManager ?? getPackageManagerFromLockfiles() ?? UNKNOWN
70
+ }
71
+
72
+ const hideSensitiveInformation = data => ({
73
+ ...data,
74
+ projectName: UNKNOWN,
75
+ packageName: UNKNOWN,
76
+ packageVersion: UNKNOWN,
77
+ gitBranch: UNKNOWN,
78
+ })
79
+
80
+ const sanitizeCommandDefinition = commandStr =>
81
+ commandStr
82
+ .replace(/\[[^\]]*\]/g, '') // Remove optional extra arguments (Eg. [foo...])
83
+ .replace(/<[^>]*>/g, '') // Remove required extra arguments (Eg. <foo>)
84
+ .replace(/ +/g, ' ') // Replace multiple spaces to a single space
85
+ .trim()
86
+ .replace(/ /g, '_')
87
+
88
+ const gatherUsageData = async (commandIdentifier, davinciCommand) => {
89
+ const [projectName, gitBranch, packageInfo] = await Promise.all([
90
+ getProjectName(),
91
+ getGitBranch(),
92
+ readPackageUp(),
93
+ ])
94
+
95
+ const {
96
+ packageJson: { name: packageName, version: packageVersion },
97
+ } = packageInfo
98
+ const osInfo = getOsInfo()
99
+ const packageManager = getPackageManager()
100
+ const nodeVersion = process.version
101
+ const commandName = sanitizeCommandDefinition(
102
+ `${davinciCommand}_${commandIdentifier}`
103
+ )
104
+
105
+ const data = {
106
+ commandName,
107
+ projectName,
108
+ packageName,
109
+ packageVersion,
110
+ gitBranch,
111
+ osInfo,
112
+ packageManager,
113
+ nodeVersion,
114
+ davinciPackage: davinciCommand,
115
+ }
116
+
117
+ if (projectName === UNKNOWN) {
118
+ // If the project is unknown we are probably dealing with an external user
119
+ // Hiding sensitive information
120
+ return hideSensitiveInformation(data)
121
+ }
122
+
123
+ return data
124
+ }
125
+
126
+ module.exports = { gatherUsageData }
@@ -0,0 +1,41 @@
1
+ const semver = require('semver')
2
+ const readPkgUp = require('read-pkg-up')
3
+
4
+ const yarnAdapter = require('./yarn-adapter')
5
+
6
+ const getPackagePackageJson = cwd => {
7
+ return readPkgUp.sync({ cwd }).packageJson
8
+ }
9
+
10
+ const getInstalledPackageVersion = packageName => {
11
+ const packageInfoList = yarnAdapter.list(packageName)
12
+
13
+ if (!packageInfoList.size) {
14
+ return null
15
+ }
16
+
17
+ return packageInfoList.get(packageName)
18
+ }
19
+
20
+ const checkPrerequirement = ({ dependencies, packageName }) => {
21
+ const validVersionOrRange = dependencies[packageName]
22
+
23
+ const installedVersion = getInstalledPackageVersion(packageName)
24
+
25
+ if (!installedVersion) {
26
+ return `Cannot find module '${packageName}'.`
27
+ }
28
+
29
+ if (semver.satisfies(semver.coerce(installedVersion), validVersionOrRange)) {
30
+ return null
31
+ }
32
+
33
+ return `Invalid version of package ${packageName} is installed.
34
+ Installed version: ${installedVersion}
35
+ Should be: ${validVersionOrRange}`
36
+ }
37
+
38
+ module.exports = {
39
+ getPackagePackageJson,
40
+ checkPrerequirement,
41
+ }
@@ -5,11 +5,15 @@ const isObject = obj => typeof obj === 'object'
5
5
  const inspectObject = obj =>
6
6
  util.inspect(obj, {
7
7
  colors: false,
8
- depth: null
8
+ depth: null,
9
9
  })
10
10
  const prettifyObjectIfExist = args =>
11
11
  args.map(arg => (isObject(arg) ? inspectObject(arg) : arg))
12
12
 
13
+ const cyan = (...args) => {
14
+ console.log(chalk.cyan(...prettifyObjectIfExist(args)))
15
+ }
16
+
13
17
  const green = (...args) => {
14
18
  console.log(chalk.green(...prettifyObjectIfExist(args)))
15
19
  }
@@ -59,9 +63,10 @@ const prettifyCommands = commands => {
59
63
 
60
64
  module.exports = {
61
65
  green,
66
+ cyan,
62
67
  yellow,
63
68
  red,
64
69
  grey,
65
70
  generatePadding,
66
- prettifyCommands
71
+ prettifyCommands,
67
72
  }
@@ -5,8 +5,8 @@ const confirm = async (name, message) => {
5
5
  {
6
6
  type: 'confirm',
7
7
  name,
8
- message
9
- }
8
+ message,
9
+ },
10
10
  ])
11
11
 
12
12
  return result[name]
@@ -18,8 +18,8 @@ const input = async (name, message, validate) => {
18
18
  type: 'input',
19
19
  name,
20
20
  message,
21
- validate
22
- }
21
+ validate,
22
+ },
23
23
  ])
24
24
 
25
25
  return result[name]
@@ -31,8 +31,8 @@ const password = async (name, message, validate) => {
31
31
  type: 'password',
32
32
  name,
33
33
  message,
34
- validate
35
- }
34
+ validate,
35
+ },
36
36
  ])
37
37
 
38
38
  return result[name]
@@ -41,5 +41,5 @@ const password = async (name, message, validate) => {
41
41
  module.exports = {
42
42
  confirm,
43
43
  input,
44
- password
44
+ password,
45
45
  }
package/src/utils/run.js CHANGED
@@ -8,7 +8,7 @@ const runSync = (command, args, options) => {
8
8
 
9
9
  const result = execa.sync(command, args, {
10
10
  stdio: 'inherit',
11
- ...options
11
+ ...options,
12
12
  })
13
13
 
14
14
  console.log('Done.')
@@ -35,5 +35,5 @@ const run = async (command, args, options) => {
35
35
 
36
36
  module.exports = {
37
37
  run,
38
- runSync
38
+ runSync,
39
39
  }
@@ -0,0 +1,44 @@
1
+ const { runSync } = require('./run')
2
+
3
+ /**
4
+ *
5
+ * @param {string} treeName
6
+ * @example '@toptal/davinci-engine@7.5.2'
7
+ * @returns {Array} Pair package name and version, ex. ['@toptal/davinci-engine', '16.0.2']
8
+ */
9
+ const splitNameAndVersion = treeName => {
10
+ const atPos = treeName.lastIndexOf('@')
11
+
12
+ return [treeName.slice(0, atPos), treeName.slice(atPos + 1)]
13
+ }
14
+
15
+ const list = packageName => {
16
+ const { stdout } = runSync(
17
+ 'yarn',
18
+ [
19
+ 'list',
20
+ '--json',
21
+ '--no-progress',
22
+ '--non-interactive',
23
+ '--depth=0',
24
+ '--pattern',
25
+ packageName,
26
+ ],
27
+ {
28
+ stdio: undefined,
29
+ }
30
+ )
31
+
32
+ const listInfo = JSON.parse(stdout)
33
+ const packagesFound = listInfo?.data?.trees || []
34
+
35
+ if (packagesFound.length <= 0) {
36
+ return new Map()
37
+ }
38
+
39
+ return new Map(packagesFound.map(pkg => splitNameAndVersion(pkg.name)))
40
+ }
41
+
42
+ module.exports = {
43
+ list,
44
+ }