Fork me on GitHub
#clj-kondo
<
2024-05-01
>
Noah Bogart15:05:12

is --dependencies like a --quiet flag? or does it only lint dependencies?

borkdude16:05:19

Yeah it’s a quiet flag

πŸ‘ 1
Noah Bogart16:05:35

purely for curiosity: i see pretty different times when running with and without the flag. any idea why that would be the case?

borkdude16:05:20

probably caching of jar files

borkdude16:05:39

also lots of analysis is skipped when linting only deps

πŸ‘ 1
Noah Bogart16:05:32

interesting, thanks

Noah Bogart16:05:58

just in case it's helpful:

$ time bin/clj-kondo
+ clj-kondo --parallel --lint .clj-kondo/config.edn dev src test
linting took 12150ms, errors: 0, warnings: 0

real	12.23s
user	12.98s
sys	1.00s
vs
$ time bin/clj-kondo --dependencies
+ clj-kondo --parallel --lint .clj-kondo/config.edn dev src test --dependencies

real	9.94s
user	11.07s
sys	0.77s

didibus17:05:29

Not sure about this. But could clj-kondo figure out if a lib is callable with -M, -X or -T ? I don't know if it's easy to infer from the code itself? Or if it could given the lib annotated its entry points ? Either way, then maybe we could have Zsh completion leverage clj-kondo or something to auto complete tools aliases

borkdude17:05:27

If the lib annotated being able to called with -X, then you could query it using clj-kondo using metadata from the analysis

seancorfield17:05:46

-X could invoke any function in the entire codebase that can accept a single hash map argument (it will happily invoke private functions). Same with -T. -M can invoke any -main in any namespace anywhere in the codebase. Since clojure.main exists in every Clojure program, all libraries are invokable with -M, and core contains several functions that will accept a single hash map so -X can be used with all libraries too. In other words, you'd have to have some sort of metadata annotation -- but then the completion would not be able to offer -M/`-X` in cases not specifically annotated but that would also work. And those options can have multiple aliases so I'm not sure how completion would work since the invokable functions available depends on the aliases used to construct the classpath which appear after the option itself?

didibus18:05:16

Ya, the annotation is probably better. Can't you just show all of them? If the classpath has 3 aliases, the you can execute any of their -X or -M no?

seancorfield18:05:44

A classpath has no aliases.

seancorfield18:05:57

I don't even think the runtime basis knows which aliases were used (on the command-line) to build the classpath...

didibus18:05:04

I'm confused, why the classpath? This would be based of the clj -X:deps aliases list. Or what you typed in the command, like clj -M:foo <tab> shows all annotated -M of foo

didibus18:05:41

So like, for all aliases listed by clj -X:deps aliases it would analyze them and also list all their -M and -X and -T from their annotations.

didibus18:05:34

Maybe we don't even need clj-kondo if we just come up with some convention of a file in the libs that can document their -X, -M and -Ts

seancorfield18:05:19

You said "If the classpath has 3 aliases"

didibus18:05:35

Oh ya, brainfart haha. Don't know why I said classpath

seancorfield18:05:55

So I looked at the runtime basis and there is :basis-config in that which lists the :aliases used as part of building it. So a program started via the CLI can tell what aliases were used to run it (I think that's relatively new?). clojure -X:deps aliases just lists aliases and where they are from (root, user, project). It does, currently, assume aliases have hash maps as their values which is an incorrect assumption (there's an Ask and a Jira for that). Looking at :aliases in deps.edn files alone does not give you enough information to determine whether -M or -X is appropriate (or -T or -A). To find annotations in source code, you'd need the classpath computed to know where to look.

didibus18:05:57

I just want clj <tab> to auto-complete with available aliases, but also their sub-commands. Or some some way at the command line I can see what I can do in a project basically.

seancorfield18:05:22

I understand what you want. I just don't think it's possible.

didibus18:05:19

If the libs exposed their doc in a machine readable way though?

didibus18:05:24

Currently, I open the deps.edn, look at the list of aliases, google them, look at their readme, and that's how I know how to call them, if I need -X, -T, and what sub-commands they take. If that doc was some easy to lookup thing, then we could automate that entire lookup no.

seancorfield18:05:26

How exactly do you envisage that actually working? At what point in typing clojure -M:thing ... or clojure -X:other ... do you imagine <tab> completion to provide something useful? You're saying it's hard to know whether to use -M or -X with an alias, but on the command-line you've already had to type either -M or -X before you type the alias names...

didibus18:05:45

Well, there's two possible UX. First one is something that just lists the available aliases and their commands(or help). Listing aliases is already here, though there's a bug but I'm assuming it works. So the bit missing is fetching for each some documentation to display. If that doc is in some structured format by convention, it could have a unified rendering. Ideally this is a feature of the Clojure cli itself (or -X:deps). But it could be something else that offers it. It means that either lib authors have to provide this file with this structured doc, or someone else has to provide it externally. The second UX is autocomplete. This is probably shell dependent. But it would be that when you type clj <tab> it just list all aliases and their available commands flattened. If you type clj -X:<tab> it lists the same filtered on those that can be called with -X, same for clj -T:<tab>, etc.

seancorfield19:05:38

> available aliases and their commands(or help) What is "their commands(or help)"? Where does that come from?

didibus19:05:41

Where exactly is TBD. But here's one possibility. It comes from a file called doc.edn which is top level in the package

seancorfield19:05:53

