| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | #!/usr/bin/env node |
| 2 | | // autofmt v1 by paper clover |
| 2 | // autofmt v2 by paper clover |
| 3 | 3 | // https://paperclover.dev/nix/config/src/branch/main/packages/autofmt/autofmt.js |
| 4 | 4 | // |
| 5 | 5 | // Different codebases use different formatters. Autofmt looks for project |
| ... | ... | @@ -25,6 +25,10 @@ |
| 25 | 25 | // } |
| 26 | 26 | // }, |
| 27 | 27 | // |
| 28 | // CHANGELOG |
| 29 | // v2: added 'prettierd' as a supported formatter option. |
| 30 | // v1: initial release |
| 31 | // |
| 28 | 32 | // @ts-nocheck |
| 29 | 33 | |
| 30 | 34 | // -- definitions -- |
| ... | ... | @@ -72,6 +76,15 @@ const formatters = { |
| 72 | 76 | cmd: ["deno", "fmt", "--", "$files"], |
| 73 | 77 | stdin: (file) => ["deno", "fmt", "--ext", path.extname(file).slice(1), "-"], |
| 74 | 78 | }, |
| 79 | prettierd: { |
| 80 | // keep in mind that pretterd never exits. |
| 81 | // https://github.com/fsouza/prettierd/issues/645 |
| 82 | languages: ["javascript", "markdown", "json", "yaml", "mdx", "html", "css"], |
| 83 | mustMatchFile: true, |
| 84 | files: { "node_modules/.bin/prettier": () => which("prettierd") }, |
| 85 | cmd: null, |
| 86 | stdin: (file) => ["prettierd", file], |
| 87 | }, |
| 75 | 88 | prettier: { |
| 76 | 89 | languages: ["javascript", "markdown", "json", "yaml", "mdx", "html", "css"], |
| 77 | 90 | files: ["node_modules/.bin/prettier"], |
| ... | ... | @@ -91,7 +104,7 @@ const formatters = { |
| 91 | 104 | "nixfmt-rfc-style": { |
| 92 | 105 | languages: ["nix"], |
| 93 | 106 | files: { |
| 94 | | "flake.nix": (contents) => contents.includes("nixfmt"), |
| 107 | "flake.nix": ({ text }) => text.includes("nixfmt"), |
| 95 | 108 | }, |
| 96 | 109 | cmd: ["nixfmt", "--", "$files"], |
| 97 | 110 | stdin: (file) => ["nixfmt", `--filename=${file}`], |
| ... | ... | @@ -99,7 +112,7 @@ const formatters = { |
| 99 | 112 | alejandra: { |
| 100 | 113 | languages: ["nix"], |
| 101 | 114 | files: { |
| 102 | | "flake.nix": (contents) => contents.includes("alejandra"), |
| 115 | "flake.nix": ({ text }) => text.includes("alejandra"), |
| 103 | 116 | }, |
| 104 | 117 | cmd: ["alejandra", "--", "$files"], |
| 105 | 118 | stdin: () => ["alejandra"], |
| ... | ... | @@ -498,24 +511,31 @@ function pickFormatter(file) { |
| 498 | 511 | return walkUp(dir, (x) => { |
| 499 | 512 | const children = readDir(x); |
| 500 | 513 | for (const fmt of order) { |
| 514 | if (formatters[fmt][stdio ? "stdin" : "cmd"] == null) continue; |
| 515 | |
| 501 | 516 | let matches = false; |
| 502 | 517 | if (formatters[fmt].files === true) { |
| 503 | 518 | matches = true; |
| 504 | 519 | } |
| 505 | 520 | if (!matches) { |
| 506 | 521 | const filesToCheck = Array.isArray(formatters[fmt].files) |
| 507 | | ? formatters[fmt].files.map((base) => ({ base, contents: true })) |
| 522 | ? formatters[fmt].files.map((base) => ({ base, check: true })) |
| 508 | 523 | : Object.entries(formatters[fmt].files) |
| 509 | | .map(([base, contents]) => ({ base, contents })); |
| 510 | | for (const { base, contents } of filesToCheck) { |
| 524 | .map(([base, check]) => ({ base, check })); |
| 525 | for (const { base, check } of filesToCheck) { |
| 511 | 526 | if (base.includes("/")) { |
| 512 | 527 | matches = readDir(path.join(x, path.dirname(base))) // |
| 513 | 528 | .includes(path.basename(base)); |
| 514 | 529 | } else { |
| 515 | 530 | matches = children.includes(base); |
| 516 | 531 | } |
| 517 | | if (matches && typeof contents === "function") { |
| 518 | | matches = !!contents(fs.readFileSync(path.join(x, base), "utf-8")); |
| 532 | if (matches && typeof check === "function") { |
| 533 | let text; |
| 534 | matches = !!check({ |
| 535 | get text() { |
| 536 | return text ??= fs.readFileSync(path.join(x, base), "utf-8"); |
| 537 | }, |
| 538 | }); |
| 519 | 539 | } |
| 520 | 540 | } |
| 521 | 541 | } |
| ... | ... | @@ -526,7 +546,7 @@ function pickFormatter(file) { |
| 526 | 546 | return formatterId; |
| 527 | 547 | } |
| 528 | 548 | } |
| 529 | | }) ?? possible[0]; |
| 549 | }) ?? possible.find((fmt) => !formatters[fmt].mustMatchFile); |
| 530 | 550 | } |
| 531 | 551 | |
| 532 | 552 | /** @param dir {string} @param find {(x: string) => any} */ |
| ... | ... | @@ -581,6 +601,29 @@ function readGitIgnore(dir) { |
| 581 | 601 | } |
| 582 | 602 | } |
| 583 | 603 | |
| 604 | /** @param {string} name @returns {string | null} */ |
| 605 | export function which(name) { |
| 606 | const paths = |
| 607 | process.env.PATH?.split(process.platform === "win32" ? ";" : ":") ?? []; |
| 608 | const exts = process.platform === "win32" |
| 609 | ? (process.env.PATHEXT?.split(";") ?? [".exe", ".cmd", ".bat", ".com"]) |
| 610 | : [""]; |
| 611 | |
| 612 | for (const dir of paths) { |
| 613 | if (!dir) continue; |
| 614 | try { |
| 615 | const entries = readDir(dir); |
| 616 | for (const ext of exts) { |
| 617 | const target = name + ext; |
| 618 | if (entries.includes(target)) { |
| 619 | return dir + sep + target; |
| 620 | } |
| 621 | } |
| 622 | } catch {} |
| 623 | } |
| 624 | return null; |
| 625 | } |
| 626 | |
| 584 | 627 | function escapeGlob(str) { |
| 585 | 628 | return str.replace(/[\\*,{}]/g, "\\$&"); |
| 586 | 629 | } |