Linter for Nix using tree-sitter 🌳 + ❄️

Overview

Linter for Nix using tree-sitter 🌳 + ❄️

asciicast

This is a simple linter for Nix that uses tree-sitter. I plan on extending it with more detections in the future. Currently we have:

  • pkg-config in buildInputs
  • dontBuild = true in stdenv.mkDerivation
  • redundant packages from stdenv in nativeBuildInputs
  • pytestCheckHook in checkInputs

Usage

$ npm run lint <path to nixpkgs>

Motivation

Why another linter? My motivation for this was spawned after doing a series of treewide PRs such as moving cmake to buildInputs. The strategy was similar each time; write some shell one-liner to go through every file (27,000+ of them) in Nixpkgs and find some anti-pattern to fix. However, this is quickly problematic for multiple reasons:

  • it is hard to account for multi-line expressions
  • it is hard to filter out false positives
  • it is hard to query for more complex features

In general discussions on IRC and Matrix, a more AST-aware approach to linting was viewed favorably but not many people took it on, despite the availability of Nix parsers in various languages. I have some subjective reasons myself:

  • need to learn the AST representation in the respective library
  • need to traverse the AST with a query
  • need to locate this information back to a source location

Often one or more of these would be pretty involved. Furthermore, it locks you into a specific parser (which may or may not have provided source information, parse all things correctly, etc.).

Enter tree-sitter. The Nix grammar for tree-sitter has been well-tested and tree-sitter having bindings in several languages gives you options in how to work with the resulting AST. You also get things like a location-annotated AST and error recovery for free.

In any case, suppose we wanted to find usages of pkg-config in buildInputs, this corresponds to the tree-sitter query

