metosin / spec-tools

Clojure(Script) tools for clojure.spec
Eclipse Public License 2.0
593 stars 94 forks source link

OpenAPI & Swagger generation fail for `st/spec` inside `s/or` #291

Open opqdonut opened 1 month ago

opqdonut commented 1 month ago

Repro:

(require '[clojure.spec.alpha :as s])
(require '[spec-tools.core :as st])
(require '[spec-tools.swagger.core :as swagger])
(require '[spec-tools.openapi.core :as openapi])

(s/def ::a int?)
(s/def ::b string?)
(s/def ::A (s/keys :req-un [::a]))
(s/def ::B (s/keys :req-un [::b]))

(s/def ::body (s/or :a ::A :b ::B))

(swagger/swagger-spec {::swagger/parameters {:body ::body}}) ;works
(openapi/transform ::body) ;works

(s/def ::body-wrapped (s/or :a (st/spec ::A) :b (st/spec ::B)))

(swagger/swagger-spec {::swagger/parameters {:body ::body-wrapped}}) ;fails
(openapi/transform ::body-wrapped) ;fails

The exceptions are:

(swagger)

#error {
 :cause "Don't know how to create ISeq from: clojure.lang.Keyword"
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message "Syntax error macroexpanding at (/home/joel/work/metosin/spec-tools/or-openapi-repro.clj:16:1)."
   :data #:clojure.error{:phase :execution, :line 16, :column 1, :source "/home/joel/work/metosin/spec-tools/or-openapi-repro.clj"}
   :at [clojure.lang.Compiler load "Compiler.java" 7665]}
  {:type java.lang.IllegalArgumentException
   :message "Don't know how to create ISeq from: clojure.lang.Keyword"
   :at [clojure.lang.RT seqFrom "RT.java" 557]}]
 :trace
 [[clojure.lang.RT seqFrom "RT.java" 557]
  [clojure.lang.RT seq "RT.java" 537]
  [clojure.core$seq__5467 invokeStatic "core.clj" 139]
  [clojure.core.protocols$seq_reduce invokeStatic "protocols.clj" 24]
  [clojure.core.protocols$fn__8226 invokeStatic "protocols.clj" 75]
  [clojure.core.protocols$fn__8226 invoke "protocols.clj" 75]
  [clojure.core.protocols$fn__8178$G__8173__8191 invoke "protocols.clj" 13]
  [clojure.core$reduce invokeStatic "core.clj" 6887]
  [clojure.core$reduce invoke "core.clj" 6869]
  [spec_tools.impl$unlift_keys invokeStatic "impl.cljc" 166]
  [spec_tools.impl$unlift_keys invoke "impl.cljc" 165]
  [spec_tools.swagger.core$eval3633$fn__3634 invoke "core.cljc" 85]
  [clojure.lang.MultiFn invoke "MultiFn.java" 244]
  [spec_tools.visitor$eval3249$fn__3250 invoke "visitor.cljc" 149]
  [clojure.lang.MultiFn invoke "MultiFn.java" 239]
  [spec_tools.visitor$visit invokeStatic "visitor.cljc" 52]
  [spec_tools.visitor$visit invoke "visitor.cljc" 26]
  [spec_tools.visitor$eval3100$fn__3101$fn__3106 invoke "visitor.cljc" 64]
  [clojure.core$mapv$fn__8535 invoke "core.clj" 6980]
  [clojure.core.protocols$iter_reduce invokeStatic "protocols.clj" 49]
  [clojure.core.protocols$fn__8238 invokeStatic "protocols.clj" 75]
  [clojure.core.protocols$fn__8238 invoke "protocols.clj" 75]
  [clojure.core.protocols$fn__8178$G__8173__8191 invoke "protocols.clj" 13]
  [clojure.core$reduce invokeStatic "core.clj" 6887]
  [clojure.core$mapv invokeStatic "core.clj" 6971]
  [clojure.core$mapv invoke "core.clj" 6971]
  [spec_tools.visitor$eval3100$fn__3101 invoke "visitor.cljc" 64]
  [clojure.lang.MultiFn invoke "MultiFn.java" 239]
  [spec_tools.visitor$visit invokeStatic "visitor.cljc" 52]
  [spec_tools.visitor$visit invoke "visitor.cljc" 26]
  [spec_tools.swagger.core$transform invokeStatic "core.cljc" 101]
  [spec_tools.swagger.core$transform invoke "core.cljc" 92]
  [spec_tools.swagger.core$eval3652$fn__3653 invoke "core.cljc" 110]
  [clojure.lang.MultiFn invoke "MultiFn.java" 234]
  [spec_tools.swagger.core$eval3702$fn__3703$fn__3705 invoke "core.cljc" 147]
  [clojure.core$map$fn__5935 invoke "core.clj" 2772]
  [clojure.lang.LazySeq sval "LazySeq.java" 42]
  [clojure.lang.LazySeq seq "LazySeq.java" 51]
  [clojure.lang.RT seq "RT.java" 535]
  [clojure.core$seq__5467 invokeStatic "core.clj" 139]
  [clojure.core$apply invokeStatic "core.clj" 662]
  [clojure.core$mapcat invokeStatic "core.clj" 2800]
  [clojure.core$mapcat doInvoke "core.clj" 2800]
  [clojure.lang.RestFn invoke "RestFn.java" 423]
  [spec_tools.swagger.core$eval3702$fn__3703 invoke "core.cljc" 147]
  [clojure.lang.MultiFn invoke "MultiFn.java" 244]
  [spec_tools.swagger.core$expand_qualified_keywords$fn__3719$fn__3720 invoke "core.cljc" 170]
  [clojure.lang.PersistentArrayMap kvreduce "PersistentArrayMap.java" 429]
  [clojure.core$fn__8525 invokeStatic "core.clj" 6909]
  [clojure.core$fn__8525 invoke "core.clj" 6889]
  [clojure.core.protocols$fn__8257$G__8252__8266 invoke "protocols.clj" 175]
  [clojure.core$reduce_kv invokeStatic "core.clj" 6920]
  [clojure.core$reduce_kv invoke "core.clj" 6911]
  [spec_tools.swagger.core$expand_qualified_keywords$fn__3719 invoke "core.cljc" 167]
  [clojure.walk$walk invokeStatic "walk.clj" 50]
  [clojure.walk$postwalk invokeStatic "walk.clj" 53]
  [clojure.walk$postwalk invoke "walk.clj" 53]
  [spec_tools.swagger.core$expand_qualified_keywords invokeStatic "core.cljc" 164]
  [spec_tools.swagger.core$expand_qualified_keywords invoke "core.cljc" 162]
  [spec_tools.swagger.core$swagger_spec invokeStatic "core.cljc" 189]
  [spec_tools.swagger.core$swagger_spec invoke "core.cljc" 181]
  [spec_tools.swagger.core$swagger_spec invokeStatic "core.cljc" 187]
  [spec_tools.swagger.core$swagger_spec invoke "core.cljc" 181]
  ...

(openapi)

#error {
 :cause "Don't know how to create ISeq from: clojure.lang.Keyword"
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message "Syntax error macroexpanding at (/home/joel/work/metosin/spec-tools/or-openapi-repro.clj:18:1)."
   :data #:clojure.error{:phase :execution, :line 18, :column 1, :source "/home/joel/work/metosin/spec-tools/or-openapi-repro.clj"}
   :at [clojure.lang.Compiler load "Compiler.java" 7665]}
  {:type java.lang.IllegalArgumentException
   :message "Don't know how to create ISeq from: clojure.lang.Keyword"
   :at [clojure.lang.RT seqFrom "RT.java" 557]}]
 :trace
 [[clojure.lang.RT seqFrom "RT.java" 557]
  [clojure.lang.RT seq "RT.java" 537]
  [clojure.core$seq__5467 invokeStatic "core.clj" 139]
  [clojure.core.protocols$seq_reduce invokeStatic "protocols.clj" 24]
  [clojure.core.protocols$fn__8226 invokeStatic "protocols.clj" 75]
  [clojure.core.protocols$fn__8226 invoke "protocols.clj" 75]
  [clojure.core.protocols$fn__8178$G__8173__8191 invoke "protocols.clj" 13]
  [clojure.core$reduce invokeStatic "core.clj" 6887]
  [clojure.core$reduce invoke "core.clj" 6869]
  [spec_tools.impl$unlift_keys invokeStatic "impl.cljc" 166]
  [spec_tools.impl$unlift_keys invoke "impl.cljc" 165]
  [spec_tools.openapi.core$eval3766$fn__3767 invoke "core.cljc" 34]
  [clojure.lang.MultiFn invoke "MultiFn.java" 244]
  [spec_tools.visitor$eval3249$fn__3250 invoke "visitor.cljc" 149]
  [clojure.lang.MultiFn invoke "MultiFn.java" 239]
  [spec_tools.visitor$visit invokeStatic "visitor.cljc" 52]
  [spec_tools.visitor$visit invoke "visitor.cljc" 26]
  [spec_tools.visitor$eval3100$fn__3101$fn__3106 invoke "visitor.cljc" 64]
  [clojure.core$mapv$fn__8535 invoke "core.clj" 6980]
  [clojure.core.protocols$iter_reduce invokeStatic "protocols.clj" 49]
  [clojure.core.protocols$fn__8238 invokeStatic "protocols.clj" 75]
  [clojure.core.protocols$fn__8238 invoke "protocols.clj" 75]
  [clojure.core.protocols$fn__8178$G__8173__8191 invoke "protocols.clj" 13]
  [clojure.core$reduce invokeStatic "core.clj" 6887]
  [clojure.core$mapv invokeStatic "core.clj" 6971]
  [clojure.core$mapv invoke "core.clj" 6971]
  [spec_tools.visitor$eval3100$fn__3101 invoke "visitor.cljc" 64]
  [clojure.lang.MultiFn invoke "MultiFn.java" 239]
  [spec_tools.visitor$visit invokeStatic "visitor.cljc" 52]
  [spec_tools.visitor$visit invoke "visitor.cljc" 26]
  [spec_tools.openapi.core$transform invokeStatic "core.cljc" 47]
  [spec_tools.openapi.core$transform invoke "core.cljc" 42]
  [spec_tools.openapi.core$transform invokeStatic "core.cljc" 45]
  [spec_tools.openapi.core$transform invoke "core.cljc" 42]
  ...