upgrade-opentui.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #!/usr/bin/env bun
  2. import path from "node:path"
  3. const args = process.argv.slice(2)
  4. const usage = "Usage: bun run script/upgrade-opentui.ts [--snapshot] <version>"
  5. if (args.includes("--help") || args.includes("-h")) {
  6. console.log(usage)
  7. process.exit(0)
  8. }
  9. const snapshotArg = args.find((arg) => arg.startsWith("--snapshot="))
  10. const snapshot = args.includes("--snapshot") || snapshotArg !== undefined
  11. const unknown = args.find((arg) => arg.startsWith("-") && arg !== "--snapshot" && !arg.startsWith("--snapshot="))
  12. if (unknown) {
  13. console.error(`Unknown option: ${unknown}`)
  14. console.error(usage)
  15. process.exit(1)
  16. }
  17. const positional = args.filter((arg) => arg !== "--snapshot" && !arg.startsWith("--snapshot="))
  18. const raw = snapshotArg?.slice("--snapshot=".length) || positional[0]
  19. if (!raw || positional.length > (snapshotArg ? 0 : 1)) {
  20. console.error(usage)
  21. process.exit(1)
  22. }
  23. if (snapshotArg === "--snapshot=") {
  24. console.error("Missing snapshot version")
  25. console.error(usage)
  26. process.exit(1)
  27. }
  28. const ver = raw.replace(/^v/, "")
  29. const root = path.resolve(import.meta.dir, "..")
  30. const skip = new Set([".git", ".opencode", ".turbo", "dist", "node_modules"])
  31. const keys = ["@opentui/core", "@opentui/keymap", "@opentui/solid"] as const
  32. const files = (await Array.fromAsync(new Bun.Glob("**/package.json").scan({ cwd: root }))).filter(
  33. (file) => !file.split("/").some((part) => skip.has(part)),
  34. )
  35. const setVersion = (cur: string, kind: "dep" | "peer") => {
  36. if (cur === "catalog:" || cur.startsWith("workspace:")) return cur
  37. if (snapshot) return ver
  38. if (kind === "peer") return `>=${ver}`
  39. if (cur.startsWith(">=")) return `>=${ver}`
  40. if (cur.startsWith("^")) return `^${ver}`
  41. if (cur.startsWith("~")) return `~${ver}`
  42. return ver
  43. }
  44. const editDeps = (obj: unknown, kind: "dep" | "peer") => {
  45. if (!obj || typeof obj !== "object") return false
  46. const map = obj as Record<string, unknown>
  47. return keys
  48. .map((key) => {
  49. const cur = map[key]
  50. if (typeof cur !== "string") return false
  51. const next = setVersion(cur, kind)
  52. if (next === cur) return false
  53. map[key] = next
  54. return true
  55. })
  56. .some(Boolean)
  57. }
  58. const editCatalog = (obj: unknown) => {
  59. if (!obj || typeof obj !== "object") return false
  60. const map = obj as Record<string, unknown>
  61. return keys
  62. .map((key) => {
  63. const cur = map[key]
  64. if (typeof cur !== "string" || cur === ver) return false
  65. map[key] = ver
  66. return true
  67. })
  68. .some(Boolean)
  69. }
  70. const editOverrides = (obj: unknown) => {
  71. if (!obj || typeof obj !== "object") return false
  72. const map = obj as Record<string, unknown>
  73. return keys
  74. .map((key) => {
  75. const cur = map[key]
  76. if (typeof cur !== "string") return false
  77. const next = snapshot ? ver : "catalog:"
  78. if (next === cur) return false
  79. map[key] = next
  80. return true
  81. })
  82. .some(Boolean)
  83. }
  84. const out = (
  85. await Promise.all(
  86. files.map(async (rel) => {
  87. const file = path.join(root, rel)
  88. const txt = await Bun.file(file).text()
  89. const json = JSON.parse(txt)
  90. const hit = [
  91. editCatalog(json.workspaces?.catalog),
  92. editOverrides(json.overrides),
  93. editDeps(json.dependencies, "dep"),
  94. editDeps(json.devDependencies, "dep"),
  95. editDeps(json.peerDependencies, "peer"),
  96. ].some(Boolean)
  97. if (!hit) return null
  98. await Bun.write(file, `${JSON.stringify(json, null, 2)}\n`)
  99. return rel
  100. }),
  101. )
  102. ).filter((item): item is string => item !== null)
  103. if (out.length === 0) {
  104. console.log("No opentui deps found")
  105. process.exit(0)
  106. }
  107. console.log(`Updated opentui${snapshot ? " snapshot" : ""} to ${ver} in:`)
  108. for (const file of out) {
  109. console.log(`- ${file}`)
  110. }