From 2bcf5a667ee00453de35fe2ca191fcf605dba79b Mon Sep 17 00:00:00 2001 From: Damian Hryniewicz Date: Tue, 9 Jan 2024 11:51:43 +0100 Subject: [PATCH] Support transform of multi-spec to JSON Schema --- CHANGELOG.md | 4 ++++ src/spec_tools/json_schema.cljc | 3 +++ src/spec_tools/visitor.cljc | 6 ++++++ test/cljc/spec_tools/json_schema_test.cljc | 22 ++++++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f53f7e06..cb6d53d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Unreleased + +* Support tranforming schema to JSON Schema. PR [#281](https://github.com/metosin/spec-tools/pull/281) + # 0.10.6 (2023-08-28) * Deprecate `spec-tools.openapi/openapi-spec` diff --git a/src/spec_tools/json_schema.cljc b/src/spec_tools/json_schema.cljc index 00804d69..02f00683 100644 --- a/src/spec_tools/json_schema.cljc +++ b/src/spec_tools/json_schema.cljc @@ -228,6 +228,9 @@ (defmethod accept-spec 'spec-tools.core/merge [_ spec children options] (accept-merge children spec options)) +(defmethod accept-spec 'clojure.spec.alpha/multi-spec [_ _ children _] + {:anyOf children}) + (defmethod accept-spec 'clojure.spec.alpha/every [_ spec children options] (let [form (impl/extract-form spec) {:keys [type]} (parse/parse-spec form)] diff --git a/src/spec_tools/visitor.cljc b/src/spec_tools/visitor.cljc index cef5755c..a4dfc2b3 100644 --- a/src/spec_tools/visitor.cljc +++ b/src/spec_tools/visitor.cljc @@ -77,6 +77,12 @@ (defmethod visit-spec 'spec-tools.core/merge [spec accept options] (visit-merge spec accept options)) +(defmethod visit-spec 'clojure.spec.alpha/multi-spec [spec accept options] + (let [methods-specs (->> (impl/extract-form spec) + (parse/get-multi-spec-sub-specs) + (into {}))] + (accept 'clojure.spec.alpha/multi-spec spec (mapv #(visit (val %) accept options) methods-specs) options))) + (defmethod visit-spec 'clojure.spec.alpha/every [spec accept options] (let [[_ inner-spec] (impl/extract-form spec)] (accept 'clojure.spec.alpha/every spec [(visit inner-spec accept options)] options))) diff --git a/test/cljc/spec_tools/json_schema_test.cljc b/test/cljc/spec_tools/json_schema_test.cljc index 1be106d4..3b0d1bec 100644 --- a/test/cljc/spec_tools/json_schema_test.cljc +++ b/test/cljc/spec_tools/json_schema_test.cljc @@ -27,6 +27,23 @@ (s/def ::keys-no-req (s/keys :opt [::e] :opt-un [::e])) +(defmulti event-payload :action) + +(s/def :event.payload.add/action #{:add}) +(s/def :event.payload.add/payload int?) + +(defmethod event-payload :add + [_] + (s/keys :req-un [:event.payload.add/action :event.payload.add/payload])) + +(s/def :event.payload.result/action #{:result}) +(s/def :event.payload.result/payload nil?) + +(defmethod event-payload :result + [_] + (s/keys :req-un [:event.payload.result/action] + :opt-un [:event.payload.result/payload])) + (deftest simple-spec-test (testing "primitive predicates" ;; You're intented to call jsc/to-json with a registered spec, but to avoid @@ -99,6 +116,11 @@ :properties {"spec-tools.json-schema-test/integer" {:type "integer"} "spec-tools.json-schema-test/string" {:type "string"}} :required ["spec-tools.json-schema-test/integer" "spec-tools.json-schema-test/string"]})) + (is (= (jsc/transform (s/multi-spec event-payload :action)) + {:anyOf [{:type "object" :properties {"action" {:enum [:result]} "payload" {:type "null"}} :required ["action"]} + {:type "object" + :properties {"action" {:enum [:add]} "payload" {:type "integer" :format "int64"}} + :required ["action" "payload"]}]})) (is (= (jsc/transform (s/every integer?)) {:type "array" :items {:type "integer"}})) (is (= (jsc/transform (s/every-kv string? integer?)) {:type "object" :additionalProperties {:type "integer"}}))