((binding attrpath: _ @a expression: (list_expression element: (variable_expression name: _ @i)))
 (#eq? @a "buildInputs")
 (#eq? @i "pkg-config")
 ) @b

We use a variation of this query in JavaScript to not restrict ourselves to when the right-hand side of the binding is not a list_expression (which occurs frequently). The JavaScript we write is

files.forEach(file => {
    const tree = parser.parse(readFileSync(file, "utf8"));
    let l = capturesByName(tree, pkgQuery, "l").filter((x) => x.text.includes('pkg-config'));
    if (l.length > 0) {
        console.log(file);
        console.log(l);
    }
});

Then we can get the output with the exact span of the right-hand side of the binding for more processing.

$ npm run lint ~/Git/forks/nixpkgs

> [email protected] lint
> node index.js "/Users/siraben/Git/forks/nixpkgs"

/Users/siraben/Git/forks/nixpkgs/pkgs/applications/audio/aumix/default.nix
[
  {
    text: '[ gettext ncurses ]\n    ++ lib.optionals gtkGUI [ pkg-config gtk2 ]',
    row: 30,
    column: 16
  }
]
/Users/siraben/Git/forks/nixpkgs/pkgs/applications/audio/grandorgue/default.nix
[
  {
    text: '[ pkg-config fftwFloat alsa-lib zlib wavpack wxGTK31 udev ]\n' +
      '    ++ lib.optional jackaudioSupport libjack2',
    row: 16,
    column: 16
  }
]

Note that this isn't meant to be a criticism of existing parsers and linters for Nix, but I wanted to get a linter off the ground that was easier to write and extend gradually.

License

This repository is licensed under the MIT license.

Comments
  • Json flag PR²

    Json flag PR²

    see #6. cc @siraben. for some reason GH won't let me comment on that one now.

    @ckiee I get the following error

    @nix { "action": "setPhase", "phase": "patchPhase" }
    patching sources
    @nix { "action": "setPhase", "phase": "updateAutotoolsGnuConfigScriptsPhase" }
    updateAutotoolsGnuConfigScriptsPhase
    @nix { "action": "setPhase", "phase": "configurePhase" }
    configuring
    @nix { "action": "setPhase", "phase": "buildPhase" }
    building
    '/private/tmp/nix-build-nix-lint-modules-1.0.0.drv-0/yarn_home/.cache/node-gyp/16.14.2/include' -> '/nix/store/m7g86w34azz3ik67vsiwyfm6p6rwzvjc-nodejs-16.14.2/include'
    yarn config v1.22.17
    success Set "yarn-offline-mirror" to "/nix/store/l32fp7r8j6cpvjjw4kb548zx11a9gjrh-offline".
    ✨  Done in 0.02s.
    yarn install v1.22.17
    [1/4] 🔍  Resolving packages...
    [2/4] 🚚  Fetching packages...
    [] 0/86error Can't make a request in offline mode ("https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz")
    info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.
    

    it wants 5.2.1 ([] 0/86error Can't make a request in offline mode ("https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz")) but it has 5.2.0 (url = "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz";)

    Just rm'd yarn.lock and regenerated it (yarn) and it seems to be happy. The JS ecosystem is weird.

    opened by ckiee 4
  • Allow selection of multiple lints

    Allow selection of multiple lints

    Currently only one lint is allowed at a time, but we might want to enable several lints at a time. Interacts with #5 for non-interactivity and #4 for putting the lint information in the JSON output.

    enhancement 
    opened by siraben 1
  • Usage could be explained a bit more

    Usage could be explained a bit more

    I tried (naively) to install npm using nix-shell -p npm and then doing npm run lint <path>, but that didn't work.

    Now I tried next to do npm install, but that failed because it expected python3 in the PATH.

    After going into a shell with nix-shell -p nodejs python3, running npm install and then running npm run lint <path>, it worked.

    Adding a shell.nix might go a long way :), but just expanding the instructions should be fine too.

    TLDR

    Usage:

    • nix-shell -p nodejs python3
    • npm install
    • npm run lint <path>

    Thanks for working on this! Expanding it seems very easy, just added a rule for makeWrapper which causes an eval failure when it's in buildInputs.

    opened by Mindavi 1
  • Bump cachix/install-nix-action from 17 to 18

    Bump cachix/install-nix-action from 17 to 18

    Bumps cachix/install-nix-action from 17 to 18.

    Release notes

    Sourced from cachix/install-nix-action's releases.

    install-nix-action-v18

    • Fix nodejs warnings & simplify maintenance
    • Use python3 when determining number of cores
    • Collapse installer log messages
    Commits
    • daddc62 Merge pull request #144 from cachix/fix-ci
    • 8500bf7 try to fix act test
    • 4024cf0 Merge pull request #143 from ggreif/patch-1
    • 3d1155e readme: don't perpetuate old versions
    • e17a164 fix #140: python -> python3
    • 92d3622 Merge pull request #139 from sigprof/collapse-log-output
    • 6c5ba55 install-nix.sh: Collapse log messages
    • 451e611 Merge pull request #134 from lovesegfault/composite-action
    • 112054f refactor: replace with a simpler composite action
    • 24e801e Merge pull request #123 from cachix/dependabot/github_actions/actions/setup-go-3
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Bump cachix/install-nix-action from 16 to 17

    Bump cachix/install-nix-action from 16 to 17

    Bumps cachix/install-nix-action from 16 to 17.

    Release notes

    Sourced from cachix/install-nix-action's releases.

    install-nix-action-v17

    Commits
    • d64e055 Merge pull request #133 from Artturin/nixciupdate
    • 0d8fd4b workflows/test.yml use macos-latest again and use nix release with
    • d8ecd38 workflows/test.yml: remove trailing whitespaces
    • 8e09c9a Merge pull request #129 from cachix/dependabot/npm_and_yarn/minimist-1.2.6
    • 9cc5350 Merge pull request #124 from cachix/dependabot/github_actions/actions/checkout-3
    • 9d24e62 Merge pull request #130 from ncfavier/user-profile
    • 1f78d39 Merge pull request #132 from lovesegfault/fix-nix-conf-copy
    • 0c1cffe chore(deps): bump actions/checkout from 2.4.0 to 3
    • 106f85d Merge pull request #131 from lovesegfault/curl-quiet
    • 83e7d63 Merge pull request #128 from cachix/fix-ci
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies 
    opened by dependabot[bot] 0
  • Add `--json` command line flag

    Add `--json` command line flag

    Currently we have the following output

    examples/syntax-error.nix:7 (7,5)-(7,15)
    examples/semantic.nix:6 (6,5)-(6,15)
    

    For composition with other tools, it would be good to have a CLI flag to output JSON instead.

    enhancement 
    opened by siraben 0
  • suggestions

    suggestions

    • [x] lint for configureFlags which are not lists ex. configureFlags = "--with-lua=yes"; should be configureFlags = [ "--with-lua=yes" ]; more examples https://github.com/NixOS/nixpkgs/pull/44423/files for https://github.com/NixOS/nixpkgs/pull/45886

    • [x] lint a single file, currently only whole dirs can be linted will be needed for ci usage

    $ nix run github:siraben/nix-lint -- ./pkgs/top-level/all-packages.nix
    ✔ What anti-pattern do you want to debug? ·
    Error: ENOTDIR: not a directory, scandir './pkgs/top-level/all-packages.nix'
        at readdirSync (node:fs:1392:3)
        at /nix/store/mka1y2a48sdq8gw254ibxdyllcj1pkzb-nix-lint/libexec/nix-lint/deps/nix-lint/built/index.js:84:34
        at step (/nix/store/mka1y2a48sdq8gw254ibxdyllcj1pkzb-nix-lint/libexec/nix-lint/deps/nix-lint/built/index.js:34:23)
        at Object.next (/nix/store/mka1y2a48sdq8gw254ibxdyllcj1pkzb-nix-lint/libexec/nix-lint/deps/nix-lint/built/index.js:15:53)
        at /nix/store/mka1y2a48sdq8gw254ibxdyllcj1pkzb-nix-lint/libexec/nix-lint/deps/nix-lint/built/index.js:9:71
        at new Promise (<anonymous>)
        at __awaiter (/nix/store/mka1y2a48sdq8gw254ibxdyllcj1pkzb-nix-lint/libexec/nix-lint/deps/nix-lint/built/index.js:5:12)
        at recurseDir (/nix/store/mka1y2a48sdq8gw254ibxdyllcj1pkzb-nix-lint/libexec/nix-lint/deps/nix-lint/built/index.js:82:12)
        at /nix/store/mka1y2a48sdq8gw254ibxdyllcj1pkzb-nix-lint/libexec/nix-lint/deps/nix-lint/built/index.js:152:86
        at Array.map (<anonymous>) {
      errno: -20,
      syscall: 'scandir',
      code: 'ENOTDIR',
      path: './pkgs/top-level/all-packages.nix'
    }
    
    opened by Artturin 0
Releases(v0.2.1)
  • v0.2.1(Dec 8, 2022)

  • v0.2.0(Dec 8, 2022)

    first release of nixpkgs-lint

    What's Changed

    • Flake pain by @ckiee in https://github.com/nix-community/nixpkgs-lint/pull/2
    • pkgConfig tree-sitter -> tree-sitter-nix by @Artturin in https://github.com/nix-community/nixpkgs-lint/pull/3
    • refactor flake by @Artturin in https://github.com/nix-community/nixpkgs-lint/pull/9
    • Add --json flag by @siraben in https://github.com/nix-community/nixpkgs-lint/pull/6
    • Bump cachix/install-nix-action from 16 to 17 by @dependabot in https://github.com/nix-community/nixpkgs-lint/pull/10
    • add makeWrapper in buildInputs lint by @Artturin in https://github.com/nix-community/nixpkgs-lint/pull/12
    • Rust port by @Artturin in https://github.com/nix-community/nixpkgs-lint/pull/13
    • Bump cachix/install-nix-action from 17 to 18 by @dependabot in https://github.com/nix-community/nixpkgs-lint/pull/15

    New Contributors

    • @ckiee made their first contribution in https://github.com/nix-community/nixpkgs-lint/pull/2
    • @Artturin made their first contribution in https://github.com/nix-community/nixpkgs-lint/pull/3
    • @siraben made their first contribution in https://github.com/nix-community/nixpkgs-lint/pull/6
    • @dependabot made their first contribution in https://github.com/nix-community/nixpkgs-lint/pull/10

    Full Changelog: https://github.com/nix-community/nixpkgs-lint/commits/v0.2.0

    Source code(tar.gz)
    Source code(zip)
Owner
Ben Siraphob
Class of '23, CS and math at Vanderbilt University.
Ben Siraphob
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Fancytree - JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkboxes, drag'n'drop, and lazy loading

Fancytree Fancytree (sequel of DynaTree 1.x) is a JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkb

Martin Wendt 2.6k Jan 9, 2023
🤪 A linter, prettier, and test suite that does everything as-simple-as-possible.

Features Fully Featured Code Grading Knowing if you need to work on your code is important- that's why we grade your code automatically. But, unlike o

Fairfield Programming Association 18 Sep 25, 2022
All-in-one code linter and formatter for TypeScript and JavaScript

Uniform is a CLI tool - code linter and formatter for JavaScript and TypeScript. Works using eslint and prettier under the hood.

Irakli Dautashvili 21 Feb 27, 2022
Yet another linter rule to detect compatibility of CSS features.

stylelint-browser-compat Yet another linter rule to detect compatibility of CSS features. This plugin checks if the CSS you're using is supported by t

Masahiro Miyashiro (3846masa) 16 Dec 15, 2022
NodeJS Implementation of Decision Tree using ID3 Algorithm

Decision Tree for Node.js This Node.js module implements a Decision Tree using the ID3 Algorithm Installation npm install decision-tree Usage Import

Ankit Kuwadekar 204 Dec 12, 2022
A refined tool for exploring open-source projects on GitHub with a file tree, rich Markdown and image previews, multi-pane multi-tab layouts and first-class support for Ink syntax highlighting.

Ink codebase browser, "Kin" ?? The Ink codebase browser is a tool to explore open-source code on GitHub, especially my side projects written in the In

Linus Lee 20 Oct 30, 2022
JqTree - Tree widget for jQuery

jqTree JqTree is a tree widget. Read more in the documentation. Features Create a tree from JSON data Drag and drop Works on ie9+, firefox, chrome and

Marco Braak 1k Dec 22, 2022
javascript implementation of logistic regression/c4.5 decision tree

LearningJS: A Javascript Implementation of Logistic Regression and C4.5 Decision Tree Algorithms Author: Yandong Liu. Email: yandongl @ cs.cmu.edu Upd

Yandong Liu 67 Aug 19, 2022
Little app for live coding effects for Matt Parker's xmas tree thing

Xmas Tree Lights App Little app for live coding and exporting effects for Matt Parker's Xmas tree experiment (2021 edition). You can check this out on

Pim Schreurs 8 Dec 12, 2022
Bootstrap an NFT minting site with Merkle tree whitelists.

??️ nft-merkle-whitelist-scaffold Bootstrap an NFT minting site with merkle tree whitelists. Go to nft-merkle-whitelist.vercel.app to see the latest d

jaclyn 87 Dec 24, 2022
Frontend, contracts, and merkle tree generator for use in quickly scaffolding ERC20 token airdrops.

Merkle Airdrop Starter Quickly bootstrap an ERC20 token airdrop to a Merkle tree of recipients. Steps: Generate Merkle tree of recipients by following

Anish Agnihotri 675 Dec 22, 2022
This package is an open source extension for MikroORM, which enables Nested Set Tree for your needs

MikroORM nested set This package is an open source extension for MikroORM, which enables Nested Set Tree for your needs Disclaimer For now, this packa

Kamil Fronczak 5 Dec 15, 2022
(🔗, 🌲) Web3 Link Tree is a free & open-source alternative to Linktree built with React.js, Next.js, Tailwind and Web3-React

Getting Started Read the detailed guide here Customize Add your name, wallet address, social media links and more in config.ts Images Save images to t

Naut 35 Sep 20, 2022
Visualize the Directed Acyclic Graph that Git creates to connect Commit, Tree and Blob objects internally.

Git Graph Visualize the Directed Acyclic Graph that Git creates to connect Commit, Tree and Blob objects. Hosted at HarshKapadia2.github.io/git-graph.

Harsh Kapadia 15 Aug 21, 2022
Library for calculating where to draw tree nodes, while avoiding overlap.

Tree Grapher Library for calculating where to draw tree nodes, while avoiding overlap. Installation 1) npm install tree-grapher --save-exact The --sav

Stephen Wicklund 1 Feb 7, 2022
Lazy evaluation list with high tree-shaking affinity and easy customization.

Lazy evaluation list with high tree-shaking affinity and easy customization. Features ?? Lazy Evaluation: The collections are only enumerated to the m

Masanori Onoue 22 Dec 28, 2022