utils.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // @ts-check
  2. import fs from 'node:fs'
  3. import pico from 'picocolors'
  4. import { createRequire } from 'node:module'
  5. import { spawn } from 'node:child_process'
  6. const require = createRequire(import.meta.url)
  7. export const targets = fs.readdirSync('packages').filter(f => {
  8. if (
  9. !fs.statSync(`packages/${f}`).isDirectory() ||
  10. !fs.existsSync(`packages/${f}/package.json`)
  11. ) {
  12. return false
  13. }
  14. const pkg = require(`../packages/${f}/package.json`)
  15. if (pkg.private && !pkg.buildOptions) {
  16. return false
  17. }
  18. return true
  19. })
  20. /**
  21. *
  22. * @param {ReadonlyArray<string>} partialTargets
  23. * @param {boolean | undefined} includeAllMatching
  24. */
  25. export function fuzzyMatchTarget(partialTargets, includeAllMatching) {
  26. /** @type {Array<string>} */
  27. const matched = []
  28. partialTargets.forEach(partialTarget => {
  29. for (const target of targets) {
  30. if (target.match(partialTarget)) {
  31. matched.push(target)
  32. if (!includeAllMatching) {
  33. break
  34. }
  35. }
  36. }
  37. })
  38. if (matched.length) {
  39. return matched
  40. } else {
  41. console.log()
  42. console.error(
  43. ` ${pico.white(pico.bgRed(' ERROR '))} ${pico.red(
  44. `Target ${pico.underline(partialTargets.toString())} not found!`,
  45. )}`,
  46. )
  47. console.log()
  48. process.exit(1)
  49. }
  50. }
  51. /**
  52. * @param {string} command
  53. * @param {ReadonlyArray<string>} args
  54. * @param {object} [options]
  55. */
  56. export async function exec(command, args, options) {
  57. return new Promise((resolve, reject) => {
  58. const _process = spawn(command, args, {
  59. stdio: [
  60. 'ignore', // stdin
  61. 'pipe', // stdout
  62. 'pipe', // stderr
  63. ],
  64. ...options,
  65. shell: process.platform === 'win32',
  66. })
  67. /**
  68. * @type {Buffer[]}
  69. */
  70. const stderrChunks = []
  71. /**
  72. * @type {Buffer[]}
  73. */
  74. const stdoutChunks = []
  75. _process.stderr?.on('data', chunk => {
  76. stderrChunks.push(chunk)
  77. })
  78. _process.stdout?.on('data', chunk => {
  79. stdoutChunks.push(chunk)
  80. })
  81. _process.on('error', error => {
  82. reject(error)
  83. })
  84. _process.on('exit', code => {
  85. const ok = code === 0
  86. const stderr = Buffer.concat(stderrChunks).toString().trim()
  87. const stdout = Buffer.concat(stdoutChunks).toString().trim()
  88. if (ok) {
  89. const result = { ok, code, stderr, stdout }
  90. resolve(result)
  91. } else {
  92. reject(
  93. new Error(
  94. `Failed to execute command: ${command} ${args.join(' ')}: ${stderr}`,
  95. ),
  96. )
  97. }
  98. })
  99. })
  100. }