mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 14:00:37 +00:00
🚧 WIP Step 12.1, Improve case validation
AI-assisted-by: muse-spark, glm-5.3
This commit is contained in:
parent
9e5620600f
commit
3b8b417045
@ -63,10 +63,14 @@
|
||||
[:dpr {:optional true} ::sm/positive-safe-number]])
|
||||
|
||||
(def schema:view
|
||||
"Camera placement plus optional viewport override. All numbers are finite:
|
||||
unbounded `number?` accepts Infinity, which JSON cannot carry and the
|
||||
renderer cannot use. Bounds come from `::sm/safe-number`, whose min/max
|
||||
also rejects NaN and infinities."
|
||||
[:map {:closed true}
|
||||
[:scale [:and number? pos?]]
|
||||
[:x number?]
|
||||
[:y number?]
|
||||
[:scale ::sm/positive-safe-number]
|
||||
[:x ::sm/safe-number]
|
||||
[:y ::sm/safe-number]
|
||||
[:viewport {:optional true} schema:viewport]])
|
||||
|
||||
(defn resolve-viewport
|
||||
@ -360,19 +364,41 @@
|
||||
;; Projection
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn- finite-number?
|
||||
"True for numbers JSON preserves: rejects NaN and infinities, which
|
||||
`number?` accepts but `JSON.stringify` turns into null."
|
||||
[value]
|
||||
(and (number? value)
|
||||
(js/isFinite value)))
|
||||
|
||||
(defn serializable?
|
||||
"True when `value` is plain data the runner can hand to the browser and
|
||||
store in results: nil, booleans, numbers, strings, keywords, and maps and
|
||||
vectors thereof. Records fail: a record reaches the runner as a host
|
||||
object, not plain data. Functions, atoms and host objects fail."
|
||||
store in results.
|
||||
|
||||
True for nil, booleans, finite numbers, strings, keywords, and vectors, and
|
||||
maps with strings or keyword keys.
|
||||
|
||||
NaN, infinities and non-string map keys fail: JSON does not carry them
|
||||
losslessly.
|
||||
|
||||
Records fail: a record reaches the runner as a host object, not plain data.
|
||||
|
||||
Functions, atoms and host objects fail.
|
||||
|
||||
Keywords are encoded with `encode-id`: the planned `app.common.json` converter
|
||||
renders keyword values by unqualified name, so `:rects/load` would arrive as
|
||||
`\"load\"`."
|
||||
[value]
|
||||
(cond
|
||||
(or (nil? value) (boolean? value) (number? value)
|
||||
(or (nil? value) (boolean? value) (finite-number? value)
|
||||
(string? value) (keyword? value))
|
||||
true
|
||||
|
||||
(and (map? value) (not (record? value)))
|
||||
(every? (fn [[k v]] (and (serializable? k) (serializable? v))) value)
|
||||
(every? (fn [[k v]]
|
||||
(and (or (string? k) (keyword? k))
|
||||
(serializable? v)))
|
||||
value)
|
||||
|
||||
(vector? value)
|
||||
(every? serializable? value)
|
||||
@ -380,6 +406,22 @@
|
||||
:else
|
||||
false))
|
||||
|
||||
(defn encode-id
|
||||
"Lossless JSON-wire encoding of a keyword identity: `:rects/load` becomes
|
||||
`\"rects/load\"`, `:fresh` becomes `\"fresh\"`. `decode-id` inverts it.
|
||||
The runner (ticket 11) applies this pair at the JSON boundary; nothing
|
||||
else may turn identities into bare `name` strings."
|
||||
[id]
|
||||
(when-not (keyword? id)
|
||||
(throw (ex-info (str "wire identities are keywords, got: " (pr-str id))
|
||||
{:type ::invalid-case :id id})))
|
||||
(subs (str id) 1))
|
||||
|
||||
(defn decode-id
|
||||
"Inverts `encode-id`: `\"rects/load\"` becomes `:rects/load`."
|
||||
[s]
|
||||
(keyword s))
|
||||
|
||||
(defn project-case
|
||||
"Plain-data projection of a registered case: internal keys (`:ns`, `:run!`,
|
||||
`:body-source`) stripped, collection defaults applied."
|
||||
@ -392,8 +434,9 @@
|
||||
(update :preparation #(or % {:version 1}))))
|
||||
|
||||
(defn check-collected-case!
|
||||
"Validates a collected case descriptor and returns it unchanged. Rejects
|
||||
anything that is not plain data: browser-side run functions must never
|
||||
"Validates a collected case descriptor and returns it unchanged.
|
||||
|
||||
Rejects anything that is not plain data: browser-side run functions must never
|
||||
reach the runner."
|
||||
[projected]
|
||||
(when-not (sm/validate schema:collected-case projected)
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
where `rtx` is the injected runtime and each operation contributes its
|
||||
plain-data identity to the collected case."
|
||||
(:require
|
||||
[app.common.schema :as sm]
|
||||
[benches.render-wasm.scenes.builder :as sb :include-macros true]
|
||||
[benches.render-wasm.scenes.core :as core :include-macros true]))
|
||||
|
||||
@ -37,12 +38,19 @@
|
||||
:max-size 100})
|
||||
|
||||
(def ^:private schema:params
|
||||
[:map {:closed true}
|
||||
[:count [:int {:min 1 :max 100000}]]
|
||||
[:width pos?]
|
||||
[:height pos?]
|
||||
[:min-size pos?]
|
||||
[:max-size pos?]])
|
||||
"Workload parameters. Sizes are finite (`pos?` accepts Infinity, which JSON
|
||||
cannot carry and the generator cannot honor); `:min-size` above `:max-size`
|
||||
is rejected so parameter sweeps cannot silently measure a reversed range."
|
||||
[:and
|
||||
[:map {:closed true}
|
||||
[:count [:int {:min 1 :max 100000}]]
|
||||
[:width ::sm/positive-safe-number]
|
||||
[:height ::sm/positive-safe-number]
|
||||
[:min-size ::sm/positive-safe-number]
|
||||
[:max-size ::sm/positive-safe-number]]
|
||||
[:fn {:error/message "min-size exceeds max-size"}
|
||||
(fn [{:keys [min-size max-size]}]
|
||||
(<= min-size max-size))]])
|
||||
|
||||
(defn- rect-defaults
|
||||
"Attribute generators for one rectangle of the workload."
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user