utils.js 2.5 KB

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