feat: support 'prettierd' in autofmt

prettierd is a daemon for prettier, allowing lower latency formats
see https://github.com/fsouza/prettierd
This commit is contained in:
clover caruso 2025-08-21 01:07:36 -07:00
parent 0a5d9bfc17
commit 1052a1ccc3
2 changed files with 55 additions and 11 deletions

View file

@ -1,5 +1,5 @@
#!/usr/bin/env node
// autofmt v1 by paper clover
// autofmt v2 by paper clover
// https://paperclover.dev/nix/config/src/branch/main/packages/autofmt/autofmt.js
//
// Different codebases use different formatters. Autofmt looks for project
@ -25,6 +25,10 @@
// }
// },
//
// CHANGELOG
// v2: added 'prettierd' as a supported formatter option.
// v1: initial release
//
// @ts-nocheck
// -- definitions --
@ -72,6 +76,15 @@ const formatters = {
cmd: ["deno", "fmt", "--", "$files"],
stdin: (file) => ["deno", "fmt", "--ext", path.extname(file).slice(1), "-"],
},
prettierd: {
// keep in mind that pretterd never exits.
// https://github.com/fsouza/prettierd/issues/645
languages: ["javascript", "markdown", "json", "yaml", "mdx", "html", "css"],
mustMatchFile: true,
files: { "node_modules/.bin/prettier": () => which("prettierd") },
cmd: null,
stdin: (file) => ["prettierd", file],
},
prettier: {
languages: ["javascript", "markdown", "json", "yaml", "mdx", "html", "css"],
files: ["node_modules/.bin/prettier"],
@ -91,7 +104,7 @@ const formatters = {
"nixfmt-rfc-style": {
languages: ["nix"],
files: {
"flake.nix": (contents) => contents.includes("nixfmt"),
"flake.nix": ({ text }) => text.includes("nixfmt"),
},
cmd: ["nixfmt", "--", "$files"],
stdin: (file) => ["nixfmt", `--filename=${file}`],
@ -99,7 +112,7 @@ const formatters = {
alejandra: {
languages: ["nix"],
files: {
"flake.nix": (contents) => contents.includes("alejandra"),
"flake.nix": ({ text }) => text.includes("alejandra"),
},
cmd: ["alejandra", "--", "$files"],
stdin: () => ["alejandra"],
@ -498,24 +511,31 @@ function pickFormatter(file) {
return walkUp(dir, (x) => {
const children = readDir(x);
for (const fmt of order) {
if (formatters[fmt][stdio ? "stdin" : "cmd"] == null) continue;
let matches = false;
if (formatters[fmt].files === true) {
matches = true;
}
if (!matches) {
const filesToCheck = Array.isArray(formatters[fmt].files)
? formatters[fmt].files.map((base) => ({ base, contents: true }))
? formatters[fmt].files.map((base) => ({ base, check: true }))
: Object.entries(formatters[fmt].files)
.map(([base, contents]) => ({ base, contents }));
for (const { base, contents } of filesToCheck) {
.map(([base, check]) => ({ base, check }));
for (const { base, check } of filesToCheck) {
if (base.includes("/")) {
matches = readDir(path.join(x, path.dirname(base))) //
.includes(path.basename(base));
} else {
matches = children.includes(base);
}
if (matches && typeof contents === "function") {
matches = !!contents(fs.readFileSync(path.join(x, base), "utf-8"));
if (matches && typeof check === "function") {
let text;
matches = !!check({
get text() {
return text ??= fs.readFileSync(path.join(x, base), "utf-8");
},
});
}
}
}
@ -526,7 +546,7 @@ function pickFormatter(file) {
return formatterId;
}
}
}) ?? possible[0];
}) ?? possible.find((fmt) => !formatters[fmt].mustMatchFile);
}
/** @param dir {string} @param find {(x: string) => any} */
@ -581,6 +601,29 @@ function readGitIgnore(dir) {
}
}
/** @param {string} name @returns {string | null} */
export function which(name) {
const paths =
process.env.PATH?.split(process.platform === "win32" ? ";" : ":") ?? [];
const exts = process.platform === "win32"
? (process.env.PATHEXT?.split(";") ?? [".exe", ".cmd", ".bat", ".com"])
: [""];
for (const dir of paths) {
if (!dir) continue;
try {
const entries = readDir(dir);
for (const ext of exts) {
const target = name + ext;
if (entries.includes(target)) {
return dir + sep + target;
}
}
} catch {}
}
return null;
}
function escapeGlob(str) {
return str.replace(/[\\*,{}]/g, "\\$&");
}

View file

@ -3,12 +3,13 @@ pkgs.writeShellApplication {
name = "autofmt";
runtimeInputs = with pkgs; [
# include only a couple of formatters by default
clang-tools
deno
nixfmt-rfc-style
dprint
nixfmt-rfc-style
prettierd # autofmt only runs on a local build of prettier
rustfmt
zig
clang-tools
];
text = ''exec ${pkgs.nodejs}/bin/node ${./autofmt.js} "$@"'';
}