From 2643dae0a75f664277320cd8acfcbd7767640987 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 26 Aug 2024 20:41:05 +0200 Subject: [PATCH] :bug: Fix json encoding on zip encoding decoding --- common/src/app/common/json.cljc | 111 ++++++++++++++++++---------- frontend/src/app/worker/export.cljs | 2 +- frontend/src/app/worker/import.cljs | 59 ++++++++++----- frontend/src/debug.cljs | 20 +---- 4 files changed, 120 insertions(+), 72 deletions(-) diff --git a/common/src/app/common/json.cljc b/common/src/app/common/json.cljc index ef3eecb67..7b576e513 100644 --- a/common/src/app/common/json.cljc +++ b/common/src/app/common/json.cljc @@ -5,12 +5,11 @@ ;; Copyright (c) KALEIDOS INC (ns app.common.json - (:refer-clojure :exclude [read]) + (:refer-clojure :exclude [read clj->js js->clj]) (:require #?(:clj [clojure.data.json :as j]) [cuerdas.core :as str])) - #?(:clj (defn read [reader & {:as opts}] @@ -21,34 +20,6 @@ [writer data & {:as opts}] (j/write data writer opts))) -#?(:cljs - (defn map->obj - "A simplified version of clj->js with focus on performance" - [x & {:keys [key-fn]}] - (cond - (nil? x) - nil - - (keyword? x) - (name x) - - (map? x) - (reduce-kv (fn [m k v] - (let [k (if (keyword? k) (name k) k)] - (unchecked-set m (key-fn k) (map->obj v key-fn)) - m)) - #js {} - x) - - (coll? x) - (reduce (fn [arr v] - (.push arr v) - arr) - (array) - x) - - :else x))) - (defn read-kebab-key [k] (if (and (string? k) (not (str/includes? k "/"))) @@ -61,12 +32,76 @@ (str/camel k) (str k))) -#?(:clj - (defn encode - [data & {:as opts}] - (j/write-str data opts))) +#?(:cljs + (defn ->js + [x & {:keys [key-fn] + :or {key-fn write-camel-key} :as opts}] + (let [f (fn this-fn [x] + (cond + (nil? x) + nil -#?(:clj - (defn decode - [data & {:as opts}] - (j/read-str data opts))) + (satisfies? cljs.core/IEncodeJS x) + (cljs.core/-clj->js x) + + (or (keyword? x) + (symbol? x)) + (name x) + + (number? x) + x + + (boolean? x) + x + + (map? x) + (reduce-kv (fn [m k v] + (let [k (key-fn k)] + (unchecked-set m k (this-fn v)) + m)) + #js {} + x) + + (coll? x) + (reduce (fn [arr v] + (.push arr (this-fn v)) + arr) + (array) + x) + + :else + (str x)))] + (f x)))) + + +#?(:cljs + (defn ->clj + [o & {:keys [key-fn val-fn] :or {key-fn read-kebab-key val-fn identity}}] + (let [f (fn this-fn [x] + (let [x (val-fn x)] + (cond + (array? x) + (persistent! + (.reduce ^js/Array x + #(conj! %1 (this-fn %2)) + (transient []))) + + (identical? (type x) js/Object) + (persistent! + (.reduce ^js/Array (js-keys x) + #(assoc! %1 (key-fn %2) (this-fn (unchecked-get x %2))) + (transient {}))) + + :else + x)))] + (f o)))) + +(defn encode + [data & {:as opts}] + #?(:clj (j/write-str data opts) + :cljs (.stringify js/JSON (->js data opts)))) + +(defn decode + [data & {:as opts}] + #?(:clj (j/read-str data opts) + :cljs (->clj (.parse js/JSON data) opts))) diff --git a/frontend/src/app/worker/export.cljs b/frontend/src/app/worker/export.cljs index bd1ccd10c..2c346e718 100644 --- a/frontend/src/app/worker/export.cljs +++ b/frontend/src/app/worker/export.cljs @@ -7,6 +7,7 @@ (ns app.worker.export (:require [app.common.data :as d] + [app.common.json :as json] [app.common.media :as cm] [app.common.text :as ct] [app.common.types.components-list :as ctkl] @@ -16,7 +17,6 @@ [app.main.render :as r] [app.main.repo :as rp] [app.util.http :as http] - [app.util.json :as json] [app.util.webapi :as wapi] [app.util.zip :as uz] [app.worker.impl :as impl] diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index 89e50c6aa..f3b4fd962 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -9,18 +9,21 @@ (:require ["jszip" :as zip] [app.common.data :as d] + [app.common.exceptions :as ex] [app.common.files.builder :as fb] [app.common.geom.point :as gpt] [app.common.geom.shapes.path :as gpa] + [app.common.json :as json] [app.common.logging :as log] [app.common.media :as cm] [app.common.pprint :as pp] + [app.common.schema :as sm] [app.common.text :as ct] + [app.common.time :as tm] [app.common.uuid :as uuid] [app.main.repo :as rp] [app.util.http :as http] [app.util.i18n :as i18n :refer [tr]] - [app.util.json :as json] [app.util.sse :as sse] [app.util.webapi :as wapi] [app.util.zip :as uz] @@ -37,6 +40,29 @@ (def conjv (fnil conj [])) +(def ^:private iso-date-rx + "Incomplete ISO regex for detect datetime-like values on strings" + #"^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d.*") + +(defn read-json-key + [m] + (or (sm/parse-uuid m) + (json/read-kebab-key m))) + +(defn read-json-val + [m] + (cond + (and (string? m) + (re-matches sm/uuid-rx m)) + (uuid/uuid m) + + (and (string? m) + (re-matches iso-date-rx m)) + (or (ex/ignoring (tm/parse-instant m)) m) + + :else + m)) + (defn get-file "Resolves the file inside the context given its id and the data" ([context type] @@ -62,22 +88,22 @@ parse-svg? (and (not= type :media) (str/ends-with? path "svg")) parse-json? (and (not= type :media) (str/ends-with? path "json")) - no-parse? (or (= type :media) - (not (or parse-svg? parse-json?))) - - file-type (if (or parse-svg? parse-json?) "text" "blob")] + file-type (if (or parse-svg? parse-json?) "text" "blob")] (log/debug :action "parsing" :path path) - (cond->> (uz/get-file (:zip context) path file-type) - parse-svg? - (rx/map (comp tubax/xml->clj :content)) + (let [stream (->> (uz/get-file (:zip context) path file-type) + (rx/map :content))] - parse-json? - (rx/map (comp json/decode :content)) + (cond + parse-svg? + (rx/map tubax/xml->clj stream) - no-parse? - (rx/map :content))))) + parse-json? + (rx/map #(json/decode % :key-fn read-json-key :val-fn read-json-val) stream) + + :else + stream))))) (defn progress! ([context type] @@ -319,7 +345,7 @@ (assoc :id (resolve old-id))) (cond-> (< (:version context 1) 2) (translate-frame type file)) - ;; Shapes inside the deleted component should be stored with absolute coordinates + ;; Shapes inside the deleted component should be stored with absolute coordinates ;; so we calculate that with the x and y stored in the context (cond-> (:x context) (assoc :x (:x context))) @@ -569,7 +595,7 @@ (update :id resolve))] (fb/add-library-color file color)))] (->> (get-file context :colors-list) - (rx/merge-map (comp d/kebab-keys parser/string->uuid)) + (rx/merge-map identity) (rx/mapcat (fn [[id color]] (let [color (assoc color :id id) @@ -599,7 +625,7 @@ (if (:has-typographies context) (let [resolve (:resolve context)] (->> (get-file context :typographies) - (rx/merge-map (comp d/kebab-keys parser/string->uuid)) + (rx/merge-map identity) (rx/map (fn [[id typography]] (-> typography (d/kebab-keys) @@ -613,7 +639,7 @@ (if (:has-media context) (let [resolve (:resolve context)] (->> (get-file context :media-list) - (rx/merge-map (comp d/kebab-keys parser/string->uuid)) + (rx/merge-map identity) (rx/mapcat (fn [[id media]] (let [media (-> media @@ -725,7 +751,6 @@ (rx/filter (fn [data] (= "application/zip" (:type data)))) (rx/merge-map #(zip/loadAsync (:body %))) (rx/merge-map #(get-file {:zip %} :manifest)) - (rx/map (comp d/kebab-keys parser/string->uuid)) (rx/map (fn [data] ;; Checks if the file is exported with components v2 and the current team only diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 01b11784c..58869b2f0 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -10,8 +10,8 @@ [app.common.data.macros :as dm] [app.common.files.repair :as cfr] [app.common.files.validate :as cfv] + [app.common.json :as json] [app.common.logging :as l] - [app.common.math :as mth] [app.common.transit :as t] [app.common.types.file :as ctf] [app.common.uri :as u] @@ -97,26 +97,14 @@ (effect-fn input) (rf result input))))) -(defn prettify - "Prepare x for cleaner output when logged." - [x] - (cond - (map? x) (d/mapm #(prettify %2) x) - (vector? x) (mapv prettify x) - (seq? x) (map prettify x) - (set? x) (into #{} (map prettify) x) - (number? x) (mth/precision x 4) - (uuid? x) (str/concat "#uuid " x) - :else x)) - (defn ^:export logjs ([str] (tap (partial logjs str))) ([str val] - (js/console.log str (clj->js (prettify val) :keyword-fn (fn [v] (str/concat v)))) + (js/console.log str (json/->js val)) val)) (when (exists? js/window) - (set! (.-dbg ^js js/window) clj->js) + (set! (.-dbg ^js js/window) json/->js) (set! (.-pp ^js js/window) pprint)) (defonce widget-style " @@ -479,7 +467,7 @@ (let [result (map (fn [row] (update row :id str)) result)] - (js/console.table (clj->js result)))) + (js/console.table (json/->js result)))) (fn [cause] (js/console.log "EE:" cause)))) nil))