Fork me on GitHub
#clj-kondo
<
2023-07-08
>
Vikas Gautam12:07:10

I am stuck at trying to add a custom hook to lint a macro defined in my https://github.com/Vikasg7/jdsl parser combinator library, I wrote. I tried to follow the hooks.md in the clj-kondo docs but failing. Here is the https://github.com/Vikasg7/jdsl, please checkout to clj-kondo-hook branch. As I am going with macroexpand approach in the hooks.md, here are the steps I followed. 1. I created the dev profile with a dependency on lein-clj-kondo as below. It enabled me to test my hook in the vscode using calva. :profiles {:dev {:dependencies [[com.github.clj-kondo/lein-clj-kondo "0.2.5"]]}} 2. I copy pasted jdsl.basic/do macro to hooks.basic/do in the .clj-kondo folder. I successfully tested my hook using following.

(def macro
  "(jb/do
      jp/any-char
      (jp/any-char)
      (jp/char \\a)
      (a <- (jp/char \\a))
      (b <- jp/any-char)
      (_ <- jp/any-char)
      (jc/return [a b]))")

;; following print statement works and prints the exact same api/list-node as the
;; analyze-hook would print as I tested earlier.
(println (api/macroexpand #'hooks.basic/do (api/parse-string macro) {}))
;; prints following list-node as printed by analyze-hook approach
;; <list: (clojure.core/fn [ts] (clojure.core/let [[_ ts] (#function[jdsl.basic/run] jp/any-char ts) [_ ts] (#function[jdsl.basic/run] jp/any-char ts) [_ ts] (#function[jdsl.basic/run] (jp/char \a) ts) [a ts] (#function[jdsl.basic/run] (jp/char \a) ts) [b ts] (#function[jdsl.basic/run] jp/any-char ts) [_ ts] (#function[jdsl.basic/run] jp/any-char ts)] (#function[jdsl.basic/run] (jc/return [a b]) ts)))>
3. I added the corresponding entry in the config.edn file as below: {:hooks {:macroexpand {jdsl.basic/do hooks.basic/do}}} 4. saved and restarted the vscode. 5. Checked the jdsl.basic-test in the test folder but linter is not linting the usage of do macro. 6. I tried following command as well but failed with and without --cache false npx clj-kondo --lint src test 7. here is the error output I am getting.
E:\Desktop\clojure\jdsl>cat test\jdsl\basic_test.clj | npx clj-kondo --lint -
WARNING: file jdsl/basic not found while loading hook
WARNING: error while trying to read hook for jdsl.basic/do: Could not find namespace: jdsl.basic.
<stdin>:37:16: error: Unresolved symbol: a
<stdin>:37:18: error: Unresolved symbol: <-
<stdin>:38:16: error: Unresolved symbol: b
<stdin>:40:15: error: jdsl.char-parser/skip-any-char is called with 0 args but expects 1
<stdin>:41:16: error: Unresolved symbol: e
<stdin>:49:16: error: Unresolved symbol: _
<stdin>:50:15: error: jdsl.char-parser/any-char is called with 0 args but expects 1
linting took 4859ms, errors: 7, warnings: 0
I tried to find and follow the Github issue but couldn't find the solution. PS. looking at those warning, seems like clj-kondo is unable to resolve the jdsl.basic/do macro located in src/jdsl/basic.clj file, not sure how to fix that. VERSION info - npx clj-kondo version v2023.05.26 calva version info- Calva version used: v2.0.374 clojure-lsp version used: 2023.07.01-22.35.41 clj-kondo version used: 2023.06.02-SNAPSHOT Clojure version - 1.11.0 Thanks in Advance. Vikas

borkdude15:07:45

There's a lot of stuff here. I think it's better to put this in a Github reo that I can run locally

borkdude15:07:06

But surely

WARNING: file jdsl/basic not found while loading hook
WARNING: error while trying to read hook for jdsl.basic/do: Could not find namespace: jdsl.basic.
is the root of the problem

Vikas Gautam15:07:00

Thanks for reply Sir. Repo is ready. https://github.com/Vikasg7/jdsl checkout to clj-kondo-hook branch.

borkdude15:07:05

The issue is with:

(:require [jdsl.basic :as jb :refer [run]])

borkdude15:07:17

if you want to run this namespace in the clj-kondo hooks interpreter, you need to add it to the config

Vikas Gautam15:07:57

oh... what is the keyvalue pair to add it?

borkdude15:07:17

why do you want to do this?

borkdude15:07:34

What is the purpose of returning:

(list run form 'ts)

Vikas Gautam15:07:11

you can read the do macro doc string.

Vikas Gautam15:07:04

every form is a parser and I want to run the parser with the token-stream ie. ts as argument and pass the ts to the next parser call.

borkdude15:07:10

I think what you are looking for is really:

(ns hooks.basic
  (:refer-clojure :exclude [do])
  (:require [jdsl.basic :as-alias jb]))

(defn- expand->bindings 
  "Expands `parser`, `(parser)`, `(a <- parser)`, `(parser args)` forms 
   in the do macro to `let` bindings."
  [form]
  (if-not (list? form)
    [['_ 'ts] (list `jb/run form 'ts)]
  (if (= 1 (count form))
    [['_ 'ts] (list `jb/run (first form) 'ts)]
  (let [[sym op prsr] form]
  (if (= '<- op)
    [[sym 'ts] (list `jb/run prsr 'ts)]
    [['_ 'ts] (list `jb/run form 'ts)])))))

(defn- expand->body
  "Expands the `parser`, `(parser)`, `(parser args)` form 
   in the do macro to `let` body"
  [form]
  (if-not (list? form)
    (list `jb/run form 'ts)
  (if (= 1 (count form))
    (list `jb/run (first form) 'ts)
    (list `jb/run form 'ts))))

borkdude15:07:39

you don't want to return a list with the function from your library, but a list with a symbol that points to the function of your library

Vikas Gautam15:07:12

yes, it sounds correct, I think I might have tried api/token-node 'jdsl.basic/run along that spirit.

Vikas Gautam15:07:17

lemme test above.

Vikas Gautam15:07:54

it worked thanks, so will it work If I lein-git-down and use this as dependency in my other repo? Actually, I use this library to make parser for the interpreter, I am writing in clojure. Also, is :as-alias any different from :as here? Thanks for the quick help. Really Appreciate it.

borkdude15:07:21

as-alias only introduced an alias, but does not load a library

borkdude15:07:09

you can read here how to "export" your configuration so it will be visible to anyone who uses your library: https://github.com/clj-kondo/clj-kondo/blob/master/doc/config.md#exporting-and-importing-configuration

Vikas Gautam15:07:17

Sure, thanks once again. You are a life savor. I was stuck on this for 2 days.

🙏 2
hifumi12322:07:37

Which version of clj-kondo was the :misplaced-docstring linter introduced? It seems that lein-clj-kondo doesn't have it, but the version bundled with the latest clojure-lsp does

borkdude22:07:51

I don't know, but you can include a newer clj-kondo as an extra dependency so lein-clj-kondo uses that one

borkdude22:07:15

also you can probably just use a git blame on src/clj_kondo/impl/config.clj to check yourself

ericdallo22:07:21

also, there is the clojure-lsp diagnostics which should behave the same as the editor + extra linters you see in the editor

hifumi12322:07:06

Thanks, @U04V15CAJ and @UKFSJSM38, I will try doing these things soon

hifumi12300:07:01

I attempted using [clj-kondo "2023.05.26"] as a managed dependency, but lein-clj-kondo does not pick this up when I use it as a plugin. Am I supposed to use exclusions?

hifumi12301:07:22

OK I think I see the problem — lein-clj-kondo is not evaluating code in the project, so it is always going to use its own clj-kondo version, regardless of what the project specifies

borkdude06:07:38

Does lein not allow to insert newer deps into plugins? That would surprise me about a dep management tool

hifumi12308:07:44

The problem is there are multiple evaluation contexts in leiningen

hifumi12308:07:57

To ensure proper isolation, you can either eval in project, eval in leiningen, or even set up your own classpath entirely

hifumi12308:07:16

It looks like lein-clj-kondo evaluates in a context isolated from the project, so there is nothing the project can do to mess with the plugin

hifumi12308:07:43

Likewise, whatever dependencies the lein-clj-kondo plugin uses will not mess with the project’s classpath

hifumi12308:07:39

so while you are able to use exclusions, managed dependencies, etc. in a project, none of these will ever end up affecting lein-clj-kondo since lein-clj-kondo does not eval-in-project to begin with

hifumi12308:07:58

for now i have decided to fork lein-clj-kondo, update the dependency, and deploy it in a private maven repository

borkdude09:07:31

Feel free to PR the update

hifumi12303:07:13

after some investigation, i realized that https://github.com/clj-kondo/clj-kondo/issues/2001 made the following NOT trigger misplaced docstring

(deftest foo
  "not a docstring"
  (is ...))

hifumi12303:07:44

so clojure-lsp is using an older version of clj-kondo before this was merged, presumably, because clojure-lsp does warn me about it

hifumi12303:07:05

this resulted in a bit of a rabbit hole finding out why clojure lsp would complain about code that passed lint tests in CI 😄

hifumi12303:07:50

% clojure-lsp --version
clojure-lsp 2023.02.27-13.12.12
clj-kondo 2023.02.17
alright, that explains everything now

hifumi12304:07:18

I am working on a project with a friend who is very new to clojure and makes a lot of silly mistakes. So I have many clj-kondo linters set to :level :error so that he avoids many bad writing styles. In particular, he attempted writing a docstring for a test, but I dont think deftest even accepts docstrings. The :misplaced-docstring linter was helpful in finding this mistake. But later versions of clj-kondo no longer do this for deftest forms.

borkdude08:07:32

AFAIK deftest never took a docstring

hifumi12308:07:19

Yeah. It looks like someone requested to make the :misplaced-docstring linter not warn about strings in a deftest form, though I personally liked the old behavior.

borkdude09:07:09

In general this should be reported as unused-value but it doesn't do this right now. I'll fix that

👍 2
ericdallo11:07:22

BTW you have a outdated clojure-lsp, so outdated kondo, latest version is from July, you are using one from February