diff --git a/packages/autofmt/autofmt.js b/packages/autofmt/autofmt.js index dc8481d..ef74cbf 100755 --- a/packages/autofmt/autofmt.js +++ b/packages/autofmt/autofmt.js @@ -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, "\\$&"); } diff --git a/packages/autofmt/default.nix b/packages/autofmt/default.nix index e46fbf6..fa006e3 100644 --- a/packages/autofmt/default.nix +++ b/packages/autofmt/default.nix @@ -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} "$@"''; }