clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
2020-09-07T18:06:05.081600Z

Hi everyone, Can I write a multi-spec for the component/config segment of this data based on the component/type which is not part of component/config's corresponding value? :

{:component/type   [:instance-manager :v-2.0.0]
 ;;-----------------------------------------;;
 :component/config {,,,
                    }
 ;;-----------------------------------------;;
 :component/deps   {}}
(I'm using spec1) Thanks a lot

2020-09-07T18:07:06.081700Z

the component/config part has to be extensible ... so different components of the system across different namespaces define their own internal config map

borkdude 2020-09-07T18:31:57.082800Z

Is it possible to inspect an evaluated regex spec?

(def x int?)
(s/fdef foo :args (s/cat :x int? :y x))
(prn (::s/op (s/cat :x int?))) ;; :clojure.spec.alpa/pcat
(prn (::s/op (:args (s/get-spec 'user/foo)))) ;; nil
Use case: I'd like to know what the x resolved to. Just inspecting the form won't tell me that.

borkdude 2020-09-07T18:52:04.083400Z

I hoped I could get more into the structure of the regex, but it seems to be an opaque thing

borkdude 2020-09-07T18:54:10.084Z

Otherwise formulated: it is possible to get back to the int? function once it's wrapped inside this reified spec object?

(s/spec int?)

borkdude 2020-09-07T20:10:34.084300Z

Maybe I'm looking for datafy on specs

2020-09-07T20:28:40.084700Z

@borkdude (s/form (s/spec int?)) => 'clojure.core/int?

2020-09-07T20:29:02.085Z

is I think what you’re looking for

borkdude 2020-09-07T20:35:57.085900Z

@tekacs That's already better!

(clojure.spec.alpha/cat :x clojure.core/int? :y user/x)

2020-09-07T20:36:39.086800Z

@borkdude

(let [{:keys [x]} (rest (s/form (:args (s/get-spec 'user/foo))))] x)
=> clojure.core/int?

2020-09-07T20:37:01.087700Z

definitely not ideal, but that works?

borkdude 2020-09-07T20:37:03.087800Z

I kinda wish that I could have user/x resolved to clojure.core/int? as well, since this information is available in the spec itself

2020-09-07T20:38:25.088700Z

right — though you wouldn’t usually use def to define a sub-spec

2020-09-07T20:38:57.089600Z

you’d usually have done:

(s/def ::x int?)
(s/fdef foo :args (s/cat :x int? :y ::x))

borkdude 2020-09-07T20:38:59.089700Z

yeah, I guess using this for linter stuff is alright, but then I might as well just inspect the raw sexpr directly

borkdude 2020-09-18T17:35:10.000400Z

Thanks. Added link to https://github.com/clj-kondo/inspector/issues/4

borkdude 2020-09-07T20:39:15.090400Z

yes, but in that case you still get :user/x

2020-09-07T20:39:46.090700Z

right, but

(s/def ::x int?)
=> :user/x
(s/form (s/spec ::x))
=> clojure.core/int?

2020-09-07T20:39:58.091Z

if you pass those through s/spec it resolves them

borkdude 2020-09-07T20:40:01.091200Z

right, you can recursively call that on qualified keywords

2020-09-07T20:40:10.091500Z

right, precisely

borkdude 2020-09-07T20:40:15.091900Z

cool, thanks!

👍 1
2020-09-07T20:40:20.092100Z

indeed you can safely pass most things through (s/form (s/spec …)) I believe

borkdude 2020-09-07T20:40:45.092600Z

@tekacs purpose of this exercise: https://gist.github.com/borkdude/c0987707ed0a1de0ab3a4c27c3affb03

2020-09-07T20:41:13.093100Z

I’ve since moved to malli but I’m excited for this! 🙂

2020-09-07T20:41:33.093600Z

I saw that you posted in #malli too 🙂

2020-09-07T20:42:17.094400Z

I also forked aave for malli to add CLJS support and some additional features I haven’t seen elsewhere (https://github.com/tekacs/aave), so I should probably pay attention to the clj-kondo type spec 🙂

borkdude 2020-09-07T20:43:19.094900Z

@tekacs That's cool, you can use the same kind of trick indeed

👍 1
borkdude 2020-09-07T20:52:36.095300Z

@tekacs

❤️ 1
borkdude 2020-09-07T20:54:48.095800Z

(code updated here: https://gist.github.com/borkdude/c0987707ed0a1de0ab3a4c27c3affb03)

kenny 2020-09-07T20:56:05.096100Z

This is awesome. Support for s/keys would be a huge productivity win. We have many functions that take large maps as params and it's so easy to forget or misspell one.

kenny 2020-09-07T20:56:19.096300Z

Thank you for working on this @borkdude 😀

borkdude 2020-09-07T21:24:34.096500Z

:)

kenny 2020-09-07T21:25:09.097300Z

OMG

kenny 2020-09-07T21:26:54.097500Z

So freaking cool. An optional toggle for something like https://github.com/bhauman/spell-spec would epic (I could see some people not liking it).

kenny 2020-09-07T21:27:52.097900Z

I wonder how many places in our code base we have a :req key and aren't actually passing it but it happens to magically work in prod 😅

borkdude 2020-09-07T21:28:19.098100Z

Note that clj-kondo can only reliably detect this right now in places where literal maps are passed

borkdude 2020-09-07T21:28:36.098300Z

there are some attempts around assoc et al, but not fully worked out

borkdude 2020-09-07T21:31:29.098500Z

but I guess something is better than nothing :)

kenny 2020-09-07T21:31:43.098700Z

Ah, right - makes sense. And totally!

kenny 2020-09-07T21:32:38.098900Z

Wonder how far you could go with it... e.g.,

(defn do-stuff
  [x])

(s/fdef do-stuff
  :args (s/cat :x int?)
  :ret (s/keys :req [::a]))

(defn do-moar-stuff
  [m]
  )

(s/fdef do-moar-stuff
  :args (s/cat :m (s/keys :req [::a ::b]))
  :ret int?)

(-> 1 
    (do-stuff)
    (do-moar-stuff))
Technically seems like you could infer that do-moar-stuff will (probably) not get passed the right stuff, assuming the specs are correct.

borkdude 2020-09-07T21:35:37.099100Z

do-stuff can still required a map which key ::b, although it's not required, so I don't see anything wrong here

borkdude 2020-09-07T21:35:54.099300Z

what we could however do is, when do-stuff has ret int? and do-moar-stuff expects a map, give an error

borkdude 2020-09-07T21:36:34.099500Z

clj-kondo already has support for this, it just needs to be mapped from spec to the right format.

kenny 2020-09-07T21:36:49.099700Z

The specs for do-stuff and do-moar stuff don't align and they should. By happenstance, do-stuff could always return ::b but that's just luck.

kenny 2020-09-07T21:37:34.099900Z

A future refactoring to do-stuff could result in ::b getting removed which will cause downstream do-moar-stuff to break.

borkdude 2020-09-07T21:40:55.100100Z

the clj-kondo "type system" will only complain if it's sure something is wrong, so in this case it would not complain I think

kenny 2020-09-07T21:41:17.100300Z

I think that particular scenario would fall under the warning category.

borkdude 2020-09-07T21:41:28.100500Z

type-wise, but maybe it could have a spec linter that gave a warning about this

borkdude 2020-09-07T21:42:06.100700Z

not sure if I want to go very deep into s/keys, since spec2 will have different ways of doing

borkdude 2020-09-07T21:42:28.100900Z

but basic type warnings as you type are already a free win

✔️ 1