|
184 | 184 | (assoc schema :title (impl/qualified-name title)) |
185 | 185 | schema))) |
186 | 186 |
|
| 187 | +(def key-group-mapping |
| 188 | + {'or :anyOf ;; there is no 'xor' key-group, so 'anyOf' is more appropriate than 'oneOf' |
| 189 | + 'and :allOf}) |
| 190 | + |
| 191 | +(defn- parse-required1 |
| 192 | + "Helper for generating correct schemas for :req/:req-un keys, |
| 193 | + taking into account potential or/and key-goups." |
| 194 | + [name-fn x] |
| 195 | + (if (list? x) ;; found key-group |
| 196 | + (let [k (or (key-group-mapping (first x)) |
| 197 | + (throw |
| 198 | + (ex-info "unsupported key-group expression" {:expression (first x)}))) |
| 199 | + v (mapv (partial parse-required1 name-fn) (next x))] |
| 200 | + {k (if (and (= k :allOf) |
| 201 | + (every? :required v)) |
| 202 | + [{:required (into [] (mapcat :required) v)}] |
| 203 | + v)}) |
| 204 | + {:required [(name-fn x)]})) |
| 205 | + |
| 206 | +(def parse-req* (partial parse-required1 impl/qualified-name)) |
| 207 | +(def parse-req-un* (partial parse-required1 name)) |
| 208 | + |
| 209 | +(comment |
| 210 | + |
| 211 | + (parse-req-un* '(or :foo (and :bar :baz))) |
| 212 | + ;; => |
| 213 | + {:anyOf [{:required ["foo"]} |
| 214 | + {:allOf [{:required ["bar"]} |
| 215 | + {:required ["baz"]}]}]} |
| 216 | + ) |
| 217 | + |
187 | 218 | (defmethod accept-spec 'clojure.spec.alpha/keys [_ spec children options] |
188 | | - (let [{:keys [req req-un opt opt-un]} (impl/parse-keys (impl/extract-form spec)) |
| 219 | + (let [form (impl/extract-form spec) |
| 220 | + {:keys [req req-un opt opt-un]} (impl/parse-keys form) |
189 | 221 | names-un (map name (concat req-un opt-un)) |
190 | 222 | names (map impl/qualified-name (concat req opt)) |
191 | | - required (map impl/qualified-name req) |
192 | | - required-un (map name req-un) |
| 223 | + m (some->> form (rest) (apply hash-map)) |
| 224 | + required (map parse-req* (:req m)) |
| 225 | + required-un (map parse-req-un* (:req-un m)) |
193 | 226 | all-required (not-empty (concat required required-un))] |
194 | 227 | (maybe-with-title |
195 | 228 | (merge |
196 | 229 | {:type "object" |
197 | 230 | :properties (zipmap (concat names names-un) children)} |
198 | 231 | (when all-required |
199 | | - {:required (vec all-required)})) |
| 232 | + (if (every? :required all-required) |
| 233 | + ;; avoid changing the simple case & break existing tests |
| 234 | + {:required (into [] (mapcat :required) all-required)} |
| 235 | + {:allOf (vec all-required)}))) |
200 | 236 | spec |
201 | 237 | options))) |
202 | 238 |
|
|
0 commit comments