|
204 | 204 |
|
205 | 205 | (defn -function-info [schema]
|
206 | 206 | (when (= (type schema) :=>)
|
207 |
| - (let [[input output] (-children schema) |
| 207 | + (let [[input output guard] (-children schema) |
208 | 208 | {:keys [min max]} (-regex-min-max input false)]
|
209 | 209 | (cond-> {:min min
|
210 | 210 | :arity (if (= min max) min :varargs)
|
211 | 211 | :input input
|
212 | 212 | :output output}
|
| 213 | + guard (assoc :guard guard) |
213 | 214 | max (assoc :max max)))))
|
214 | 215 |
|
215 | 216 | (defn -group-by-arity! [infos]
|
|
1750 | 1751 | ^{:type ::into-schema}
|
1751 | 1752 | (reify
|
1752 | 1753 | AST
|
1753 |
| - (-from-ast [parent {:keys [input output properties]} options] |
1754 |
| - (-into-schema parent properties [(from-ast input options) (from-ast output options)] options)) |
| 1754 | + (-from-ast [parent {:keys [input output guard properties]} options] |
| 1755 | + (-into-schema parent properties (cond-> [(from-ast input options) (from-ast output options)] |
| 1756 | + guard (conj (from-ast guard))) options)) |
1755 | 1757 | IntoSchema
|
1756 | 1758 | (-type [_] :=>)
|
1757 | 1759 | (-type-properties [_])
|
1758 | 1760 | (-into-schema [parent properties children {::keys [function-checker] :as options}]
|
1759 |
| - (-check-children! :=> properties children 2 2) |
1760 |
| - (let [[input output :as children] (-vmap #(schema % options) children) |
1761 |
| - form (delay (-simple-form parent properties children -form options)) |
| 1761 | + (-check-children! :=> properties children 2 3) |
| 1762 | + (let [[input output guard :as children] (-vmap #(schema % options) children) |
| 1763 | + form (delay (-create-form (-type parent) properties (-vmap -form children) options)) |
1762 | 1764 | cache (-create-cache options)
|
1763 | 1765 | ->checker (if function-checker #(function-checker % options) (constantly nil))]
|
1764 | 1766 | (when-not (#{:cat :catn} (type input))
|
|
1768 | 1770 | AST
|
1769 | 1771 | (-to-ast [_ _]
|
1770 | 1772 | (cond-> {:type :=>, :input (ast input), :output (ast output)}
|
1771 |
| - properties (assoc :properties properties))) |
| 1773 | + guard (assoc :guard (ast guard)), properties (assoc :properties properties))) |
1772 | 1774 | Schema
|
1773 | 1775 | (-validator [this]
|
1774 | 1776 | (if-let [checker (->checker this)]
|
|
1780 | 1782 | (if (not (fn? x))
|
1781 | 1783 | (conj acc (miu/-error path in this x))
|
1782 | 1784 | (if-let [res (checker x)]
|
1783 |
| - (conj acc (assoc (miu/-error path in this x) :check res)) |
| 1785 | + (let [{::keys [explain-input explain-output explain-guard]} res |
| 1786 | + res (dissoc res ::explain-input ::explain-output ::explain-guard) |
| 1787 | + {:keys [path in] :as error} (assoc (miu/-error path in this x) :check res) |
| 1788 | + -push (fn [acc i e] |
| 1789 | + (cond-> acc e (into (map #(assoc % :path (conj path i), :in in) (:errors e)))))] |
| 1790 | + (-> (conj acc error) (-push 0 explain-input) (-push 1 explain-output) (-push 2 explain-guard))) |
1784 | 1791 | acc)))
|
1785 | 1792 | (let [validator (-validator this)]
|
1786 | 1793 | (fn explain [x in acc]
|
|
2582 | 2589 | | key | description |
|
2583 | 2590 | | ----------|-------------|
|
2584 | 2591 | | `:schema` | function schema
|
2585 |
| - | `:scope` | optional set of scope definitions, defaults to `#{:input :output}` |
| 2592 | + | `:scope` | optional set of scope definitions, defaults to `#{:input :output :guard}` |
2586 | 2593 | | `:report` | optional side-effecting function of `key data -> any` to report problems, defaults to `m/-fail!`
|
2587 | 2594 | | `:gen` | optional function of `schema -> schema -> value` to be invoked on the args to get the return value"
|
2588 | 2595 | ([props]
|
2589 | 2596 | (-instrument props nil nil))
|
2590 | 2597 | ([props f]
|
2591 | 2598 | (-instrument props f nil))
|
2592 |
| - ([{:keys [scope report gen] :or {scope #{:input :output}, report -fail!} :as props} f options] |
| 2599 | + ([{:keys [scope report gen] :or {scope #{:input :output :guard}, report -fail!} :as props} f options] |
2593 | 2600 | (let [schema (-> props :schema (schema options))]
|
2594 | 2601 | (case (type schema)
|
2595 |
| - :=> (let [{:keys [min max input output]} (-function-info schema) |
2596 |
| - [validate-input validate-output] (-vmap validator [input output]) |
2597 |
| - [wrap-input wrap-output] (-vmap (partial contains? scope) [:input :output]) |
| 2602 | + :=> (let [{:keys [min max input output guard]} (-function-info schema) |
| 2603 | + [validate-input validate-output validate-guard] (-vmap validator [input output (or guard :any)]) |
| 2604 | + [wrap-input wrap-output wrap-guard] (-vmap #(contains? scope %) [:input :output :guard]) |
2598 | 2605 | f (or (if gen (gen schema) f) (-fail! ::missing-function {:props props}))]
|
2599 | 2606 | (fn [& args]
|
2600 | 2607 | (let [args (vec args), arity (count args)]
|
|
2604 | 2611 | (when-not (validate-input args)
|
2605 | 2612 | (report ::invalid-input {:input input, :args args, :schema schema})))
|
2606 | 2613 | (let [value (apply f args)]
|
2607 |
| - (when wrap-output |
2608 |
| - (when-not (validate-output value) |
2609 |
| - (report ::invalid-output {:output output, :value value, :args args, :schema schema}))) |
| 2614 | + (when (and wrap-output (not (validate-output value))) |
| 2615 | + (report ::invalid-output {:output output, :value value, :args args, :schema schema})) |
| 2616 | + (when (and wrap-guard (not (validate-guard [args value]))) |
| 2617 | + (report ::invalid-guard {:guard guard, :value value, :args args, :schema schema})) |
2610 | 2618 | value))))
|
2611 | 2619 | :function (let [arity->info (->> (children schema)
|
2612 | 2620 | (map (fn [s] (assoc (-function-info s) :f (-instrument (assoc props :schema s) f options))))
|
|
0 commit comments