candid82 / joker Goto Github PK
View Code? Open in Web Editor NEWSmall Clojure interpreter, linter and formatter.
Home Page: https://joker-lang.org/
License: Eclipse Public License 1.0
Small Clojure interpreter, linter and formatter.
Home Page: https://joker-lang.org/
License: Eclipse Public License 1.0
Probably not ideal as a default but given that def*
macros is a very common thing it could be nice.
Just a thought, just close if you think this is a bad idea :)
I'd like Joker linter to give a warning on the following:
(if true 1)
Often this happens when I mistakenly forget to handle the else case.
The warning could be: "if with only one branch, use when".
Currently joker provides the column where an error/warning "starts" but not where it ends. When an undeclared var is used or similar it would be useful to know start and end columns so the issue can be properly highlighted in editors.
this might actually be two issues, the first is with one-armed reader contionals
(ns user (:require [clojure.set :as set] #?(:cljs foo.bar)))
which throws
Read error: Unexpected )
The other valid syntax for contional require where the clj platform has no matching requirement is
(ns user (:require [clojure.set :as set] #?@(:clj [] :cljs [foo.bar])))
which throws
cljc:1:1: Eval error: No value supplied for key true
my system:
joker --version v0.8.3
ls ~/.joker No such file or directory
I recently wrote a linter for https://github.com/w0rp/ale (a vim plugin for async linting). Joker works really really well for this due to it's fast startup speed and nice outputs.
However having spent a couple of days using it I started running into an issue where joker didn't seem to detect my .joker
file. Looking deeper into the issue, I found it was because ale was writing the contents of my file to a /tmp/xzy.clj
file then linting that, loosing the context of the original sources directory and thus its .joker
file.
Swapping the ale linter to pipe the files contents to stdin worked... until I changed directory and again lost the context of my working directory. finally frustrated I swapped the linter to just read the file off the disk and now it only works on saving the file.
Ideally I would like to add a flag to the linter to parse in the config directly:
joker --lint --config='{:known-macros [bar/def-something foo/another-macro ...]}' <filename/stdin>
or
joker --lint --config='/path/to/file/.joker' <filename/stdin>
or
joker --lint --working-dir='/path/to/file/' <filename/stdin>
however the current main doesn't leave much leeway in terms of adding additional flags.
Instead of parsing os.Args
manually something along the lines of the flag lib would give more flexibility. I had a mess about last night converting it use pflag just to see if it would work and it appears functional (if a bit ugly).
Is this something that seems reasonable? I don't want to break anything in the repl/interpreter.
Namespace aliases created with the alias
function don't seem to be recognized by the linter. For example, if I define (alias 'stc 'clojure.spec.gen.test)
and later use ::stc/ret
, joker --lint will give an "Unable to resolve namespace stc" error.
In (ns some.place)
I have a function
(defn get [options]
(do-something))
I get the following warning (in NeoVim):
WARNING: get already refers to: #'joker.core/get in namespace user, being replaced by: #'user/get
Does anyone know if there's a workaround for this?
(case val
("F" "f") false ;; Parse warning: F is not a function
true)
(case val
("F" "f") "false" ;; ok
true)
(case val
("T" "t") true ;; ok
false)
v0.8.9. I think this appeared in one of the recent versions, not sure in which.
Looks like github's syntax hl has the same problem 😄
Example:
(ns dre.integration.frontend.core
(:use [etaoin.api :as eta :exclude [chrome]])
(:require [etaoin.keys :as k]))
(def chrome (eta/chrome)) ;; Unable to resolve symbol eta/chrome
Upon running:
$ go get github.com/candid82/joker
I get:
github.com/candid82/joker/core
go/src/github.com/candid82/joker/core/procs.go:1594:28: undefined: linter_allData
go/src/github.com/candid82/joker/core/procs.go:1600:27: undefined: linter_cljxData
go/src/github.com/candid82/joker/core/procs.go:1604:28: undefined: linter_cljData
go/src/github.com/candid82/joker/core/procs.go:1606:28: undefined: linter_cljsData
go/src/github.com/candid82/joker/core/procs.go:1805:14: undefined: coreData
go/src/github.com/candid82/joker/core/procs.go:1806:14: undefined: timeData
go/src/github.com/candid82/joker/core/procs.go:1807:14: undefined: mathData
Also I was able to install the binary from the download page successfully and installed the Emacs library flycheck-joker and it works awesomely! Just wanted to thank you for writing such a cool project.
Another question: does this library suffer from flycheck-clojure's issue:
Do not use squiggly-clojure unless your code can be reloaded without side effects, as the linters will be reloading it repeatedly.
I'm using flycheck-joker in spacemacs and I'm very happy with what it provides.
However, one thing that bothers me quite a lot is that joker reports deftest
and is
as unresolved symbols.
Here's the minimal repro for me:
(ns myapp.util-test
(:require [myapp.util :as u]
[clojure.test :refer :all]))
(deftest namespaced-map
(testing "keys are namespaced"
(let [unqualified-keys {:name "Juraj" :age 32}
qualified-keys #:user{:name "Juraj" :age 32}]
(is (= qualified-keys unqualified-keys)))))
I realized that this might be because deftest
and is
are macros so I tried to add following to ~/.joker (inspired by https://github.com/candid82/joker#reducing-false-positives):
{:known-macros [clojure.test/deftest clojure.test/testing clojure.test/is clojure.test/are]}
No success, however.
Any ideas why that happens?
Is it something that should work out of the box?
In ClojureScript, it's possible to alias macros under the same alias as non-macros. Joker panics in this situation. In core async, since the macros are in a different namespace than the functions it's desirable to alias them like this:
(ns example.macros
(:require-macros [cljs.core.async.macros :as async])
(:require [cljs.core.async :as async]))
$ joker --lint test.cljs
test.cljs:1:1: Eval error: Alias async already exists in namespace user, aliasing cljs.core.async.macros
Stacktrace:
global test.cljs:1:1
joker.core/require <joker.core>:3323:3
joker.core/apply <joker.core>:509:4
joker.core/apply__ <joker.core>:3243:9
joker.core/apply <joker.core>:509:4
joker.core/apply__ <joker.core>:3202:5
joker.core/with-bindings* <joker.core>:1382:7
joker.core/apply <joker.core>:507:4
joker.core/apply__ <joker.core>:3217:9
joker.core/alias <joker.core>:2372:3
When linting in my editor, Joker doesn't seem to respect the .joker
file in my project root, and I think this is because when Joker is receiving input over stdin, it doesn't know where the file it's linting is located, and so doesn't know where to start looking for the .joker
file.
Would it be a good idea to be able to pass the file path in addition to the unsaved text over stdin?
I understand that joker
doesn't try to resolve symbols from external namespaces, and it does show an error if I use a symbol that was referred with a :refer :all
in the require
form.
I do not use :refer :all
much, but there are a few cases (like com.rpl.specter
) where I make an exception, and I would be fine with configuring joker
to know about those few exceptions.
Would it be easy to add an option I could put in the .joker
config file :known-unqualified-syms [ALL collect collect-one MAP-KEYS ... ]
and then not get false positives from joker
when using those symbols unqualified? (or, is there another way to silence these warnings that I missed?)
If someone can point me in the right direction, I might be able to do it myself. I just discovered joker
today (and it's awesome! 🚀 ).
Datomic's #db/fn
tagged literal is current flagged with an error "No reader function for tag db/fn". Perhaps a :known-tags
feature would mitigate this? This particular case also has the possibility of introducting local symbols in the :params
attribute, would be nice-to-have to avoid that, but it's a pretty limited use-case.
I would love to be able to provide linter messages to the user while they're typing (before the file has been saved). I can provide both the current edited unsaved text and the file path, but I think I would need a way to pass the code text via the command line.
This is kind of a "nice-to-have", so I understand if it's out of scope, but it would be cool if this were possible.
I am not quite sure if this is too specific, but there is an issue with referred macros in ClojureScript and om.next. I'll show you an example:
$ joker -v
0.8.4
The tooltip says "Unable to resolve symbol: HelloWorld" etc.
Console output:
$ joker --lint hello.cljs
hello.cljs:9:8: Parse error: Unable to resolve symbol: HelloWorld
hello.cljs:13:3: Parse error: Unable to resolve symbol: Object
hello.cljs:14:4: Parse error: Unable to resolve symbol: render
This is not really a big thing, but I wanted to add this for completeness, because I really like your project and there will be many people developing ClojureScript and seeing this false-positive.
Thanks for your work! I'd help you with this, but I can't program Go...
Joker complains about the \033
escape sequence. Using \e
is also problematic. These are commonly needed for ansi escape terminal sequences, like color printing.
(defn foo []
(println "\033[31mFOO\033[0m")) ; print FOO in red
% joker --lint src/foo/core.clj
src/foo/core.clj:151:17: Read error: Unsupported escape character: \0
I spotted this in the atom-parinfer source code. I suspect that it's guessing wrongly as to what array
is being referenced in the code.
Downloaded and installed the 0.8.3 Windows binary. I can run "joker" and get a prompt, but running "joker --lint foo.clj" just burns CPU for several minutes, exits with no obvious output.
Clojure 1.9 allows the following:
(require '[com.acme.foo :as foo])
(let [{::foo/keys [bar]} {:com.acme.foo/bar :YUP}]
bar)
;; => :YUP
But joker signals an Unable to resolve symbol: bar
error.
I may be alone in this request, but I often like to use :as
in destructuring to name a map for descriptive purposes, even though I don't use the binding. Is it possible to ignore measurement here?
e.g.
(defn my-fn [{:keys [value] :as measurement}]
value)
Thank you for this tool. It has already improved my life massively when used via vim.
->
and ->>
with one arg could have it's use cases. For ex. mapping "to a structure":
(map #(-> [%]) [1 2 3]) => ([1] [2] [3])
(map #(-> {:foo %}) [1 2 3]) => ({:foo 1} {:foo 2} {:foo 3})
(map #(-> `(~%)) [1 2 3]) => ((1) (2) (3))
which cause "No forms in ->". This has to be written like
(map #(vec [%]) [1 2 3]) ;; i put vec in your ver so you get vec...
(map #(assoc {} :foo %) [1 2 3]) ;; almost like m = {}; for i in ...
(map #(list %) [1 2 3]) ;; ok, this probably is a tie
I assume the linter wants to guard against mistakes like
(let [val ...]
(-> val)
(do-something-with-val)) ;; should be in ->
but I can't think of any examples where this could go unnoticed and not cause problems immediately.
Suppose I have test.clj
:
(ns foo.core
(:require [bar.baz]))
This gives me a warning, "unused namespace bar.baz". I'm assuming the following configuration in .joker
would inhibit it, but no luck:
{:ignore-unused-namespaces [bar.baz]}
Other configuration options like known-macros
work as expected. It makes no difference whether I'm linting Clojure or ClojureScript files. I'm using v0.9.1 on Arch Linux.
First of all, thank you for all the work you are putting into this. Using flycheck-joker for linting in emacs became part of my daily coding.
For this reason, I was trying to package joker for the nix package manager which I've been using a lot lately, but I ran into a problem as currently, I am unable to build v0.8.5 from source, seeing as I get this error:
building
../std/generate-std.sh: line 4: joker: command not found
I am able to build the master branch and if I understood correctly the issue I'm having was fixed with the commit "Commit joker generated files". Would there be a plan for releasing a new version with the latest fixes soon? I'd love to be able to finish packaging it for use in nix, whenever a new version is out (Hope this sounds good to you!).
I've found that using the joker linter is great to catch typos and syntax errors that I usually would miss until executing the code, so it's a huge time saver.
Comparing it to linters I use in other languages, I think it could benefit from showing a warning when a required or declared var is never actually used. This can help to catch stuff like you forgot some step in your logic, or you're not referencing the var you actually meant, or simply you didn't do the proper cleanup after a refactor.
Thanks for the good work!
I'm probably just missing something but the README mentions stdin support, shouldn't that mean the following should work?
cat boot/core/src/boot/cli.clj | joker --clojure --lint
Thanks! :)
http://cljs.github.io/api/syntax/dot
This allows doing things otherwise not allowed in Clojure. Examples are e.target.value
(accessing a property of a variable), Math.PI
(accessing a property of an imported object), (XHR.send ...)
(calling a property belonging to an imported object). I've taken a brief look at the code, but haven't found CLJS-specific code for interop, so I suspect both Clojure and ClojureScript are treated the same.
Is it possible to also lint code inside a comment expression?
(foo x) ;; Unable to resolve symbol: foo
(comment
(foo x) ;; No warning
)
I'm playing quite a bit with shadow-cljs and the way it works with npm is that instead of using symbols in :require
it uses strings.
Example:
(ns app.fb-auth
(:require ["firebase" :as firebase]
[clojure.string :as string]
[app.state :as state]))
is there anything I could do about this?
Thank you
I'm loving the unused vars linter but in my current project I'm finding that many public vars and some namespaces are simply never called or required elsewhere in the app.
It would be great if joker could somehow lint these as well. What are your feelings on this idea?
I see two possible ways to accomplish this. The first would be to simply take a list of source-dirs and write an index of used ns/vars to file, then subsequent lints of single files could read that index and call out missing vars while updating the index for it's calls.
The other way, a user provide a main fn and joker could statically trace calls, and produce a call graph with anything outside of the graph producing a warning. This graph could be useful for other cursive/intellij like analyses.
It is common practice to specify a function prior its implementation.. But when I do this with joker-linting enabled, it says "Unable to resolve symbol: add".
For example:
(require '[clojure.spec.alpha :as s])
(s/fdef add
:args (s/cat :x int? :y int?)
:ret int?)
(defn add
"Insecure add. Not the best idea."
[x y] (+ x y))
That is just a small thing, just a nice-to-have feature to remove this false-positive. I am usually using joker in combination with flycheck (I even created a small spacemacs-layer for it) and I have always this warning in my editor ;-)
Thank you!
go version
go version go1.8.3 linux/amd64
go build
# github.com/candid82/joker/std/time
std/time/a_time.go:127: time.Duration(d).Round undefined (type time.Duration has no field or method Round)
std/time/a_time.go:219: time.Duration(d).Truncate undefined (type time.Duration has no field or method Truncate)
I am trying to build it using go get .
and then go build
but it fails at go get
itself.
The file is called .joker and should be in your home directory. It should contain a single map with :known-macros key
Why can't we use .joker
in root directory of the project?
We just want to make same linter options for whole team. It would be great if along with ~/.joker
, it will look at project root directory.
Thanks!
I'm not sure if this expected behaviour but when I have a clojure file like this:
;foo.clj
(ns foobar.core)
(joker.string/split "ha-ha-ha-ha" #"-")
and I run the linter I get no errors:
$ joker --lint foo.clj
$ joker --lintclj foo.clj
If I introduce an error by removing the pattern from the original example:
;foo.clj
(ns foobar.core)
(joker.string/split "ha-ha-ha-ha")
you get joker errors
$ joker --lint foo.clj
foo.clj:4:1: Parse warning: Wrong number of args (1) passed to #'joker.string/split
$ joker --lintclj foo.clj
foo.clj:4:1: Parse warning: Wrong number of args (1) passed to #'joker.string/split
I'm expecting something along the lines of this when I lint this clojure file as the joker dialect:
;foo.clj
(ns foo.core)
(clojure.string/split "ha-ha-ha-ha" #"-")
$ joker --lintjoker input.clj
input.clj:4:2: Parse error: Unable to resolve symbol: clojure.string/split
A recent version of ClojureScript introduced the :npm-deps compiler flag (blog post). The example used in the blog post is:
;; src/example/core.cljs
(ns example.core
(:require left-pad))
(enable-console-print!)
;; pad the number 42 with five zeros
(println (left-pad 42 5 0))
In joker's lint mode, this currently throws two errors: One for the unused namespace and one at the site of the function call (unable to resolve symbol).
P.S. I'm still learning my way around ClojureScript and I've integrated joker's linter into my editor and it's helping quite a bit. Thank you!
When linting boot/core.clj joker throws an exception near the end of the file.
In your opinion, could we Joker’s pprint to format Clojure source code?
I downloaded the Windows binary (v0.7.1), and ran it as described - however, the program itself is just the interpreter. I exited out of the program and try to run joker
, to no avail:
'joker' is not recognized as an internal or external command,
operable program or batch file.
How do I install joker
on Windows?
Not an issue per se, but just wanted to say thanks for writing such a useful tool! I use it everyday at work, and it helps me tremendously 💯
I'm getting this error on line:
>>> 15 (s/def ::original_total (s/and double? pos?))
am I miss something, or joker doesn't support double?
function?
I'm using the linter for cljc
files and it works good except for reader conditionals, which give the warning No reader function for tag ?
. Also ClojureScript expressions inside those conditionals may show up as errors:
Allowing the #?
and maybe ignoring whatever's inside of them would be great.
Thanks for this project!
Clojure 1.9 introduces map namespace syntax, which allows to write
#:person{:first "Han" :last "Solo"}}
which is read as
{:person/first "Han" :person/last "Solo"}
Currently joker complains about this:
vlaaad@ubuntu ~/P/transportal> joker --lint src/common/clj/transportal/seeder.clj
src/common/clj/transportal/seeder.clj:237:7: Read error: Reader tag must be a symbol
It would be great if joker supported such syntax
I tend to remove namespace requires that have squiggles in Emacs, but sometimes this is a duplicate require instead of an obsolete require. Then I will remove some refers that were needed, but should be combined in the single require.
Is it possible to get a different color in the squiggle for duplicate requires and unused requires?
Just created a #joker channel on Clojurians Slack where we (hopefully) can discuss useful things to do with Joker. Maybe it's nice to mention it in the README?
I have a macro that introduces a local symbol and it's used like this:
(api/with-validated-params [::api-spec/reset-new-stats nil]
(act/visit (:user-id-int params) (:pagename params))
(resp/response {})))
The macro takes (:params req)
, applies the conforming clojure.spec
stuff, and introduces a local binding of params
. Unfortunately, Joker flags the use of params
on the next line as invalid.
I verified that :known-macros
is working correctly here: if I add foo
immediately after with-validated-params
in that code, Joker doesn't flag that -- so it's assuming that a macro is invoked with a symbol and that is defining something new.
I guess it doesn't allow for a deliberately unhygienic macro that introduces a new local binding?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.