|
|
@@ -1,40 +1,40 @@
|
|
|
import { text } from "node:stream/consumers"
|
|
|
-import { BunProc } from "../bun"
|
|
|
import { Instance } from "../project/instance"
|
|
|
import { Filesystem } from "../util/filesystem"
|
|
|
import { Process } from "../util/process"
|
|
|
import { which } from "../util/which"
|
|
|
import { Flag } from "@/flag/flag"
|
|
|
+import { Npm } from "@/npm"
|
|
|
|
|
|
export interface Info {
|
|
|
name: string
|
|
|
- command: string[]
|
|
|
environment?: Record<string, string>
|
|
|
extensions: string[]
|
|
|
- enabled(): Promise<boolean>
|
|
|
+ enabled(): Promise<string[] | false>
|
|
|
}
|
|
|
|
|
|
export const gofmt: Info = {
|
|
|
name: "gofmt",
|
|
|
- command: ["gofmt", "-w", "$FILE"],
|
|
|
extensions: [".go"],
|
|
|
async enabled() {
|
|
|
- return which("gofmt") !== null
|
|
|
+ const p = which("gofmt")
|
|
|
+ if (p === null) return false
|
|
|
+ return [p, "-w", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const mix: Info = {
|
|
|
name: "mix",
|
|
|
- command: ["mix", "format", "$FILE"],
|
|
|
extensions: [".ex", ".exs", ".eex", ".heex", ".leex", ".neex", ".sface"],
|
|
|
async enabled() {
|
|
|
- return which("mix") !== null
|
|
|
+ const p = which("mix")
|
|
|
+ if (p === null) return false
|
|
|
+ return [p, "format", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const prettier: Info = {
|
|
|
name: "prettier",
|
|
|
- command: [BunProc.which(), "x", "prettier", "--write", "$FILE"],
|
|
|
environment: {
|
|
|
BUN_BE_BUN: "1",
|
|
|
},
|
|
|
@@ -73,8 +73,9 @@ export const prettier: Info = {
|
|
|
dependencies?: Record<string, string>
|
|
|
devDependencies?: Record<string, string>
|
|
|
}>(item)
|
|
|
- if (json.dependencies?.prettier) return true
|
|
|
- if (json.devDependencies?.prettier) return true
|
|
|
+ if (json.dependencies?.prettier || json.devDependencies?.prettier) {
|
|
|
+ return [await Npm.which("prettier"), "--write", "$FILE"]
|
|
|
+ }
|
|
|
}
|
|
|
return false
|
|
|
},
|
|
|
@@ -82,7 +83,6 @@ export const prettier: Info = {
|
|
|
|
|
|
export const oxfmt: Info = {
|
|
|
name: "oxfmt",
|
|
|
- command: [BunProc.which(), "x", "oxfmt", "$FILE"],
|
|
|
environment: {
|
|
|
BUN_BE_BUN: "1",
|
|
|
},
|
|
|
@@ -95,8 +95,9 @@ export const oxfmt: Info = {
|
|
|
dependencies?: Record<string, string>
|
|
|
devDependencies?: Record<string, string>
|
|
|
}>(item)
|
|
|
- if (json.dependencies?.oxfmt) return true
|
|
|
- if (json.devDependencies?.oxfmt) return true
|
|
|
+ if (json.dependencies?.oxfmt || json.devDependencies?.oxfmt) {
|
|
|
+ return [await Npm.which("oxfmt"), "$FILE"]
|
|
|
+ }
|
|
|
}
|
|
|
return false
|
|
|
},
|
|
|
@@ -104,7 +105,6 @@ export const oxfmt: Info = {
|
|
|
|
|
|
export const biome: Info = {
|
|
|
name: "biome",
|
|
|
- command: [BunProc.which(), "x", "@biomejs/biome", "check", "--write", "$FILE"],
|
|
|
environment: {
|
|
|
BUN_BE_BUN: "1",
|
|
|
},
|
|
|
@@ -141,7 +141,7 @@ export const biome: Info = {
|
|
|
for (const config of configs) {
|
|
|
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
|
|
|
if (found.length > 0) {
|
|
|
- return true
|
|
|
+ return [await Npm.which("@biomejs/biome"), "check", "--write", "$FILE"]
|
|
|
}
|
|
|
}
|
|
|
return false
|
|
|
@@ -150,47 +150,49 @@ export const biome: Info = {
|
|
|
|
|
|
export const zig: Info = {
|
|
|
name: "zig",
|
|
|
- command: ["zig", "fmt", "$FILE"],
|
|
|
extensions: [".zig", ".zon"],
|
|
|
async enabled() {
|
|
|
- return which("zig") !== null
|
|
|
+ const p = which("zig")
|
|
|
+ if (p === null) return false
|
|
|
+ return [p, "fmt", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const clang: Info = {
|
|
|
name: "clang-format",
|
|
|
- command: ["clang-format", "-i", "$FILE"],
|
|
|
extensions: [".c", ".cc", ".cpp", ".cxx", ".c++", ".h", ".hh", ".hpp", ".hxx", ".h++", ".ino", ".C", ".H"],
|
|
|
async enabled() {
|
|
|
const items = await Filesystem.findUp(".clang-format", Instance.directory, Instance.worktree)
|
|
|
- return items.length > 0
|
|
|
+ if (items.length === 0) return false
|
|
|
+ return ["clang-format", "-i", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const ktlint: Info = {
|
|
|
name: "ktlint",
|
|
|
- command: ["ktlint", "-F", "$FILE"],
|
|
|
extensions: [".kt", ".kts"],
|
|
|
async enabled() {
|
|
|
- return which("ktlint") !== null
|
|
|
+ const p = which("ktlint")
|
|
|
+ if (p === null) return false
|
|
|
+ return [p, "-F", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const ruff: Info = {
|
|
|
name: "ruff",
|
|
|
- command: ["ruff", "format", "$FILE"],
|
|
|
extensions: [".py", ".pyi"],
|
|
|
async enabled() {
|
|
|
- if (!which("ruff")) return false
|
|
|
+ const p = which("ruff")
|
|
|
+ if (p === null) return false
|
|
|
const configs = ["pyproject.toml", "ruff.toml", ".ruff.toml"]
|
|
|
for (const config of configs) {
|
|
|
const found = await Filesystem.findUp(config, Instance.directory, Instance.worktree)
|
|
|
if (found.length > 0) {
|
|
|
if (config === "pyproject.toml") {
|
|
|
const content = await Filesystem.readText(found[0])
|
|
|
- if (content.includes("[tool.ruff]")) return true
|
|
|
+ if (content.includes("[tool.ruff]")) return [p, "format", "$FILE"]
|
|
|
} else {
|
|
|
- return true
|
|
|
+ return [p, "format", "$FILE"]
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -199,7 +201,7 @@ export const ruff: Info = {
|
|
|
const found = await Filesystem.findUp(dep, Instance.directory, Instance.worktree)
|
|
|
if (found.length > 0) {
|
|
|
const content = await Filesystem.readText(found[0])
|
|
|
- if (content.includes("ruff")) return true
|
|
|
+ if (content.includes("ruff")) return [p, "format", "$FILE"]
|
|
|
}
|
|
|
}
|
|
|
return false
|
|
|
@@ -208,14 +210,13 @@ export const ruff: Info = {
|
|
|
|
|
|
export const rlang: Info = {
|
|
|
name: "air",
|
|
|
- command: ["air", "format", "$FILE"],
|
|
|
extensions: [".R"],
|
|
|
async enabled() {
|
|
|
const airPath = which("air")
|
|
|
if (airPath == null) return false
|
|
|
|
|
|
try {
|
|
|
- const proc = Process.spawn(["air", "--help"], {
|
|
|
+ const proc = Process.spawn([airPath, "--help"], {
|
|
|
stdout: "pipe",
|
|
|
stderr: "pipe",
|
|
|
})
|
|
|
@@ -227,7 +228,10 @@ export const rlang: Info = {
|
|
|
const firstLine = output.split("\n")[0]
|
|
|
const hasR = firstLine.includes("R language")
|
|
|
const hasFormatter = firstLine.includes("formatter")
|
|
|
- return hasR && hasFormatter
|
|
|
+ if (hasR && hasFormatter) {
|
|
|
+ return [airPath, "format", "$FILE"]
|
|
|
+ }
|
|
|
+ return false
|
|
|
} catch (error) {
|
|
|
return false
|
|
|
}
|
|
|
@@ -236,14 +240,14 @@ export const rlang: Info = {
|
|
|
|
|
|
export const uvformat: Info = {
|
|
|
name: "uv",
|
|
|
- command: ["uv", "format", "--", "$FILE"],
|
|
|
extensions: [".py", ".pyi"],
|
|
|
async enabled() {
|
|
|
if (await ruff.enabled()) return false
|
|
|
- if (which("uv") !== null) {
|
|
|
- const proc = Process.spawn(["uv", "format", "--help"], { stderr: "pipe", stdout: "pipe" })
|
|
|
+ const uvPath = which("uv")
|
|
|
+ if (uvPath !== null) {
|
|
|
+ const proc = Process.spawn([uvPath, "format", "--help"], { stderr: "pipe", stdout: "pipe" })
|
|
|
const code = await proc.exited
|
|
|
- return code === 0
|
|
|
+ if (code === 0) return [uvPath, "format", "--", "$FILE"]
|
|
|
}
|
|
|
return false
|
|
|
},
|
|
|
@@ -251,108 +255,118 @@ export const uvformat: Info = {
|
|
|
|
|
|
export const rubocop: Info = {
|
|
|
name: "rubocop",
|
|
|
- command: ["rubocop", "--autocorrect", "$FILE"],
|
|
|
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
|
|
async enabled() {
|
|
|
- return which("rubocop") !== null
|
|
|
+ const path = which("rubocop")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "--autocorrect", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const standardrb: Info = {
|
|
|
name: "standardrb",
|
|
|
- command: ["standardrb", "--fix", "$FILE"],
|
|
|
extensions: [".rb", ".rake", ".gemspec", ".ru"],
|
|
|
async enabled() {
|
|
|
- return which("standardrb") !== null
|
|
|
+ const path = which("standardrb")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "--fix", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const htmlbeautifier: Info = {
|
|
|
name: "htmlbeautifier",
|
|
|
- command: ["htmlbeautifier", "$FILE"],
|
|
|
extensions: [".erb", ".html.erb"],
|
|
|
async enabled() {
|
|
|
- return which("htmlbeautifier") !== null
|
|
|
+ const path = which("htmlbeautifier")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const dart: Info = {
|
|
|
name: "dart",
|
|
|
- command: ["dart", "format", "$FILE"],
|
|
|
extensions: [".dart"],
|
|
|
async enabled() {
|
|
|
- return which("dart") !== null
|
|
|
+ const path = which("dart")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "format", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const ocamlformat: Info = {
|
|
|
name: "ocamlformat",
|
|
|
- command: ["ocamlformat", "-i", "$FILE"],
|
|
|
extensions: [".ml", ".mli"],
|
|
|
async enabled() {
|
|
|
- if (!which("ocamlformat")) return false
|
|
|
+ const path = which("ocamlformat")
|
|
|
+ if (!path) return false
|
|
|
const items = await Filesystem.findUp(".ocamlformat", Instance.directory, Instance.worktree)
|
|
|
- return items.length > 0
|
|
|
+ if (items.length === 0) return false
|
|
|
+ return [path, "-i", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const terraform: Info = {
|
|
|
name: "terraform",
|
|
|
- command: ["terraform", "fmt", "$FILE"],
|
|
|
extensions: [".tf", ".tfvars"],
|
|
|
async enabled() {
|
|
|
- return which("terraform") !== null
|
|
|
+ const path = which("terraform")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "fmt", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const latexindent: Info = {
|
|
|
name: "latexindent",
|
|
|
- command: ["latexindent", "-w", "-s", "$FILE"],
|
|
|
extensions: [".tex"],
|
|
|
async enabled() {
|
|
|
- return which("latexindent") !== null
|
|
|
+ const path = which("latexindent")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "-w", "-s", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const gleam: Info = {
|
|
|
name: "gleam",
|
|
|
- command: ["gleam", "format", "$FILE"],
|
|
|
extensions: [".gleam"],
|
|
|
async enabled() {
|
|
|
- return which("gleam") !== null
|
|
|
+ const path = which("gleam")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "format", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const shfmt: Info = {
|
|
|
name: "shfmt",
|
|
|
- command: ["shfmt", "-w", "$FILE"],
|
|
|
extensions: [".sh", ".bash"],
|
|
|
async enabled() {
|
|
|
- return which("shfmt") !== null
|
|
|
+ const path = which("shfmt")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "-w", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const nixfmt: Info = {
|
|
|
name: "nixfmt",
|
|
|
- command: ["nixfmt", "$FILE"],
|
|
|
extensions: [".nix"],
|
|
|
async enabled() {
|
|
|
- return which("nixfmt") !== null
|
|
|
+ const path = which("nixfmt")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const rustfmt: Info = {
|
|
|
name: "rustfmt",
|
|
|
- command: ["rustfmt", "$FILE"],
|
|
|
extensions: [".rs"],
|
|
|
async enabled() {
|
|
|
- return which("rustfmt") !== null
|
|
|
+ const path = which("rustfmt")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const pint: Info = {
|
|
|
name: "pint",
|
|
|
- command: ["./vendor/bin/pint", "$FILE"],
|
|
|
extensions: [".php"],
|
|
|
async enabled() {
|
|
|
const items = await Filesystem.findUp("composer.json", Instance.directory, Instance.worktree)
|
|
|
@@ -361,8 +375,9 @@ export const pint: Info = {
|
|
|
require?: Record<string, string>
|
|
|
"require-dev"?: Record<string, string>
|
|
|
}>(item)
|
|
|
- if (json.require?.["laravel/pint"]) return true
|
|
|
- if (json["require-dev"]?.["laravel/pint"]) return true
|
|
|
+ if (json.require?.["laravel/pint"] || json["require-dev"]?.["laravel/pint"]) {
|
|
|
+ return ["./vendor/bin/pint", "$FILE"]
|
|
|
+ }
|
|
|
}
|
|
|
return false
|
|
|
},
|
|
|
@@ -370,27 +385,30 @@ export const pint: Info = {
|
|
|
|
|
|
export const ormolu: Info = {
|
|
|
name: "ormolu",
|
|
|
- command: ["ormolu", "-i", "$FILE"],
|
|
|
extensions: [".hs"],
|
|
|
async enabled() {
|
|
|
- return which("ormolu") !== null
|
|
|
+ const path = which("ormolu")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "-i", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const cljfmt: Info = {
|
|
|
name: "cljfmt",
|
|
|
- command: ["cljfmt", "fix", "--quiet", "$FILE"],
|
|
|
extensions: [".clj", ".cljs", ".cljc", ".edn"],
|
|
|
async enabled() {
|
|
|
- return which("cljfmt") !== null
|
|
|
+ const path = which("cljfmt")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "fix", "--quiet", "$FILE"]
|
|
|
},
|
|
|
}
|
|
|
|
|
|
export const dfmt: Info = {
|
|
|
name: "dfmt",
|
|
|
- command: ["dfmt", "-i", "$FILE"],
|
|
|
extensions: [".d"],
|
|
|
async enabled() {
|
|
|
- return which("dfmt") !== null
|
|
|
+ const path = which("dfmt")
|
|
|
+ if (path === null) return false
|
|
|
+ return [path, "-i", "$FILE"]
|
|
|
},
|
|
|
}
|