├── .github └── workflows │ ├── ci.yml │ └── docs.yml ├── .gitignore ├── LICENSE ├── README.md ├── default.nix ├── docs ├── default.nix ├── man-pages.xml └── manual.xml ├── flake.lock ├── flake.nix ├── module.nix ├── renovate.json ├── templates ├── advanced │ └── flake.nix └── minimal │ └── flake.nix ├── tests ├── default.nix ├── module.nix ├── tool-test.nix └── tools │ ├── alejandra │ ├── default.nix │ └── files │ │ ├── invalid.nix.raw │ │ └── valid.nix.raw │ ├── deadnix │ ├── default.nix │ ├── files │ │ ├── invalid.nix.raw │ │ └── valid.nix.raw │ └── format-succeeds-with-all-options.nix │ ├── default │ ├── check-fails-for-invalid-file.nix │ ├── check-succeeds-for-valid-file.nix │ ├── format-succeeds-for-invalid-file.nix │ ├── format-succeeds-for-valid-file.nix │ └── lib.nix │ ├── nixfmt │ ├── default.nix │ ├── files │ │ ├── invalid.nix.raw │ │ └── valid.nix.raw │ ├── format-succeeds-with-all-options.nix │ └── nixfmt-formats-all-nix-files-in-directoy.nix │ ├── nixpkgs-fmt │ ├── default.nix │ └── files │ │ ├── invalid.nix.raw │ │ └── valid.nix.raw │ └── statix │ ├── default.nix │ ├── files │ ├── invalid.nix.raw │ └── valid.nix.raw │ └── format-succeeds-with-all-options.nix └── tools ├── alejandra.nix ├── deadnix.nix ├── nixfmt.nix ├── nixpkgs-fmt.nix └── statix.nix /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build and test flake outputs 2 | on: 3 | push: 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | nix-command: 13 | - build .#manPages 14 | - build .#manualHtml 15 | - build .#optionsJson 16 | - flake check 17 | - fmt 18 | 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v4 22 | with: 23 | persist-credentials: false 24 | 25 | - name: Install nix 26 | uses: cachix/install-nix-action@v31 27 | with: 28 | extra_nix_config: | 29 | keep-going = true 30 | 31 | - name: Run ${{ matrix.nix-command }} 32 | run: nix ${{ matrix.nix-command }} 33 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy docs 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | 7 | # Allow one concurrent deployment 8 | concurrency: 9 | group: "pages" 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | # Single deploy job since we're just deploying 14 | deploy: 15 | environment: 16 | name: github-pages 17 | url: ${{ steps.deployment.outputs.page_url }} 18 | 19 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 20 | permissions: 21 | contents: read 22 | pages: write 23 | id-token: write 24 | 25 | runs-on: ubuntu-latest 26 | 27 | steps: 28 | - name: Checkout repository 29 | uses: actions/checkout@v4 30 | with: 31 | persist-credentials: false 32 | 33 | - name: Install nix 34 | uses: cachix/install-nix-action@v31 35 | with: 36 | extra_nix_config: | 37 | keep-going = true 38 | 39 | - name: Build docs 40 | run: | 41 | nix build .#manualHtml 42 | 43 | # see https://github.com/actions/deploy-pages/issues/58 44 | cp \ 45 | --recursive \ 46 | --dereference \ 47 | --no-preserve=mode,ownership \ 48 | result/share/doc/nix-formatter-pack \ 49 | public 50 | 51 | - name: Setup Pages 52 | uses: actions/configure-pages@v5 53 | 54 | - name: Upload artifact 55 | uses: actions/upload-pages-artifact@v3 56 | with: 57 | path: ./public 58 | 59 | - name: Deploy to GitHub Pages 60 | id: deployment 61 | uses: actions/deploy-pages@v4 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | result 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Tobias Happ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nix formatter pack 2 | 3 | With this project you can combine the simplicity of [`nix fmt`][nix-fmt-manual] with several static code analysis and 4 | formatting tools. 5 | 6 | Currently supported tools: 7 | 8 | - [alejandra][alejandra] 9 | - [deadnix][deadnix] 10 | - [nixfmt][nixfmt] 11 | - [nixpkgs-fmt][nixpkgs-fmt] 12 | - [statix][statix] 13 | 14 | For the list of available options, see the [manual][manual]. 15 | 16 | ## Usage 17 | 18 | **Hint**: To get started quickly, have a look at the provided nix templates in [./templates](./templates). 19 | 20 | ### For `nix fmt` 21 | 22 | Set the special flake output `formatter` like the following: 23 | 24 | ```nix 25 | { 26 | inputs = { 27 | nixpkgs.url = "github:NixOS/nixpkgs/release-22.05"; 28 | nix-formatter-pack.url = "github:Gerschtli/nix-formatter-pack"; 29 | }; 30 | 31 | outputs = { self, nixpkgs, nix-formatter-pack }: { 32 | 33 | formatter.x86_64-linux = nix-formatter-pack.lib.mkFormatter { 34 | inherit nixpkgs; 35 | system = "x86_64-linux"; 36 | # or a custom instance of nixpkgs: 37 | # pkgs = import nixpkgs { inherit system; }; 38 | 39 | # extensible with custom modules: 40 | # extraModules = [ otherFlake.nixFormatterPackModules.default ]; 41 | 42 | config = { 43 | # define custom formatters: 44 | # formatters.customFormatter.commandFn = 45 | # { checkOnly, files, ... }: 46 | # '' 47 | # ${customFormatter}/bin/customFormatter ${if checkOnly then "--check" else "--fix"} ${files} 48 | # ''; 49 | 50 | tools = { 51 | deadnix.enable = true; 52 | nixpkgs-fmt.enable = true; 53 | statix.enable = true; 54 | }; 55 | }; 56 | }; 57 | 58 | }; 59 | } 60 | ``` 61 | 62 | With this configuration, `nix fmt` will format your complete flake with the configured tools. `nix fmt -- --check` only 63 | reports if any tool found an issue and fails with a non-zero exit code if any issue has been found, recommended for 64 | usage in CI. 65 | 66 | For more information, see `nix fmt -- --help`. 67 | 68 | ### For `nix flake check` 69 | 70 | It can also be used as a [`nix flake check`][nix-flake-check-manual] like the following: 71 | 72 | ```nix 73 | { 74 | inputs = { 75 | nixpkgs.url = "github:NixOS/nixpkgs/release-22.05"; 76 | nix-formatter-pack.url = "github:Gerschtli/nix-formatter-pack"; 77 | }; 78 | 79 | outputs = { self, nixpkgs, nix-formatter-pack }: { 80 | 81 | checks.x86_64-linux.nix-formatter-pack = nix-formatter-pack.lib.mkCheck { 82 | inherit nixpkgs; 83 | system = "x86_64-linux"; 84 | # or a custom instance of nixpkgs: 85 | # pkgs = import nixpkgs { inherit system; }; 86 | 87 | # extensible with custom modules: 88 | # extraModules = [ otherFlake.nixFormatterPackModules.default ]; 89 | 90 | config = { 91 | # define custom formatters: 92 | # formatters.customFormatter.commandFn = 93 | # { checkOnly, files, ... }: 94 | # '' 95 | # ${customFormatter}/bin/customFormatter ${if checkOnly then "--check" else "--fix"} ${files} 96 | # ''; 97 | 98 | tools = { 99 | deadnix.enable = true; 100 | nixpkgs-fmt.enable = true; 101 | statix.enable = true; 102 | }; 103 | }; 104 | 105 | # specify which files to check 106 | checkFiles = [ ./. ]; 107 | }; 108 | 109 | }; 110 | } 111 | ``` 112 | 113 | [manual]: https://gerschtli.github.io/nix-formatter-pack/ 114 | [alejandra]: https://github.com/kamadorueda/alejandra 115 | [deadnix]: https://github.com/astro/deadnix 116 | [nix-flake-check-manual]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake-check.html 117 | [nix-fmt-manual]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html 118 | [nixfmt]: https://github.com/serokell/nixfmt 119 | [nixpkgs-fmt]: https://github.com/nix-community/nixpkgs-fmt 120 | [statix]: https://github.com/nerdypepper/statix 121 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs ? null 2 | , system ? null 3 | , pkgs ? nixpkgs.legacyPackages.${system} 4 | , config ? { } 5 | , extraModules ? [ ] 6 | , checkFiles ? [ ] 7 | }: 8 | 9 | assert pkgs != null; 10 | 11 | let 12 | toolsModules = builtins.filter (pkgs.lib.hasSuffix ".nix") (pkgs.lib.filesystem.listFilesRecursive ./tools); 13 | 14 | modules = [ 15 | { _module.args = { inherit pkgs; }; } 16 | ./module.nix 17 | "${pkgs.path}/nixos/modules/misc/assertions.nix" 18 | config 19 | ] 20 | ++ toolsModules 21 | ++ extraModules; 22 | 23 | evaluatedModules = pkgs.lib.evalModules { inherit modules; }; 24 | 25 | check = pkgs.runCommand "nix-formatter-pack-check" { } '' 26 | ${evaluatedModules.config.script}/bin/nix-formatter-pack --check ${pkgs.lib.concatStringsSep " " checkFiles} 27 | touch ${placeholder "out"} 28 | ''; 29 | in 30 | 31 | { 32 | inherit (evaluatedModules.config) script; 33 | inherit (evaluatedModules) config options; 34 | inherit check modules; 35 | } 36 | -------------------------------------------------------------------------------- /docs/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, nmdSrc, formatter }: 2 | 3 | let 4 | nmd = import nmdSrc { inherit pkgs; }; 5 | 6 | # Make sure the used package is scrubbed to avoid actually instantiating 7 | # derivations. 8 | setupModule = { 9 | _module.args.pkgs = pkgs.lib.mkForce (nmd.scrubDerivations "pkgs" pkgs); 10 | }; 11 | 12 | modulesDocs = nmd.buildModulesDocs { 13 | modules = formatter.modules ++ [ setupModule ]; 14 | moduleRootPaths = [ ../. ]; 15 | mkModuleUrl = path: "https://github.com/Gerschtli/nix-formatter-pack/blob/master/${path}"; 16 | channelName = "nix-formatter-pack"; 17 | docBook.id = "nix-formatter-pack-options"; 18 | }; 19 | 20 | docs = nmd.buildDocBookDocs { 21 | pathName = "nix-formatter-pack"; 22 | modulesDocs = [ modulesDocs ]; 23 | documentsDirectory = ./.; 24 | chunkToc = '' 25 | 26 | 27 | 28 | 29 | 30 | ''; 31 | }; 32 | in 33 | 34 | { 35 | inherit (docs) manPages; 36 | 37 | optionsJson = pkgs.symlinkJoin { 38 | name = "nix-formatter-pack-options-json"; 39 | paths = [ 40 | (modulesDocs.json.override { 41 | path = "share/doc/nix-formatter-pack/nix-formatter-pack-options.json"; 42 | }) 43 | ]; 44 | }; 45 | 46 | manualHtml = docs.html; 47 | } 48 | -------------------------------------------------------------------------------- /docs/man-pages.xml: -------------------------------------------------------------------------------- 1 | 4 | Nix formatter pack Reference Pages 5 | 6 | Tobias Happ 7 | 8 | 2022Tobias Happ 9 | 10 | 11 | 12 | 13 | nix-formatter-pack-options 14 | 5 15 | Nix formatter pack 16 | 17 | 18 | nix-formatter-pack-options 19 | Nix formatter pack configuration specification 20 | 21 | 22 | Description 23 | 24 | This contains the module options available for Nix formatter pack. 25 | 26 | 27 | 28 | Options 29 | 30 | You can use the following options as arg config when calling 31 | mkCheck or mkFormatter: 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/manual.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | Nix formatter pack manual 8 | 9 | 10 | Preface 11 | 12 | Some basic documentation of Nix formatter pack. 13 | 14 | 15 | If you encounter problems or bugs then please report them on the 16 | issue tracker. 17 | 18 | 19 | 20 | 21 | Nix formatter pack configuration options 22 |
23 | Usage 24 | 25 | 26 | To use these options, set the config argument in the call 27 | to mkCheck or mkFormatter in your 28 | flake.nix like that: 29 | 30 | { 31 | inputs = { 32 | nixpkgs.url = "github:NixOS/nixpkgs/release-22.05"; 33 | nix-formatter-pack.url = "github:Gerschtli/nix-formatter-pack"; 34 | }; 35 | 36 | outputs = { self, nixpkgs, nix-formatter-pack }: { 37 | 38 | formatter.x86_64-linux = nix-formatter-pack.lib.mkFormatter { 39 | inherit nixpkgs; 40 | system = "x86_64-linux"; 41 | # or a custom instance of nixpkgs: 42 | # pkgs = import nixpkgs { inherit system; }; 43 | 44 | # extensible with custom modules: 45 | # extraModules = [ otherFlake.nixFormatterPackModules.default ]; 46 | 47 | config = { 48 | tools = { 49 | deadnix.enable = true; 50 | nixpkgs-fmt.enable = true; 51 | statix.enable = true; 52 | }; 53 | }; 54 | }; 55 | 56 | }; 57 | } 58 | 59 | 60 |
61 |
62 | Options 63 | 64 | 65 |
66 |
67 |
68 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1669933672, 6 | "narHash": "sha256-9nzaATSTmEMpTrx+7j3vVwQkcpu9JMkQ1M08iPtu7m4=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "da12bb299b2941299b1de24fbd92c5dd35de40e9", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "NixOS", 14 | "ref": "release-22.11", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "nmd": { 20 | "flake": false, 21 | "locked": { 22 | "lastModified": 1666190571, 23 | "narHash": "sha256-Z1hc7M9X6L+H83o9vOprijpzhTfOBjd0KmUTnpHAVjA=", 24 | "owner": "rycee", 25 | "repo": "nmd", 26 | "rev": "b75d312b4f33bd3294cd8ae5c2ca8c6da2afc169", 27 | "type": "gitlab" 28 | }, 29 | "original": { 30 | "owner": "rycee", 31 | "repo": "nmd", 32 | "type": "gitlab" 33 | } 34 | }, 35 | "nmt": { 36 | "flake": false, 37 | "locked": { 38 | "lastModified": 1648075362, 39 | "narHash": "sha256-u36WgzoA84dMVsGXzml4wZ5ckGgfnvS0ryzo/3zn/Pc=", 40 | "owner": "rycee", 41 | "repo": "nmt", 42 | "rev": "d83601002c99b78c89ea80e5e6ba21addcfe12ae", 43 | "type": "gitlab" 44 | }, 45 | "original": { 46 | "owner": "rycee", 47 | "repo": "nmt", 48 | "type": "gitlab" 49 | } 50 | }, 51 | "root": { 52 | "inputs": { 53 | "nixpkgs": "nixpkgs", 54 | "nmd": "nmd", 55 | "nmt": "nmt" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Collection of several nix formatters."; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/release-22.11"; 6 | nmd = { 7 | url = "gitlab:rycee/nmd"; 8 | flake = false; 9 | }; 10 | nmt = { 11 | url = "gitlab:rycee/nmt"; 12 | flake = false; 13 | }; 14 | }; 15 | 16 | outputs = { self, nixpkgs, nmd, nmt }: 17 | let 18 | forEachSystem = nixpkgs.lib.genAttrs [ "aarch64-darwin" "aarch64-linux" "i686-linux" "x86_64-darwin" "x86_64-linux" ]; 19 | optiniatedDefaultConfig = { 20 | tools = { 21 | deadnix = { 22 | enable = true; 23 | noLambdaPatternNames = true; 24 | }; 25 | nixpkgs-fmt.enable = true; 26 | statix.enable = true; 27 | }; 28 | }; 29 | 30 | mkFormatterApp = args: { 31 | type = "app"; 32 | program = "${self.lib.mkFormatter args}/bin/nix-formatter-pack"; 33 | }; 34 | in 35 | { 36 | apps = forEachSystem (system: 37 | { 38 | default = mkFormatterApp { 39 | inherit nixpkgs system; 40 | config = optiniatedDefaultConfig; 41 | }; 42 | } 43 | // nixpkgs.lib.genAttrs 44 | [ "alejandra" "deadnix" "nixfmt" "nixpkgs-fmt" "statix" ] 45 | (tool: mkFormatterApp { 46 | inherit nixpkgs system; 47 | config.tools.${tool}.enable = true; 48 | }) 49 | ); 50 | 51 | checks = nixpkgs.lib.genAttrs [ "x86_64-linux" ] (system: { 52 | nix-formatter-pack-check = self.lib.mkCheck { 53 | inherit nixpkgs system; 54 | config = optiniatedDefaultConfig; 55 | checkFiles = [ ./. ]; 56 | }; 57 | 58 | tests = import ./tests { 59 | inherit nixpkgs nmt system; 60 | }; 61 | }); 62 | 63 | formatter = forEachSystem (system: 64 | self.lib.mkFormatter { 65 | inherit nixpkgs system; 66 | config = optiniatedDefaultConfig; 67 | } 68 | ); 69 | 70 | lib = { 71 | mkCheck = args: (import ./. args).check; 72 | mkFormatter = args: (import ./. args).script; 73 | }; 74 | 75 | packages = forEachSystem 76 | (system: import ./docs { 77 | formatter = import ./. { 78 | inherit nixpkgs system; 79 | }; 80 | 81 | pkgs = nixpkgs.legacyPackages.${system}; 82 | 83 | nmdSrc = nmd; 84 | }); 85 | 86 | templates = { 87 | default = self.templates.minimal; 88 | 89 | minimal = { 90 | path = ./templates/minimal; 91 | description = "Minimal usage example of nix-formatter-pack."; 92 | }; 93 | 94 | advanced = { 95 | path = ./templates/advanced; 96 | description = "Advanced usage example of nix-formatter-pack."; 97 | }; 98 | }; 99 | }; 100 | } 101 | -------------------------------------------------------------------------------- /module.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | enabledFormatters = filter (f: f.enable) (attrValues config.formatters); 7 | 8 | buildCommand = commandFn: checkOnly: 9 | let 10 | command = commandFn { 11 | inherit checkOnly; 12 | files = "\"\${FILE_PATHS[@]}\""; 13 | }; 14 | in 15 | "${command} || LOCAL_RESULT=$?"; 16 | 17 | commands = 18 | concatMapStringsSep 19 | "\n" 20 | (formatter: '' 21 | logInfo "Running ${formatter.name}..." 22 | LOCAL_RESULT=0 23 | if [[ -n "$CHECK_ONLY" ]]; then 24 | ${buildCommand formatter.commandFn true} 25 | else 26 | ${buildCommand formatter.commandFn false} 27 | fi 28 | 29 | if (( LOCAL_RESULT > 0 )); then 30 | RESULT=1 31 | logWarn "Failed with exit code: $LOCAL_RESULT" 32 | fi 33 | 34 | echo 35 | '') 36 | enabledFormatters; 37 | 38 | script = pkgs.writeShellApplication { 39 | name = "nix-formatter-pack"; 40 | runtimeInputs = with pkgs; [ ncurses ]; 41 | 42 | text = '' 43 | COLOR_RESET= 44 | COLOR_ERROR= 45 | COLOR_WARN= 46 | COLOR_INFO= 47 | if [[ -t 1 ]]; then 48 | COLOR_RESET="$(tput sgr0)" 49 | COLOR_ERROR="$(tput bold)$(tput setaf 1)" 50 | COLOR_WARN="$(tput setaf 3)" 51 | COLOR_INFO="$(tput bold)$(tput setaf 6)" 52 | fi 53 | 54 | function logError() { 55 | echo >&2 "$COLOR_ERROR$*$COLOR_RESET" 56 | } 57 | 58 | function logWarn() { 59 | echo "$COLOR_WARN$*$COLOR_RESET" 60 | } 61 | 62 | function logInfo() { 63 | echo "$COLOR_INFO$*$COLOR_RESET" 64 | } 65 | 66 | function doHelp() { 67 | echo "Usage: $0 [OPTION] [--] FILES" 68 | echo 69 | echo "Formats nix source files. Enabled formatters are ${concatMapStringsSep ", " (f: "'${f.name}'") enabledFormatters}." 70 | echo 71 | echo "Options" 72 | echo 73 | echo " -h|--help Print this help" 74 | echo " -c|--check Check only (useful for CI)" 75 | } 76 | 77 | CHECK_ONLY= 78 | FILE_PATHS=() 79 | RESULT=0 80 | 81 | while [[ $# -gt 0 ]]; do 82 | opt="$1" 83 | shift 84 | case "$opt" in 85 | -c|--check) 86 | CHECK_ONLY=1 87 | ;; 88 | -h|--help) 89 | doHelp 90 | exit 0 91 | ;; 92 | --) 93 | FILE_PATHS+=("$@") 94 | break 95 | ;; 96 | -*) 97 | logError "$0: unknown option '$opt'" 98 | logError "Run '$0 --help' for usage help" 99 | exit 2 100 | ;; 101 | *) 102 | FILE_PATHS+=("$opt") 103 | ;; 104 | esac 105 | done 106 | 107 | # default to current directory 108 | if [[ "''${#FILE_PATHS[@]}" -eq 0 ]]; then 109 | FILE_PATHS+=(.) 110 | fi 111 | 112 | ${commands} 113 | 114 | exit $RESULT 115 | ''; 116 | }; 117 | 118 | failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions); 119 | throwAssertions = res: 120 | if (failedAssertions != [ ]) 121 | then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" 122 | else res; 123 | in 124 | 125 | { 126 | options = { 127 | formatters = mkOption { 128 | type = types.attrsOf (types.submodule ( 129 | { name, ... }: 130 | { 131 | options = { 132 | enable = mkEnableOption "formatter" // { default = true; }; 133 | 134 | name = mkOption { 135 | type = types.str; 136 | default = name; 137 | description = "Name of formatter."; 138 | }; 139 | 140 | commandFn = mkOption { 141 | type = types.functionTo types.singleLineStr; 142 | example = literalExpression '' 143 | { checkOnly, files, ... }: 144 | ''' 145 | ''${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ''${lib.optionalString checkOnly "--check"} ''${files} 146 | ''' 147 | ''; 148 | description = '' 149 | Command for formatter. Receives at least checkOnly as boolean 150 | and files as a string. 151 | 152 | Must return a non-zero exit code when checkOnly is true and the 153 | check fails. Should return zero exit code when checkOnly is false 154 | and all issues could be fixed. 155 | 156 | For more complex commands, use pkgs.writeScript like 157 | 158 | { checkOnly, files, ... }: 159 | "''${pkgs.writeScript 160 | "nixpkgs-fmt" 161 | ''' 162 | ''${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ''${lib.optionalString checkOnly "--check"} "$@" 163 | ''' 164 | } ''${files}"; 165 | 166 | ''; 167 | }; 168 | }; 169 | } 170 | )); 171 | default = { }; 172 | description = "Set of all formatters to run on script execution."; 173 | }; 174 | 175 | script = mkOption { 176 | type = types.package; 177 | internal = true; 178 | readOnly = true; 179 | description = "Final script."; 180 | }; 181 | }; 182 | 183 | config = { 184 | 185 | assertions = [ 186 | { 187 | assertion = enabledFormatters != [ ]; 188 | message = "At least one formatter needs to be enabled."; 189 | } 190 | ]; 191 | 192 | script = throwAssertions (showWarnings config.warnings script); 193 | 194 | }; 195 | } 196 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /templates/advanced/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Advanced usage example of nix-formatter-pack."; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/release-22.05"; 6 | nix-formatter-pack.url = "github:Gerschtli/nix-formatter-pack"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, nix-formatter-pack }: 10 | let 11 | forEachSystem = nixpkgs.lib.genAttrs [ "aarch64-darwin" "aarch64-linux" "i686-linux" "x86_64-darwin" "x86_64-linux" ]; 12 | 13 | formatterPackArgsPerSystem = forEachSystem (system: { 14 | inherit nixpkgs system; 15 | # or a custom instance of nixpkgs: 16 | # pkgs = import nixpkgs { inherit system; }; 17 | 18 | # extensible with custom modules: 19 | # extraModules = [ otherFlake.nixFormatterPackModules.default ]; 20 | 21 | checkFiles = [ ./. ]; 22 | 23 | config = { 24 | # define custom formatters: 25 | # formatters.customFormatter.commandFn = 26 | # { checkOnly, files, ... }: 27 | # '' 28 | # ${customFormatter}/bin/customFormatter ${if checkOnly then "--check" else "--fix"} ${files} 29 | # ''; 30 | 31 | tools = { 32 | deadnix.enable = true; 33 | nixpkgs-fmt.enable = true; 34 | statix.enable = true; 35 | }; 36 | }; 37 | }); 38 | in 39 | 40 | { 41 | checks = forEachSystem (system: { 42 | nix-formatter-pack-check = nix-formatter-pack.lib.mkCheck formatterPackArgsPerSystem.${system}; 43 | }); 44 | 45 | formatter = forEachSystem (system: nix-formatter-pack.lib.mkFormatter formatterPackArgsPerSystem.${system}); 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /templates/minimal/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Minimal usage example of nix-formatter-pack."; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/release-22.05"; 6 | nix-formatter-pack.url = "github:Gerschtli/nix-formatter-pack"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, nix-formatter-pack }: 10 | let 11 | system = "x86_64-linux"; 12 | 13 | formatterPackArgs = { 14 | inherit nixpkgs system; 15 | checkFiles = [ ./. ]; 16 | 17 | config.tools.nixpkgs-fmt.enable = true; 18 | }; 19 | in 20 | 21 | { 22 | checks.${system}.nix-formatter-pack-check = nix-formatter-pack.lib.mkCheck formatterPackArgs; 23 | 24 | formatter.${system} = nix-formatter-pack.lib.mkFormatter formatterPackArgs; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /tests/default.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs 2 | , system 3 | , nmt 4 | }: 5 | 6 | let 7 | pkgs = nixpkgs.legacyPackages.${system}; 8 | 9 | modules = [ 10 | { 11 | _file = ./default.nix; 12 | _module.args = { inherit pkgs; }; 13 | } 14 | ./module.nix 15 | ./tool-test.nix 16 | ]; 17 | 18 | defaultNixFiles = builtins.filter (x: baseNameOf x == "default.nix") (pkgs.lib.filesystem.listFilesRecursive ./tools); 19 | 20 | nmtInstance = import nmt { 21 | inherit pkgs modules; 22 | testedAttrPath = [ "formatter" ]; 23 | tests = builtins.foldl' (a: b: a // (import b)) { } defaultNixFiles; 24 | }; 25 | in 26 | 27 | pkgs.runCommandLocal "tests" { } '' 28 | touch ${placeholder "out"} 29 | 30 | ${nmtInstance.run.all.shellHook} 31 | '' 32 | -------------------------------------------------------------------------------- /tests/module.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | { 6 | options = { 7 | 8 | formatter = mkOption { 9 | type = types.package; 10 | description = "Formatter to use for the test."; 11 | }; 12 | 13 | configuration = mkOption { 14 | type = types.submodule (import ../. { inherit pkgs; }).modules; 15 | description = "Nix formatter pack configuration to test."; 16 | }; 17 | 18 | }; 19 | 20 | config = { 21 | 22 | formatter = mkIf (config != null) config.configuration.script; 23 | 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /tests/tool-test.nix: -------------------------------------------------------------------------------- 1 | { lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.toolTest; 7 | in 8 | 9 | { 10 | options = { 11 | 12 | toolTest = { 13 | enable = mkEnableOption "tool test helper"; 14 | 15 | checkOnly = mkOption { 16 | type = types.bool; 17 | description = "Whether to run in check or fix mode."; 18 | }; 19 | 20 | files = mkOption { 21 | type = types.attrsOf (types.submodule ( 22 | { config, name, ... }: 23 | { 24 | options = { 25 | name = mkOption { 26 | type = types.str; 27 | default = name; 28 | description = "Name of file."; 29 | }; 30 | 31 | source = mkOption { 32 | type = types.path; 33 | description = "Source file."; 34 | }; 35 | 36 | expected = mkOption { 37 | type = types.path; 38 | default = config.source; 39 | description = '' 40 | Expected file. Defaults to to ensure that the file did not change. 41 | ''; 42 | }; 43 | }; 44 | } 45 | )); 46 | description = "Files for the test and its assertions."; 47 | }; 48 | 49 | filePathsArgs = mkOption { 50 | type = types.listOf types.str; 51 | default = map (f: f.name) (attrValues cfg.files); 52 | defaultText = literalExpression ''map (f: f.name) (attrValues config.toolTest.files)''; 53 | description = '' 54 | List of file paths to call nix-formatter-pack with. Defaults to all files listed in 55 | option. 56 | 57 | 58 | 59 | Note: Each value is prefixed with $out/files, 60 | the same directory where all files from are copied to. 61 | ''; 62 | }; 63 | 64 | expectedExitCode = mkOption { 65 | type = types.int; 66 | description = "Expected exit code of nix-formatter-pack."; 67 | }; 68 | }; 69 | 70 | }; 71 | 72 | config = mkIf cfg.enable { 73 | 74 | nmt.script = 75 | let 76 | filesDir = "${placeholder "out"}/files"; 77 | mappedFilePathsArgs = concatMapStringsSep " " (file: ''"${filesDir}/${file}"'') cfg.filePathsArgs; 78 | in 79 | '' 80 | mkdir -p ${filesDir} 81 | ${concatMapStrings (file: '' 82 | cp "${file.source}" "${filesDir}/${file.name}" 83 | '') (attrValues cfg.files)} 84 | chmod --recursive +w ${filesDir} 85 | 86 | $TESTED/bin/nix-formatter-pack ${optionalString cfg.checkOnly "--check"} ${mappedFilePathsArgs}; EXIT_CODE=$? 87 | 88 | if (( EXIT_CODE != ${toString cfg.expectedExitCode} )); then 89 | fail "Expected exit code to be ${toString cfg.expectedExitCode}, got $EXIT_CODE." 90 | fi 91 | 92 | ${concatMapStrings (file: '' 93 | assertFileContent "${filesDir}/${file.name}" "${file.expected}" 94 | '') (attrValues cfg.files)} 95 | ''; 96 | 97 | }; 98 | } 99 | -------------------------------------------------------------------------------- /tests/tools/alejandra/default.nix: -------------------------------------------------------------------------------- 1 | import ../default/lib.nix { 2 | name = "alejandra"; 3 | configuration.tools.alejandra.enable = true; 4 | validFile = ./files/valid.nix.raw; 5 | invalidFile = ./files/invalid.nix.raw; 6 | } 7 | -------------------------------------------------------------------------------- /tests/tools/alejandra/files/invalid.nix.raw: -------------------------------------------------------------------------------- 1 | { 2 | x=1; 3 | } 4 | -------------------------------------------------------------------------------- /tests/tools/alejandra/files/valid.nix.raw: -------------------------------------------------------------------------------- 1 | { 2 | x = 1; 3 | } 4 | -------------------------------------------------------------------------------- /tests/tools/deadnix/default.nix: -------------------------------------------------------------------------------- 1 | (import ../default/lib.nix { 2 | name = "deadnix"; 3 | configuration.tools.deadnix.enable = true; 4 | validFile = ./files/valid.nix.raw; 5 | invalidFile = ./files/invalid.nix.raw; 6 | }) // { 7 | deadnix-format-succeeds-with-all-options = import ./format-succeeds-with-all-options.nix; 8 | } 9 | -------------------------------------------------------------------------------- /tests/tools/deadnix/files/invalid.nix.raw: -------------------------------------------------------------------------------- 1 | let 2 | x = 1; 3 | in 4 | 5 | { } 6 | -------------------------------------------------------------------------------- /tests/tools/deadnix/files/valid.nix.raw: -------------------------------------------------------------------------------- 1 | { } 2 | -------------------------------------------------------------------------------- /tests/tools/deadnix/format-succeeds-with-all-options.nix: -------------------------------------------------------------------------------- 1 | _: { 2 | configuration.tools.deadnix = { 3 | enable = true; 4 | checkHiddenFiles = true; 5 | noLambdaArg = true; 6 | noLambdaPatternNames = true; 7 | noUnderscore = true; 8 | }; 9 | 10 | toolTest = { 11 | enable = true; 12 | checkOnly = false; 13 | files."valid.nix" = { 14 | source = ./files/valid.nix.raw; 15 | }; 16 | expectedExitCode = 0; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /tests/tools/default/check-fails-for-invalid-file.nix: -------------------------------------------------------------------------------- 1 | { configuration, invalidFile, ... }: 2 | 3 | _: 4 | 5 | { 6 | inherit configuration; 7 | 8 | toolTest = { 9 | enable = true; 10 | checkOnly = true; 11 | files."invalid.nix" = { 12 | source = invalidFile; 13 | }; 14 | expectedExitCode = 1; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /tests/tools/default/check-succeeds-for-valid-file.nix: -------------------------------------------------------------------------------- 1 | { configuration, validFile, ... }: 2 | 3 | _: 4 | 5 | { 6 | inherit configuration; 7 | 8 | toolTest = { 9 | enable = true; 10 | checkOnly = true; 11 | files."valid.nix" = { 12 | source = validFile; 13 | }; 14 | expectedExitCode = 0; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /tests/tools/default/format-succeeds-for-invalid-file.nix: -------------------------------------------------------------------------------- 1 | { configuration, validFile, invalidFile, ... }: 2 | 3 | _: 4 | 5 | { 6 | inherit configuration; 7 | 8 | toolTest = { 9 | enable = true; 10 | checkOnly = false; 11 | files."invalid.nix" = { 12 | source = invalidFile; 13 | expected = validFile; 14 | }; 15 | expectedExitCode = 0; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /tests/tools/default/format-succeeds-for-valid-file.nix: -------------------------------------------------------------------------------- 1 | { configuration, validFile, ... }: 2 | 3 | _: 4 | 5 | { 6 | inherit configuration; 7 | 8 | toolTest = { 9 | enable = true; 10 | checkOnly = false; 11 | files."valid.nix" = { 12 | source = validFile; 13 | }; 14 | expectedExitCode = 0; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /tests/tools/default/lib.nix: -------------------------------------------------------------------------------- 1 | { name, configuration, validFile, invalidFile }@args: 2 | 3 | { 4 | "${name}-check-fails-for-invalid-file" = import ./check-fails-for-invalid-file.nix args; 5 | "${name}-check-succeeds-for-valid-file" = import ./check-succeeds-for-valid-file.nix args; 6 | "${name}-format-succeeds-for-invalid-file" = import ./format-succeeds-for-invalid-file.nix args; 7 | "${name}-format-succeeds-for-valid-file" = import ./format-succeeds-for-valid-file.nix args; 8 | } 9 | -------------------------------------------------------------------------------- /tests/tools/nixfmt/default.nix: -------------------------------------------------------------------------------- 1 | (import ../default/lib.nix { 2 | name = "nixfmt"; 3 | configuration.tools.nixfmt.enable = true; 4 | validFile = ./files/valid.nix.raw; 5 | invalidFile = ./files/invalid.nix.raw; 6 | }) // { 7 | nixfmt-format-succeeds-with-all-options = import ./format-succeeds-with-all-options.nix; 8 | nixfmt-formats-all-nix-files-in-directoy = import ./nixfmt-formats-all-nix-files-in-directoy.nix; 9 | } 10 | -------------------------------------------------------------------------------- /tests/tools/nixfmt/files/invalid.nix.raw: -------------------------------------------------------------------------------- 1 | { 2 | x=1; 3 | } 4 | -------------------------------------------------------------------------------- /tests/tools/nixfmt/files/valid.nix.raw: -------------------------------------------------------------------------------- 1 | { x = 1; } 2 | -------------------------------------------------------------------------------- /tests/tools/nixfmt/format-succeeds-with-all-options.nix: -------------------------------------------------------------------------------- 1 | _: { 2 | configuration.tools.nixfmt = { 3 | enable = true; 4 | maxWidth = 80; 5 | }; 6 | 7 | toolTest = { 8 | enable = true; 9 | checkOnly = false; 10 | files."valid.nix" = { 11 | source = ./files/valid.nix.raw; 12 | }; 13 | expectedExitCode = 0; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /tests/tools/nixfmt/nixfmt-formats-all-nix-files-in-directoy.nix: -------------------------------------------------------------------------------- 1 | _: { 2 | configuration.tools.nixfmt.enable = true; 3 | 4 | toolTest = { 5 | enable = true; 6 | checkOnly = false; 7 | files = { 8 | "file1.nix" = { 9 | source = ./files/invalid.nix.raw; 10 | expected = ./files/valid.nix.raw; 11 | }; 12 | "file2.nix" = { 13 | source = ./files/invalid.nix.raw; 14 | expected = ./files/valid.nix.raw; 15 | }; 16 | "file3.any" = { 17 | source = ./files/invalid.nix.raw; 18 | expected = ./files/invalid.nix.raw; 19 | }; 20 | }; 21 | filePathsArgs = [ "." ]; 22 | expectedExitCode = 0; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /tests/tools/nixpkgs-fmt/default.nix: -------------------------------------------------------------------------------- 1 | import ../default/lib.nix { 2 | name = "nixpkgs-fmt"; 3 | configuration.tools.nixpkgs-fmt.enable = true; 4 | validFile = ./files/valid.nix.raw; 5 | invalidFile = ./files/invalid.nix.raw; 6 | } 7 | -------------------------------------------------------------------------------- /tests/tools/nixpkgs-fmt/files/invalid.nix.raw: -------------------------------------------------------------------------------- 1 | { 2 | x=1; 3 | } 4 | -------------------------------------------------------------------------------- /tests/tools/nixpkgs-fmt/files/valid.nix.raw: -------------------------------------------------------------------------------- 1 | { 2 | x = 1; 3 | } 4 | -------------------------------------------------------------------------------- /tests/tools/statix/default.nix: -------------------------------------------------------------------------------- 1 | (import ../default/lib.nix { 2 | name = "statix"; 3 | configuration.tools.statix.enable = true; 4 | validFile = ./files/valid.nix.raw; 5 | invalidFile = ./files/invalid.nix.raw; 6 | }) // { 7 | statix-format-succeeds-with-all-options = import ./format-succeeds-with-all-options.nix; 8 | } 9 | -------------------------------------------------------------------------------- /tests/tools/statix/files/invalid.nix.raw: -------------------------------------------------------------------------------- 1 | let 2 | x = 1; 3 | in 4 | 5 | { x = x; } 6 | -------------------------------------------------------------------------------- /tests/tools/statix/files/valid.nix.raw: -------------------------------------------------------------------------------- 1 | let 2 | x = 1; 3 | in 4 | 5 | { inherit x; } 6 | -------------------------------------------------------------------------------- /tests/tools/statix/format-succeeds-with-all-options.nix: -------------------------------------------------------------------------------- 1 | _: { 2 | configuration.tools.statix = { 3 | enable = true; 4 | disabledLints = [ "bool_comparison" ]; 5 | unrestricted = true; 6 | }; 7 | 8 | toolTest = { 9 | enable = true; 10 | checkOnly = false; 11 | files."valid.nix" = { 12 | source = ./files/valid.nix.raw; 13 | }; 14 | expectedExitCode = 0; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /tools/alejandra.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.tools.alejandra; 7 | in 8 | 9 | { 10 | options = { 11 | 12 | tools.alejandra = { 13 | enable = mkEnableOption "alejandra"; 14 | }; 15 | 16 | }; 17 | 18 | config = mkIf cfg.enable { 19 | 20 | formatters.alejandra.commandFn = 21 | { checkOnly, files, ... }: 22 | '' 23 | ${pkgs.alejandra}/bin/alejandra ${optionalString checkOnly "--check"} ${files} 24 | ''; 25 | 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /tools/deadnix.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.tools.deadnix; 7 | in 8 | 9 | { 10 | options = { 11 | 12 | tools.deadnix = { 13 | enable = mkEnableOption "deadnix"; 14 | 15 | checkHiddenFiles = mkOption { 16 | type = types.bool; 17 | default = false; 18 | description = "Recurse into hidden subdirectories and process hidden .*.nix files."; 19 | }; 20 | 21 | noLambdaArg = mkOption { 22 | type = types.bool; 23 | default = false; 24 | description = "Don't check lambda parameter arguments."; 25 | }; 26 | 27 | noLambdaPatternNames = mkOption { 28 | type = types.bool; 29 | default = false; 30 | description = "Don't check lambda attrset pattern names (don't break nixpkgs' callPackage)."; 31 | }; 32 | 33 | noUnderscore = mkOption { 34 | type = types.bool; 35 | default = false; 36 | description = "Don't check any bindings that start with a _."; 37 | }; 38 | }; 39 | 40 | }; 41 | 42 | config = mkIf cfg.enable { 43 | 44 | formatters.deadnix.commandFn = 45 | { checkOnly, files, ... }: 46 | concatStringsSep " " [ 47 | "${pkgs.deadnix}/bin/deadnix" 48 | (if checkOnly then "--fail" else "--edit") 49 | (optionalString cfg.checkHiddenFiles "--hidden") 50 | (optionalString cfg.noLambdaArg "--no-lambda-arg") 51 | (optionalString cfg.noLambdaPatternNames "--no-lambda-pattern-names") 52 | (optionalString cfg.noUnderscore "--no-underscore") 53 | files 54 | ]; 55 | 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /tools/nixfmt.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.tools.nixfmt; 7 | in 8 | 9 | { 10 | options = { 11 | 12 | tools.nixfmt = { 13 | enable = mkEnableOption "nixfmt"; 14 | 15 | maxWidth = mkOption { 16 | type = types.nullOr types.int; 17 | default = null; 18 | description = "Maximum width in characters."; 19 | }; 20 | }; 21 | 22 | }; 23 | 24 | config = mkIf cfg.enable { 25 | 26 | formatters.nixfmt.commandFn = 27 | { checkOnly, files, ... }: 28 | "${pkgs.writeShellScript 29 | "nixmft" 30 | '' 31 | shopt -s globstar 32 | 33 | FILES=() 34 | for path in "$@"; do 35 | if [[ -d "$path" ]]; then 36 | FILES+=("$path"/**/*.nix) 37 | else 38 | FILES+=("$path") 39 | fi 40 | done 41 | 42 | ${pkgs.nixfmt}/bin/nixfmt \ 43 | ${optionalString checkOnly "--check"} \ 44 | ${optionalString (cfg.maxWidth != null) "--width ${toString cfg.maxWidth}"} \ 45 | "''${FILES[@]}" 46 | '' 47 | } ${files}"; 48 | 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /tools/nixpkgs-fmt.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.tools.nixpkgs-fmt; 7 | in 8 | 9 | { 10 | options = { 11 | 12 | tools.nixpkgs-fmt = { 13 | enable = mkEnableOption "nixpkgs-fmt"; 14 | }; 15 | 16 | }; 17 | 18 | config = mkIf cfg.enable { 19 | 20 | formatters.nixpkgs-fmt.commandFn = 21 | { checkOnly, files, ... }: 22 | '' 23 | ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ${optionalString checkOnly "--check"} ${files} 24 | ''; 25 | 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /tools/statix.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, config, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.tools.statix; 7 | 8 | configFile = pkgs.writeTextFile { 9 | name = "statix-config"; 10 | destination = "/statix.toml"; 11 | text = '' 12 | disabled = [ 13 | ${concatMapStringsSep "\n" (l: " \"${l}\",") cfg.disabledLints} 14 | ] 15 | ''; 16 | }; 17 | in 18 | 19 | { 20 | options = { 21 | 22 | tools.statix = { 23 | enable = mkEnableOption "statix"; 24 | 25 | disabledLints = mkOption { 26 | type = types.listOf types.str; 27 | default = [ ]; 28 | description = '' 29 | Disabled lints, see 30 | offical statix docs 31 | for list of all available lints. 32 | 33 | 34 | 35 | Note: When this option is used, no other config file will be 36 | read by statix. 37 | ''; 38 | }; 39 | 40 | unrestricted = mkOption { 41 | type = types.bool; 42 | default = false; 43 | description = "Don't respect .gitignore files."; 44 | }; 45 | }; 46 | 47 | }; 48 | 49 | config = mkIf cfg.enable { 50 | 51 | formatters.statix.commandFn = 52 | { checkOnly, files, ... }: 53 | concatStringsSep " " [ 54 | "${pkgs.statix}/bin/statix" 55 | (if checkOnly then "check" else "fix") 56 | (optionalString (cfg.disabledLints != [ ]) "--config ${configFile}") 57 | (optionalString cfg.unrestricted "--unrestricted") 58 | files 59 | ]; 60 | 61 | }; 62 | } 63 | --------------------------------------------------------------------------------