Top-level in what package? Aliases don't correspond to single packages. Aliases might have :extra-deps or might not. They might specify multiple libraries.

didibus19:05:00

Good point. Union of deps and extra-deps probably

seancorfield19:05:27

> If you type clj -X:<tab> it lists the same filtered on those that can be called with -X The problem here is that any alias can follow -X. Consider an alias that just has :jvm-opts to enable some Clojure behavior. That can be used with other aliases which may or may not have :exec-fn or :exec-args. You can say clojure -X:lots:of:aliases some-ns/my-fn and it will execute (some-ns/my-fn ...) regardless of what's in those aliases.

didibus19:05:33

For each package in :deps, :extra-deps or override-deps lookup their doc.edn if they have one at the root, and is so, display their current on a formated way or use it to auto complete

seancorfield19:05:42

Even if aliases include :ns-default, :exec-fn, or :exec-args, you can still use them with -A or -M.

seancorfield19:05:36

> For each package in :deps, :extra-deps or override-deps lookup their doc.edn if they have one at the root This would require fetching every possible dependency/version and looking in the downloaded artifact for doc.edn... and different aliases can pull down different versions of those artifacts that might have different doc.edn files.

didibus19:05:39

Well, alternatively, I thought it might be the alias itself that would expose the doc. So on the alias you might need :doc key where it points to the structured doc for that alias. Could be a git repo or local file or inline doc

didibus19:05:35

Ya, deps already pulled them all down and looks inside them to retrieve the deps.edn so I don't see the problem?

seancorfield19:05:22

Then it would be up to the user to put that :doc key into each alias -- which means they'd have to figure that out by looking at the repo where the instructions were on how to "install" the library's alias -- which seems like what you're trying to avoid?

didibus19:05:19

You already have to do that to "install" an alias. So I think that's fine

didibus19:05:04

No, I'm avoiding having to ever lookup the aliases and their doc after that

didibus19:05:19

I'd love a way to also auto-install the alias the first time, ala brew install, but I'm not tackling this here haha. It's less of a big deal if it's a one time thing.

seancorfield19:05:17

I don't think you've thought this through... the artifacts that you want to look inside depend on processing the aliases... so you can't know whether to use -M or -X until after you've already selected the aliases. As for annotating deps.edn manually, sure, you could do that. But everyone would have to do it for each alias they added to each project's deps.edn file, and that annotation would either need to be in the library's readme/docs or the user would have to figure it out when they added the alias manually, and also add this "documentation annotation".

didibus19:05:27

It wouldn't be too bad. If say I want to use antq. I copy/paste the alias from it's readme. If that alias includes the doc or a reference to it's doc. Now I should be able to list the aliases in my deps.edn or it's parents and also show the antq doc next to it's alias entry.

didibus19:05:46

Now if I have an alias to compile my project. I can add doc to it saying that "Used to compile project, options are X, Y, ..." And I mean the doc could be a bit better than a plaintext string. So maybe it has a :subcommands, and what not.

seancorfield19:05:57

OK, so "by convention" pick a key that is used for documentation, and have that key used by some tool that displays it... sounds like it really needs to be part of the CLI and -X:deps aliases would use it... so go create an Ask for that (I'd upvote it). And if a user decides to combine multiple libraries into a single alias, they can use that doc key as they wish. And if users want a library to explain usage automatically, they can create an issue or submit a PR to add this doc key to the library's readme/docs.

seancorfield19:05:51

(it needs to be a standard key across all libraries/tools which is why I think it needs to be in the core CLI itself)

πŸ’― 1
didibus19:05:25

Ya, I think that be good enough. Now if I pull down a project for example, I know how to quickly list everything I "can" do in this project. By seeing the aliases and a doc about how to use each one and what they are for.

seancorfield19:05:38

And the "nice" thing about this approach is that it is totally opt-in, open-ended, and doesn't require tooling to try to locate/inspect artifacts at all.

seancorfield19:05:01

LMK when you've created the Ask so I can go upvote it πŸ™‚

didibus19:05:09

Sounds good. I'm juggling a baby so it might take some time, but I'll remind you when I do haha.

seancorfield19:05:05

I suspect I'll have that image in my head every time I see you post messages for the next several days πŸ™‚

2
seancorfield19:05:46

didbus types with one hand while throwing a baby in the air with the other... πŸ‘¨β€πŸΌ:skin-tone-2:

didibus19:05:55

Haha, it's ready to be prompted for image generation

seancorfield19:05:03

I resisted that urge... barely...

didibus19:05:20

I didn't haha

1
seancorfield19:05:51

Argh! Those fingers... :rolling_on_the_floor_laughing:

🦎 2
James Amberger21:05:49

It’s expected that (#'myfun this arity is wrong) will go unreported right?

borkdude21:05:34

Hmm, good point:

$ clj-kondo --lint - <<< "(#'inc 1 2)"
linting took 10ms, errors: 0, warnings: 0
I guess this could be improved

rafaeldelboni12:05:42

Kinda off topic, but I'm curious now, what is the point of using #' before the function name?

Stig Brautaset14:05:28

We use it in tests to add unit tests for private functions. We configure clj-kondo to allow this kind of private var access in tests, but not in production code, e.g. something like:

:ns-groups [{:pattern ".*-test$" :name test-namespaces}]
 :config-in-ns {test-namespaces {:linters {:private-call {:level :off}}}}

πŸ‘ 1
🀯 1
rafaeldelboni15:05:53

til ! thanks for the use case :)

til 1