| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- import { App } from "../app/app"
- import { BunProc } from "../bun"
- import { Config } from "../config/config"
- import { Log } from "../util/log"
- import path from "path"
- export namespace Format {
- const log = Log.create({ service: "format" })
- const state = App.state("format", async () => {
- const hooks: Record<string, Hook[]> = {}
- for (const item of FORMATTERS) {
- if (await item.enabled()) {
- for (const ext of item.extensions) {
- const list = hooks[ext] ?? []
- list.push({
- command: item.command,
- environment: item.environment,
- })
- hooks[ext] = list
- }
- }
- }
- const cfg = await Config.get()
- for (const [file, items] of Object.entries(
- cfg.experimental?.hook?.file_edited ?? {},
- )) {
- for (const item of items) {
- const list = hooks[file] ?? []
- list.push({
- command: item.command,
- environment: item.environment,
- })
- hooks[file] = list
- }
- }
- return {
- hooks,
- }
- })
- export async function run(file: string) {
- log.info("formatting", { file })
- const { hooks } = await state()
- const ext = path.extname(file)
- const match = hooks[ext]
- if (!match) return
- for (const item of match) {
- log.info("running", { command: item.command })
- const proc = Bun.spawn({
- cmd: item.command.map((x) => x.replace("$FILE", file)),
- cwd: App.info().path.cwd,
- env: item.environment,
- stdout: "ignore",
- stderr: "ignore",
- })
- const exit = await proc.exited
- if (exit !== 0)
- log.error("failed", {
- command: item.command,
- ...item.environment,
- })
- }
- }
- interface Hook {
- command: string[]
- environment?: Record<string, string>
- }
- interface Native {
- name: string
- command: string[]
- environment?: Record<string, string>
- extensions: string[]
- enabled(): Promise<boolean>
- }
- const FORMATTERS: Native[] = [
- {
- name: "prettier",
- command: [BunProc.which(), "run", "prettier", "--write", "$FILE"],
- environment: {
- BUN_BE_BUN: "1",
- },
- extensions: [
- ".js",
- ".jsx",
- ".mjs",
- ".cjs",
- ".ts",
- ".tsx",
- ".mts",
- ".cts",
- ".html",
- ".htm",
- ".css",
- ".scss",
- ".sass",
- ".less",
- ".vue",
- ".svelte",
- ".json",
- ".jsonc",
- ".yaml",
- ".yml",
- ".toml",
- ".xml",
- ".md",
- ".mdx",
- ".graphql",
- ".gql",
- ],
- async enabled() {
- try {
- const proc = Bun.spawn({
- cmd: [BunProc.which(), "run", "prettier", "--version"],
- cwd: App.info().path.cwd,
- env: {
- BUN_BE_BUN: "1",
- },
- stdout: "ignore",
- stderr: "ignore",
- })
- const exit = await proc.exited
- return exit === 0
- } catch {
- return false
- }
- },
- },
- ]
- }
|