util.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import https from 'https'
  2. import { IncomingMessage } from 'http'
  3. import { spawnSync } from '../../helpers/spawn'
  4. import { sync as crossSpawnSync } from 'cross-spawn'
  5. import { appDir, resolve as appResolve } from '../../helpers/app-paths'
  6. import { existsSync } from 'fs'
  7. import semver from 'semver'
  8. const BASE_URL = 'https://docs.rs/crate/'
  9. async function useYarn(): Promise<boolean> {
  10. const hasYarnLockfile = existsSync(appResolve.app('yarn.lock'))
  11. if (hasYarnLockfile) {
  12. return true
  13. } else {
  14. return await new Promise((resolve) => {
  15. const child = crossSpawnSync('npm', ['--version'])
  16. resolve(!!(child.status ?? child.error))
  17. })
  18. }
  19. }
  20. async function getCrateLatestVersion(crateName: string): Promise<string> {
  21. return await new Promise((resolve, reject) => {
  22. const url = `${BASE_URL}${crateName}`
  23. https.get(url, (res: IncomingMessage) => {
  24. if (res.statusCode !== 302 || !res.headers.location) {
  25. reject(res)
  26. } else {
  27. const version = res.headers.location.replace(url + '/', '')
  28. resolve(version)
  29. }
  30. })
  31. })
  32. }
  33. async function getNpmLatestVersion(packageName: string): Promise<string> {
  34. if (await useYarn()) {
  35. const child = crossSpawnSync(
  36. 'yarn',
  37. ['info', packageName, 'versions', '--json'],
  38. {
  39. cwd: appDir
  40. }
  41. )
  42. const output = String(child.output[1])
  43. const packageJson = JSON.parse(output) as { data: string[] }
  44. return packageJson.data[packageJson.data.length - 1]
  45. } else {
  46. const child = crossSpawnSync('npm', ['show', packageName, 'version'], {
  47. cwd: appDir
  48. })
  49. return String(child.output[1]).replace('\n', '')
  50. }
  51. }
  52. async function getNpmPackageVersion(
  53. packageName: string
  54. ): Promise<string | null> {
  55. const child = (await useYarn())
  56. ? crossSpawnSync(
  57. 'yarn',
  58. ['list', '--patern', packageName, '--depth', '0'],
  59. {
  60. cwd: appDir
  61. }
  62. )
  63. : crossSpawnSync('npm', ['list', packageName, 'version', '--depth', '0'], {
  64. cwd: appDir
  65. })
  66. const output = String(child.output[1])
  67. // eslint-disable-next-line security/detect-non-literal-regexp
  68. const matches = new RegExp(packageName + '@(\\S+)', 'g').exec(output)
  69. if (matches?.[1]) {
  70. return matches[1]
  71. } else {
  72. return null
  73. }
  74. }
  75. async function installNpmPackage(packageName: string): Promise<void> {
  76. if (await useYarn()) {
  77. spawnSync('yarn', ['add', packageName], appDir)
  78. } else {
  79. spawnSync('npm', ['install', packageName], appDir)
  80. }
  81. }
  82. async function installNpmDevPackage(packageName: string): Promise<void> {
  83. if (await useYarn()) {
  84. spawnSync('yarn', ['add', packageName, '--dev'], appDir)
  85. } else {
  86. spawnSync('npm', ['install', packageName, '--save-dev'], appDir)
  87. }
  88. }
  89. function updateNpmPackage(packageName: string): void {
  90. const usesYarn = existsSync(appResolve.app('yarn.lock'))
  91. if (usesYarn) {
  92. spawnSync('yarn', ['upgrade', packageName, '--latest'], appDir)
  93. } else {
  94. spawnSync('npm', ['install', `${packageName}@latest`], appDir)
  95. }
  96. }
  97. function padVersion(version: string): string {
  98. let count = (version.match(/\./g) ?? []).length
  99. while (count < 2) {
  100. count++
  101. version += '.0'
  102. }
  103. return version
  104. }
  105. function semverLt(first: string, second: string): boolean {
  106. return semver.lt(padVersion(first), padVersion(second))
  107. }
  108. export {
  109. getCrateLatestVersion,
  110. getNpmLatestVersion,
  111. getNpmPackageVersion,
  112. installNpmPackage,
  113. installNpmDevPackage,
  114. updateNpmPackage,
  115. padVersion,
  116. semverLt
  117. }