|
1 | 1 | (ns mycelium.cell |
2 | 2 | "Cell registry for Mycelium. Cells are registered via `defmethod cell-spec`." |
3 | | - (:require [mycelium.validation :as v])) |
| 3 | + (:require [mycelium.schema :as schema] |
| 4 | + [mycelium.validation :as v])) |
4 | 5 |
|
5 | 6 | (defmulti cell-spec |
6 | 7 | "Multimethod-backed cell registry. Dispatches on cell-id keyword, |
|
35 | 36 | (throw (ex-info (str "Cell " id " not found in registry") |
36 | 37 | {:id id})))) |
37 | 38 |
|
| 39 | +(defn- output-dispatched? |
| 40 | + "Heuristic for defcell/set-cell-schema! (no edge context available): |
| 41 | + a map output schema is per-transition if all values are vectors (Malli schema |
| 42 | + forms like [:map ...], [:or ...], etc.). If any value is a keyword or map, |
| 43 | + it's treated as lite syntax. For manifests, edge context is used instead. |
| 44 | + Trade-off: per-transition maps with bare keyword schemas (e.g. {:success :any}) |
| 45 | + would be misclassified as lite — use vector form [:any] in that rare case." |
| 46 | + [output] |
| 47 | + (and (map? output) (seq output) (every? vector? (vals output)))) |
| 48 | + |
38 | 49 | (defn set-cell-schema! |
39 | 50 | "Sets or overwrites the schema for an already-registered cell. |
40 | | - Validates that the schema is well-formed Malli before updating. |
| 51 | + Normalizes lite syntax, validates Malli, then updates. |
41 | 52 | Throws if the cell is not found or the schema is invalid." |
42 | 53 | [cell-id schema] |
43 | 54 | (when-not (cell-spec cell-id) |
44 | 55 | (throw (ex-info (str "Cell " cell-id " not found in registry") |
45 | 56 | {:id cell-id}))) |
46 | | - (when (:input schema) |
47 | | - (v/validate-malli-schema! (:input schema) (str cell-id " :input"))) |
48 | | - (when (:output schema) |
49 | | - (v/validate-output-schema! (:output schema) (str cell-id " :output"))) |
50 | | - (swap! cell-overrides update cell-id merge {:schema schema}) |
51 | | - schema) |
| 57 | + (let [dispatched? (output-dispatched? (:output schema)) |
| 58 | + schema (schema/normalize-cell-schema schema dispatched?)] |
| 59 | + (when (:input schema) |
| 60 | + (v/validate-malli-schema! (:input schema) (str cell-id " :input"))) |
| 61 | + (when (:output schema) |
| 62 | + (v/validate-output-schema! (:output schema) (str cell-id " :output"))) |
| 63 | + (swap! cell-overrides update cell-id merge {:schema schema}) |
| 64 | + schema)) |
52 | 65 |
|
53 | 66 | (defn set-cell-meta! |
54 | 67 | "Sets metadata overrides (schema, requires) on a registered cell. |
55 | 68 | The manifest calls this to inject metadata into cells that were registered |
56 | | - without schemas/requires. Validates schema is well-formed. |
57 | | - Throws if the cell is not found." |
| 69 | + without schemas/requires. Expects schemas to be pre-normalized. |
| 70 | + Validates schema is well-formed. Throws if the cell is not found." |
58 | 71 | [cell-id {:keys [schema requires] :as meta-map}] |
59 | 72 | (when-not (cell-spec cell-id) |
60 | 73 | (throw (ex-info (str "Cell " cell-id " not found in registry") |
|
110 | 123 | ([cell-id opts handler-fn] |
111 | 124 | (let [schema-keys #{:input :output} |
112 | 125 | opt-keys #{:doc :requires :async?} |
113 | | - schema (when opts |
| 126 | + raw-schema (when opts |
114 | 127 | (let [s (select-keys opts schema-keys)] |
115 | 128 | (when (seq s) s))) |
| 129 | + dispatched? (and raw-schema (output-dispatched? (:output raw-schema))) |
| 130 | + schema (when raw-schema |
| 131 | + (schema/normalize-cell-schema raw-schema dispatched?)) |
116 | 132 | extra (when opts (select-keys opts opt-keys)) |
117 | 133 | spec (cond-> {:id cell-id :handler handler-fn} |
118 | 134 | schema (assoc :schema schema) |
|
0 commit comments