From d33a5e6df1b3f88d454da8626462145b72de8ebb Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 17:34:47 +0200 Subject: [PATCH 1/7] :sparkles: Backport from develop partial improvements to sm/register! helper --- common/src/app/common/schema.cljc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 28a4ab0f2d..241f484a0c 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -317,11 +317,14 @@ ([params] (cond (map? params) - (let [type (get params :type)] + (let [mdata (meta params) + type (or (get mdata ::id) + (get mdata ::type) + (get params :type))] (assert (qualified-keyword? type) "expected qualified keyword for `type`") (let [s (m/-simple-schema params)] (swap! sr/registry assoc type s) - nil)) + s)) (vector? params) (let [mdata (meta params) @@ -329,11 +332,12 @@ (get mdata ::type))] (assert (qualified-keyword? type) "expected qualified keyword to be on metadata") (swap! sr/registry assoc type params) - nil) + params) (m/into-schema? params) (let [type (m/-type params)] - (swap! sr/registry assoc type params)) + (swap! sr/registry assoc type params) + params) :else (throw (ex-info "Invalid Arguments" {})))) From 3224ba26f193c82548f4c9f3b9bfed6509c0b621 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 17:25:23 +0200 Subject: [PATCH 2/7] :recycle: Replace :any schema with own ::sm/any That a more specific, json friendly generator --- backend/src/app/rpc/commands/audit.clj | 4 +- backend/src/app/rpc/commands/files.clj | 2 +- backend/src/app/rpc/commands/fonts.clj | 4 +- common/src/app/common/files/changes.cljc | 18 ++++---- .../src/app/common/files/changes_builder.cljc | 21 +++++----- common/src/app/common/schema.cljc | 2 + common/src/app/common/schema/generators.cljc | 42 +++++++++++++------ common/src/app/common/types/color.cljc | 2 +- common/src/app/common/types/tokens_lib.cljc | 5 ++- 9 files changed, 61 insertions(+), 39 deletions(-) diff --git a/backend/src/app/rpc/commands/audit.clj b/backend/src/app/rpc/commands/audit.clj index f43195dd72..a9bed1db44 100644 --- a/backend/src/app/rpc/commands/audit.clj +++ b/backend/src/app/rpc/commands/audit.clj @@ -92,9 +92,9 @@ [:string {:max 250}] [::sm/one-of {:format "string"} valid-event-types]]] [:props - [:map-of :keyword :any]] + [:map-of :keyword ::sm/any]] [:context {:optional true} - [:map-of :keyword :any]]]) + [:map-of :keyword ::sm/any]]]) (def schema:push-audit-events [:map {:title "push-audit-events"} diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index bdb2fcbc59..aff510d4cf 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -189,7 +189,7 @@ [:is-shared ::sm/boolean] [:project-id ::sm/uuid] [:created-at ::dt/instant] - [:data {:optional true} :any]]) + [:data {:optional true} ::sm/any]]) (def schema:permissions-mixin [:map {:title "PermissionsMixin"} diff --git a/backend/src/app/rpc/commands/fonts.clj b/backend/src/app/rpc/commands/fonts.clj index 43b90305e1..4c4e243669 100644 --- a/backend/src/app/rpc/commands/fonts.clj +++ b/backend/src/app/rpc/commands/fonts.clj @@ -80,9 +80,9 @@ (def ^:private schema:create-font-variant [:map {:title "create-font-variant"} [:team-id ::sm/uuid] - [:data [:map-of :string :any]] + [:data [:map-of ::sm/text ::sm/any]] [:font-id ::sm/uuid] - [:font-family :string] + [:font-family ::sm/text] [:font-weight [::sm/one-of {:format "number"} valid-weight]] [:font-style [::sm/one-of {:format "string"} valid-style]]]) diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index 023491a9ca..d3ee9f2180 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -47,14 +47,14 @@ [:type [:= :assign]] ;; NOTE: the full decoding is happening on the handler because it ;; needs a proper context of the current shape and its type - [:value [:map-of :keyword :any]] + [:value [:map-of :keyword ::sm/any]] [:ignore-touched {:optional true} :boolean] [:ignore-geometry {:optional true} :boolean]]] [:set [:map {:title "SetOperation"} [:type [:= :set]] [:attr :keyword] - [:val :any] + [:val ::sm/any] [:ignore-touched {:optional true} :boolean] [:ignore-geometry {:optional true} :boolean]]] [:set-touched @@ -238,9 +238,9 @@ [:component-id {:optional true} ::sm/uuid] [:ignore-touched {:optional true} :boolean] [:parent-id ::sm/uuid] - [:shapes :any] + [:shapes ::sm/any] [:index {:optional true} [:maybe :int]] - [:after-shape {:optional true} :any] + [:after-shape {:optional true} ::sm/any] [:component-swap {:optional true} :boolean]]] [:reorder-children @@ -250,14 +250,14 @@ [:component-id {:optional true} ::sm/uuid] [:ignore-touched {:optional true} :boolean] [:parent-id ::sm/uuid] - [:shapes :any]]] + [:shapes ::sm/any]]] [:add-page [:map {:title "AddPageChange"} [:type [:= :add-page]] [:id {:optional true} ::sm/uuid] [:name {:optional true} :string] - [:page {:optional true} :any]]] + [:page {:optional true} ::sm/any]]] [:mod-page [:map {:title "ModPageChange"} @@ -327,14 +327,14 @@ [:type [:= :add-component]] [:id ::sm/uuid] [:name :string] - [:shapes {:optional true} [:vector {:gen/max 3} :any]] + [:shapes {:optional true} [:vector {:gen/max 3} ::sm/any]] [:path {:optional true} :string]]] [:mod-component [:map {:title "ModCompoenentChange"} [:type [:= :mod-component]] [:id ::sm/uuid] - [:shapes {:optional true} [:vector {:gen/max 3} :any]] + [:shapes {:optional true} [:vector {:gen/max 3} ::sm/any]] [:name {:optional true} :string] [:variant-id {:optional true} ::sm/uuid] [:variant-properties {:optional true} [:vector ::ctv/variant-property]]]] @@ -411,7 +411,7 @@ [:set-tokens-lib [:map {:title "SetTokensLib"} [:type [:= :set-tokens-lib]] - [:tokens-lib :any]]] + [:tokens-lib ::sm/any]]] [:set-token-set [:map {:title "SetTokenSetChange"} diff --git a/common/src/app/common/files/changes_builder.cljc b/common/src/app/common/files/changes_builder.cljc index 692bde840c..8429503f63 100644 --- a/common/src/app/common/files/changes_builder.cljc +++ b/common/src/app/common/files/changes_builder.cljc @@ -25,18 +25,19 @@ ;; Auxiliary functions to help create a set of changes (undo + redo) -(sm/register! - ^{::sm/type ::changes} - [:map {:title "changes"} - [:redo-changes vector?] - [:undo-changes seq?] - [:origin {:optional true} any?] - [:save-undo? {:optional true} boolean?] - [:stack-undo? {:optional true} boolean?] - [:undo-group {:optional true} any?]]) +(def schema:changes + (sm/register! + ^{::sm/type ::changes} + [:map {:title "changes"} + [:redo-changes vector?] + [:undo-changes seq?] + [:origin {:optional true} ::sm/any] + [:save-undo? {:optional true} boolean?] + [:stack-undo? {:optional true} boolean?] + [:undo-group {:optional true} ::sm/any]])) (def check-changes! - (sm/check-fn ::changes)) + (sm/check-fn schema:changes)) (defn empty-changes ([origin page-id] diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 241f484a0c..27a9ca2a21 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -1045,6 +1045,8 @@ {:title "agent" :description "instance of clojure agent"}})) +(register! ::any (mu/update-properties :any assoc :gen/gen sg/any)) + ;; ---- PREDICATES (def valid-safe-number? diff --git a/common/src/app/common/schema/generators.cljc b/common/src/app/common/schema/generators.cljc index 57bc3703f6..2f90ab2260 100644 --- a/common/src/app/common/schema/generators.cljc +++ b/common/src/app/common/schema/generators.cljc @@ -5,7 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.common.schema.generators - (:refer-clojure :exclude [set subseq uuid filter map let boolean]) + (:refer-clojure :exclude [set subseq uuid filter map let boolean vector keyword int double]) #?(:cljs (:require-macros [app.common.schema.generators])) (:require [app.common.schema.registry :as sr] @@ -38,10 +38,6 @@ ([s opts] (mg/generator s (assoc opts :registry sr/default-registry)))) -(defn filter - [pred gen] - (tg/such-that pred gen 100)) - (defn small-double [& {:keys [min max] :or {min -100 max 100}}] (tg/double* {:min min, :max max, :infinite? false, :NaN? false})) @@ -61,7 +57,7 @@ (defn word-keyword [] (->> (word-string) - (tg/fmap keyword))) + (tg/fmap c/keyword))) (defn email [] @@ -100,12 +96,11 @@ (c/map second)) (c/map list bools elements))))))) -(def any tg/any) -(def boolean tg/boolean) - -(defn set - [g] - (tg/set g)) +(defn map-of + ([kg vg] + (tg/map kg vg {:min-elements 1 :max-elements 3})) + ([kg vg opts] + (tg/map kg vg opts))) (defn elements [s] @@ -119,6 +114,10 @@ [f g] (tg/fmap f g)) +(defn filter + [pred gen] + (tg/such-that pred gen 100)) + (defn mcat [f g] (tg/bind g f)) @@ -126,3 +125,22 @@ (defn tuple [& opts] (apply tg/tuple opts)) + +(defn vector + [& opts] + (apply tg/vector opts)) + +(defn set + [g] + (tg/set g)) + +;; Static Generators + +(def boolean tg/boolean) +(def text (word-string)) +(def double (small-double)) +(def int (small-int)) +(def keyword (word-keyword)) + +(def any + (tg/one-of [text boolean double int keyword])) diff --git a/common/src/app/common/types/color.cljc b/common/src/app/common/types/color.cljc index f93f756174..29ea0b08c1 100644 --- a/common/src/app/common/types/color.cljc +++ b/common/src/app/common/types/color.cljc @@ -35,7 +35,7 @@ (.. r (toString 16) (padStart 2 "0")) (.. g (toString 16) (padStart 2 "0")) (.. b (toString 16) (padStart 2 "0")))))) - sg/any)) + sg/int)) (defn rgb-color-string? [o] diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index ffed9c3949..5e2d17ddf8 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -118,7 +118,7 @@ [:map {:title "Token"} [:name cto/token-name-ref] [:type [::sm/one-of cto/token-types]] - [:value :any] + [:value ::sm/any] [:description {:optional true} :string] [:modified-at {:optional true} ::sm/inst]]) @@ -389,7 +389,8 @@ [:description {:optional true} :string] [:modified-at {:optional true} ::sm/inst] [:tokens {:optional true - :gen/gen (->> (sg/generator [:map-of ::sm/text schema:token]) + :gen/gen (->> (sg/map-of (sg/generator ::sm/text) + (sg/generator schema:token)) (sg/fmap #(into (d/ordered-map) %)))} [:and [:map-of {:gen/max 5 From 9378a5786f3f1c2399c784b00183459af762a98b Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 17:26:31 +0200 Subject: [PATCH 3/7] :sparkles: Replace json library used for generate openapi json --- backend/src/app/rpc/doc.clj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/app/rpc/doc.clj b/backend/src/app/rpc/doc.clj index efd23ed44a..46715d4803 100644 --- a/backend/src/app/rpc/doc.clj +++ b/backend/src/app/rpc/doc.clj @@ -9,6 +9,7 @@ (:require [app.common.data :as d] [app.common.exceptions :as ex] + [app.common.json :as json] [app.common.pprint :as pp] [app.common.schema :as sm] [app.common.schema.desc-js-like :as smdj] @@ -19,7 +20,6 @@ [app.http.sse :as-alias sse] [app.loggers.webhooks :as-alias webhooks] [app.rpc :as-alias rpc] - [app.util.json :as json] [app.util.services :as sv] [app.util.template :as tmpl] [clojure.java.io :as io] @@ -179,7 +179,6 @@ {::yres/status 200 ::yres/headers {"content-type" "application/json; charset=utf-8"} ::yres/body (json/encode context)}) - (fn [_] {::yres/status 404}))) From c87fa4f723c10f440c2db588e2f015c4b8be0652 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 17:29:07 +0200 Subject: [PATCH 4/7] :sparkles: Make the rpc doc generation lazy --- backend/src/app/rpc/doc.clj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/app/rpc/doc.clj b/backend/src/app/rpc/doc.clj index 46715d4803..cba16e0ab5 100644 --- a/backend/src/app/rpc/doc.clj +++ b/backend/src/app/rpc/doc.clj @@ -86,7 +86,7 @@ (fn [request] (let [params (:query-params request) pstyle (:type params "js") - context (assoc context :param-style pstyle)] + context (assoc @context :param-style pstyle)] {::yres/status 200 ::yres/body (-> (io/resource "app/templates/api-doc.tmpl") @@ -178,7 +178,7 @@ (fn [_] {::yres/status 200 ::yres/headers {"content-type" "application/json; charset=utf-8"} - ::yres/body (json/encode context)}) + ::yres/body (json/encode @context)}) (fn [_] {::yres/status 404}))) @@ -208,7 +208,7 @@ (defmethod ig/init-key ::routes [_ {:keys [::rpc/methods] :as cfg}] - [(let [context (prepare-doc-context methods)] + [(let [context (delay (prepare-doc-context methods))] [["/_doc" {:handler (doc-handler context) :allowed-methods #{:get}}] @@ -216,7 +216,7 @@ {:handler (doc-handler context) :allowed-methods #{:get}}]]) - (let [context (prepare-openapi-context methods)] + (let [context (delay (prepare-openapi-context methods))] [["/openapi" {:handler (openapi-handler) :allowed-methods #{:get}}] From 004a9f17d34c4f404a6074e3be585e22004aa206 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 17:29:34 +0200 Subject: [PATCH 5/7] :sparkles: Add minor js-like type schema formatting improvements --- .../src/app/common/schema/desc_js_like.cljc | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/common/src/app/common/schema/desc_js_like.cljc b/common/src/app/common/schema/desc_js_like.cljc index e60c329e89..f61279378c 100644 --- a/common/src/app/common/schema/desc_js_like.cljc +++ b/common/src/app/common/schema/desc_js_like.cljc @@ -7,6 +7,7 @@ (ns app.common.schema.desc-js-like (:require [app.common.data :as d] + [app.common.schema :as-alias sm] [cuerdas.core :as str] [malli.core :as m] [malli.util :as mu])) @@ -90,7 +91,7 @@ (defmethod visit :int [_ schema _ _] (str "integer" (-titled schema) (-min-max-suffix-number schema))) (defmethod visit :double [_ schema _ _] (str "double" (-titled schema) (-min-max-suffix-number schema))) (defmethod visit :select-keys [_ schema _ options] (describe* (m/deref schema) options)) -(defmethod visit :and [_ s children _] (str (str/join ", and " children) (-titled s))) +(defmethod visit :and [_ s children _] (str (str/join " && " children) (-titled s))) (defmethod visit :enum [_ s children _options] (str "enum" (-titled s) " of " (str/join ", " children))) (defmethod visit :maybe [_ _ children _] (str (first children) " nullable")) (defmethod visit :tuple [_ _ children _] (str "(" (str/join ", " children) ")")) @@ -106,7 +107,8 @@ (defmethod visit :qualified-symbol [_ _ _ _] "qualified symbol") (defmethod visit :uuid [_ _ _ _] "uuid") (defmethod visit :boolean [_ _ _ _] "boolean") -(defmethod visit :keyword [_ _ _ _] "keyword") +(defmethod visit :keyword [_ _ _ _] "string") +(defmethod visit :fn [_ _ _ _] "FN") (defmethod visit :vector [_ _ children _] (str "[" (last children) "]")) @@ -123,10 +125,12 @@ (defmethod visit :repeat [_ schema children _] (str "repeat " (-diamond (first children)) (-repeat-suffix schema))) - (defmethod visit :set [_ schema children _] (str "set[" (first children) "]" (minmax-suffix schema))) +(defmethod visit ::sm/set [_ schema children _] + (str "set[" (first children) "]" (minmax-suffix schema))) + (defmethod visit ::m/val [_ schema children _] (let [suffix (minmax-suffix schema)] (cond-> (first children) @@ -152,7 +156,6 @@ (or (:title props) "*"))) - (defmethod visit :map [_ schema children {:keys [::level ::max-level] :as options}] (let [props (m/properties schema) @@ -172,13 +175,11 @@ ": " s))) (str/join ",\n")) - header (cond-> (if (zero? level) - (str "type " title) - (str title)) + header (cond-> (str "type " title) closed? (str "!") (some? title) (str " "))] - (str header "{\n" entries "\n" (pad "}" level)))))) + (str (pad header level) "{\n" entries "\n" (pad "}\n" level)))))) (defmethod visit :multi [_ s children {:keys [::level ::max-level] :as options}] @@ -205,18 +206,18 @@ (defmethod visit :merge [_ schema children _] - (let [entries (str/join " , " children) + (let [entries (str/join ",\n" children) props (m/properties schema) title (or (some-> (:title props) str/camel str/capital) "")] - (str "merge object " title " { " entries " }"))) + (str "merge type " title " { \n" entries "\n}\n"))) -(defmethod visit :app.common.schema/one-of - [_ _ children _] +(defmethod visit ::sm/one-of + [_ _ children _] (let [elems (last children)] - (str "OneOf[" (->> elems - (map d/name) - (str/join ",")) "]"))) + (str "string oneOf (" (->> elems + (map d/name) + (str/join "|")) ")"))) (defmethod visit :schema [_ schema children options] (visit ::m/schema schema children options)) From 1334d733cd7588c7228d5a7c1af25ad67880931c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 17:30:15 +0200 Subject: [PATCH 6/7] :bug: Fix openapi json generation for :re schemas --- common/src/app/common/schema/openapi.cljc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/app/common/schema/openapi.cljc b/common/src/app/common/schema/openapi.cljc index f571408269..967e267043 100644 --- a/common/src/app/common/schema/openapi.cljc +++ b/common/src/app/common/schema/openapi.cljc @@ -97,7 +97,8 @@ (defmethod visit :enum [_ _ children options] (merge (some-> (m/-infer children) (transform* options)) {:enum children})) (defmethod visit :maybe [_ _ children _] {:oneOf (conj children {:type "null"})}) (defmethod visit :tuple [_ _ children _] {:type "array", :items children, :additionalItems false}) -(defmethod visit :re [_ schema _ options] {:type "string", :pattern (first (m/children schema options))}) +(defmethod visit :re [_ schema _ options] + {:type "string", :pattern (str (first (m/children schema options)))}) (defmethod visit :nil [_ _ _ _] {:type "null"}) (defmethod visit :string [_ schema _ _] From 2d3ad5a88fcd687a52716adacc5f5d3e17da664a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 14 May 2025 17:40:43 +0200 Subject: [PATCH 7/7] :paperclip: Update changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 51f8639a0e..4771a8b57c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -52,6 +52,7 @@ - Fix exception on paste invalid html [Taiga #11047](https://tree.taiga.io/project/penpot/issue/11047) - Fix share button being displayed with no permissions [Taiga #11086](https://tree.taiga.io/project/penpot/issue/11086) - Fix inline styles in code tab [Taiga Issue #7583](https://tree.taiga.io/project/penpot/issue/7583) +- Fix exception on returning openapi.json ## 2.6.2