index.ts 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { App } from "../app/app"
  2. import { Bus } from "../bus"
  3. import { File } from "../file"
  4. import { Log } from "../util/log"
  5. import path from "path"
  6. import * as Formatter from "./formatter"
  7. export namespace Format {
  8. const log = Log.create({ service: "format" })
  9. const state = App.state("format", () => {
  10. const enabled: Record<string, boolean> = {}
  11. return {
  12. enabled,
  13. }
  14. })
  15. async function isEnabled(item: Formatter.Info) {
  16. const s = state()
  17. let status = s.enabled[item.name]
  18. if (status === undefined) {
  19. status = await item.enabled()
  20. s.enabled[item.name] = status
  21. }
  22. return status
  23. }
  24. async function getFormatter(ext: string) {
  25. const result = []
  26. for (const item of Object.values(Formatter)) {
  27. if (!item.extensions.includes(ext)) continue
  28. if (!isEnabled(item)) continue
  29. result.push(item)
  30. }
  31. return result
  32. }
  33. export function init() {
  34. log.info("init")
  35. Bus.subscribe(File.Event.Edited, async (payload) => {
  36. const file = payload.properties.file
  37. log.info("formatting", { file })
  38. const ext = path.extname(file)
  39. for (const item of await getFormatter(ext)) {
  40. log.info("running", { command: item.command })
  41. const proc = Bun.spawn({
  42. cmd: item.command.map((x) => x.replace("$FILE", file)),
  43. cwd: App.info().path.cwd,
  44. env: item.environment,
  45. stdout: "ignore",
  46. stderr: "ignore",
  47. })
  48. const exit = await proc.exited
  49. if (exit !== 0)
  50. log.error("failed", {
  51. command: item.command,
  52. ...item.environment,
  53. })
  54. }
  55. })
  56. }
  57. }