| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | #!/usr/bin/env node | 1 | #!/usr/bin/env node |
| 2 | // autofmt v1 by paper clover | 2 | // autofmt v2 by paper clover |
| 3 | // https://paperclover.dev/nix/config/src/branch/main/packages/autofmt/autofmt.js | 3 | // https://paperclover.dev/nix/config/src/branch/main/packages/autofmt/autofmt.js |
| 4 | // | 4 | // |
| 5 | // Different codebases use different formatters. Autofmt looks for project | 5 | // Different codebases use different formatters. Autofmt looks for project |
| ... | @@ -25,6 +25,10 @@ | ... | @@ -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 | // @ts-nocheck | 32 | // @ts-nocheck |
| 29 | | 33 | |
| 30 | // -- definitions -- | 34 | // -- definitions -- |
| ... | @@ -72,6 +76,15 @@ const formatters = { | ... | @@ -72,6 +76,15 @@ const formatters = { |
| 72 | cmd: ["deno", "fmt", "--", "$files"], | 76 | cmd: ["deno", "fmt", "--", "$files"], |
| 73 | stdin: (file) => ["deno", "fmt", "--ext", path.extname(file).slice(1), "-"], | 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 | prettier: { | 88 | prettier: { |
| 76 | languages: ["javascript", "markdown", "json", "yaml", "mdx", "html", "css"], | 89 | languages: ["javascript", "markdown", "json", "yaml", "mdx", "html", "css"], |
| 77 | files: ["node_modules/.bin/prettier"], | 90 | files: ["node_modules/.bin/prettier"], |
| ... | @@ -91,7 +104,7 @@ const formatters = { | ... | @@ -91,7 +104,7 @@ const formatters = { |
| 91 | "nixfmt-rfc-style": { | 104 | "nixfmt-rfc-style": { |
| 92 | languages: ["nix"], | 105 | languages: ["nix"], |
| 93 | files: { | 106 | files: { |
| 94 | "flake.nix": (contents) => contents.includes("nixfmt"), | 107 | "flake.nix": ({ text }) => text.includes("nixfmt"), |
| 95 | }, | 108 | }, |
| 96 | cmd: ["nixfmt", "--", "$files"], | 109 | cmd: ["nixfmt", "--", "$files"], |
| 97 | stdin: (file) => ["nixfmt", `--filename=${file}`], | 110 | stdin: (file) => ["nixfmt", `--filename=${file}`], |
| ... | @@ -99,7 +112,7 @@ const formatters = { | ... | @@ -99,7 +112,7 @@ const formatters = { |
| 99 | alejandra: { | 112 | alejandra: { |
| 100 | languages: ["nix"], | 113 | languages: ["nix"], |
| 101 | files: { | 114 | files: { |
| 102 | "flake.nix": (contents) => contents.includes("alejandra"), | 115 | "flake.nix": ({ text }) => text.includes("alejandra"), |
| 103 | }, | 116 | }, |
| 104 | cmd: ["alejandra", "--", "$files"], | 117 | cmd: ["alejandra", "--", "$files"], |
| 105 | stdin: () => ["alejandra"], | 118 | stdin: () => ["alejandra"], |
| ... | @@ -498,24 +511,31 @@ function pickFormatter(file) { | ... | @@ -498,24 +511,31 @@ function pickFormatter(file) { |
| 498 | return walkUp(dir, (x) => { | 511 | return walkUp(dir, (x) => { |
| 499 | const children = readDir(x); | 512 | const children = readDir(x); |
| 500 | for (const fmt of order) { | 513 | for (const fmt of order) { |
| | 514 | if (formatters[fmt][stdio ? "stdin" : "cmd"] == null) continue; |
| | 515 | |
| 501 | let matches = false; | 516 | let matches = false; |
| 502 | if (formatters[fmt].files === true) { | 517 | if (formatters[fmt].files === true) { |
| 503 | matches = true; | 518 | matches = true; |
| 504 | } | 519 | } |
| 505 | if (!matches) { | 520 | if (!matches) { |
| 506 | const filesToCheck = Array.isArray(formatters[fmt].files) | 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 | : Object.entries(formatters[fmt].files) | 523 | : Object.entries(formatters[fmt].files) |
| 509 | .map(([base, contents]) => ({ base, contents })); | 524 | .map(([base, check]) => ({ base, check })); |
| 510 | for (const { base, contents } of filesToCheck) { | 525 | for (const { base, check } of filesToCheck) { |
| 511 | if (base.includes("/")) { | 526 | if (base.includes("/")) { |
| 512 | matches = readDir(path.join(x, path.dirname(base))) // | 527 | matches = readDir(path.join(x, path.dirname(base))) // |
| 513 | .includes(path.basename(base)); | 528 | .includes(path.basename(base)); |
| 514 | } else { | 529 | } else { |
| 515 | matches = children.includes(base); | 530 | matches = children.includes(base); |
| 516 | } | 531 | } |
| 517 | if (matches && typeof contents === "function") { | 532 | if (matches && typeof check === "function") { |
| 518 | matches = !!contents(fs.readFileSync(path.join(x, base), "utf-8")); | 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,7 +546,7 @@ function pickFormatter(file) { |
| 526 | return formatterId; | 546 | return formatterId; |
| 527 | } | 547 | } |
| 528 | } | 548 | } |
| 529 | }) ?? possible[0]; | 549 | }) ?? possible.find((fmt) => !formatters[fmt].mustMatchFile); |
| 530 | } | 550 | } |
| 531 | | 551 | |
| 532 | /** @param dir {string} @param find {(x: string) => any} */ | 552 | /** @param dir {string} @param find {(x: string) => any} */ |
| ... | @@ -581,6 +601,29 @@ function readGitIgnore(dir) { | ... | @@ -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 | function escapeGlob(str) { | 627 | function escapeGlob(str) { |
| 585 | return str.replace(/[\\*,{}]/g, "\\$&"); | 628 | return str.replace(/[\\*,{}]/g, "\\$&"); |
| 586 | } | 629 | } |