🐛 Fix json encoding on zip encoding decoding

This commit is contained in:
Andrey Antukh 2024-08-26 20:41:05 +02:00
parent 1f53e48032
commit 2643dae0a7
4 changed files with 120 additions and 72 deletions

View file

@ -5,12 +5,11 @@
;; Copyright (c) KALEIDOS INC ;; Copyright (c) KALEIDOS INC
(ns app.common.json (ns app.common.json
(:refer-clojure :exclude [read]) (:refer-clojure :exclude [read clj->js js->clj])
(:require (:require
#?(:clj [clojure.data.json :as j]) #?(:clj [clojure.data.json :as j])
[cuerdas.core :as str])) [cuerdas.core :as str]))
#?(:clj #?(:clj
(defn read (defn read
[reader & {:as opts}] [reader & {:as opts}]
@ -21,34 +20,6 @@
[writer data & {:as opts}] [writer data & {:as opts}]
(j/write data writer 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 (defn read-kebab-key
[k] [k]
(if (and (string? k) (not (str/includes? k "/"))) (if (and (string? k) (not (str/includes? k "/")))
@ -61,12 +32,76 @@
(str/camel k) (str/camel k)
(str k))) (str k)))
#?(:clj #?(:cljs
(defn encode (defn ->js
[data & {:as opts}] [x & {:keys [key-fn]
(j/write-str data opts))) :or {key-fn write-camel-key} :as opts}]
(let [f (fn this-fn [x]
(cond
(nil? x)
nil
#?(:clj (satisfies? cljs.core/IEncodeJS x)
(defn decode (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}] [data & {:as opts}]
(j/read-str data 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)))

View file

@ -7,6 +7,7 @@
(ns app.worker.export (ns app.worker.export
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.json :as json]
[app.common.media :as cm] [app.common.media :as cm]
[app.common.text :as ct] [app.common.text :as ct]
[app.common.types.components-list :as ctkl] [app.common.types.components-list :as ctkl]
@ -16,7 +17,6 @@
[app.main.render :as r] [app.main.render :as r]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.util.http :as http] [app.util.http :as http]
[app.util.json :as json]
[app.util.webapi :as wapi] [app.util.webapi :as wapi]
[app.util.zip :as uz] [app.util.zip :as uz]
[app.worker.impl :as impl] [app.worker.impl :as impl]

View file

@ -9,18 +9,21 @@
(:require (:require
["jszip" :as zip] ["jszip" :as zip]
[app.common.data :as d] [app.common.data :as d]
[app.common.exceptions :as ex]
[app.common.files.builder :as fb] [app.common.files.builder :as fb]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.path :as gpa] [app.common.geom.shapes.path :as gpa]
[app.common.json :as json]
[app.common.logging :as log] [app.common.logging :as log]
[app.common.media :as cm] [app.common.media :as cm]
[app.common.pprint :as pp] [app.common.pprint :as pp]
[app.common.schema :as sm]
[app.common.text :as ct] [app.common.text :as ct]
[app.common.time :as tm]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.util.http :as http] [app.util.http :as http]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[app.util.json :as json]
[app.util.sse :as sse] [app.util.sse :as sse]
[app.util.webapi :as wapi] [app.util.webapi :as wapi]
[app.util.zip :as uz] [app.util.zip :as uz]
@ -37,6 +40,29 @@
(def conjv (fnil conj [])) (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 (defn get-file
"Resolves the file inside the context given its id and the data" "Resolves the file inside the context given its id and the data"
([context type] ([context type]
@ -62,22 +88,22 @@
parse-svg? (and (not= type :media) (str/ends-with? path "svg")) parse-svg? (and (not= type :media) (str/ends-with? path "svg"))
parse-json? (and (not= type :media) (str/ends-with? path "json")) 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) (log/debug :action "parsing" :path path)
(cond->> (uz/get-file (:zip context) path file-type) (let [stream (->> (uz/get-file (:zip context) path file-type)
(rx/map :content))]
(cond
parse-svg? parse-svg?
(rx/map (comp tubax/xml->clj :content)) (rx/map tubax/xml->clj stream)
parse-json? parse-json?
(rx/map (comp json/decode :content)) (rx/map #(json/decode % :key-fn read-json-key :val-fn read-json-val) stream)
no-parse? :else
(rx/map :content))))) stream)))))
(defn progress! (defn progress!
([context type] ([context type]
@ -569,7 +595,7 @@
(update :id resolve))] (update :id resolve))]
(fb/add-library-color file color)))] (fb/add-library-color file color)))]
(->> (get-file context :colors-list) (->> (get-file context :colors-list)
(rx/merge-map (comp d/kebab-keys parser/string->uuid)) (rx/merge-map identity)
(rx/mapcat (rx/mapcat
(fn [[id color]] (fn [[id color]]
(let [color (assoc color :id id) (let [color (assoc color :id id)
@ -599,7 +625,7 @@
(if (:has-typographies context) (if (:has-typographies context)
(let [resolve (:resolve context)] (let [resolve (:resolve context)]
(->> (get-file context :typographies) (->> (get-file context :typographies)
(rx/merge-map (comp d/kebab-keys parser/string->uuid)) (rx/merge-map identity)
(rx/map (fn [[id typography]] (rx/map (fn [[id typography]]
(-> typography (-> typography
(d/kebab-keys) (d/kebab-keys)
@ -613,7 +639,7 @@
(if (:has-media context) (if (:has-media context)
(let [resolve (:resolve context)] (let [resolve (:resolve context)]
(->> (get-file context :media-list) (->> (get-file context :media-list)
(rx/merge-map (comp d/kebab-keys parser/string->uuid)) (rx/merge-map identity)
(rx/mapcat (rx/mapcat
(fn [[id media]] (fn [[id media]]
(let [media (-> media (let [media (-> media
@ -725,7 +751,6 @@
(rx/filter (fn [data] (= "application/zip" (:type data)))) (rx/filter (fn [data] (= "application/zip" (:type data))))
(rx/merge-map #(zip/loadAsync (:body %))) (rx/merge-map #(zip/loadAsync (:body %)))
(rx/merge-map #(get-file {:zip %} :manifest)) (rx/merge-map #(get-file {:zip %} :manifest))
(rx/map (comp d/kebab-keys parser/string->uuid))
(rx/map (rx/map
(fn [data] (fn [data]
;; Checks if the file is exported with components v2 and the current team only ;; Checks if the file is exported with components v2 and the current team only

View file

@ -10,8 +10,8 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.repair :as cfr] [app.common.files.repair :as cfr]
[app.common.files.validate :as cfv] [app.common.files.validate :as cfv]
[app.common.json :as json]
[app.common.logging :as l] [app.common.logging :as l]
[app.common.math :as mth]
[app.common.transit :as t] [app.common.transit :as t]
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.common.uri :as u] [app.common.uri :as u]
@ -97,26 +97,14 @@
(effect-fn input) (effect-fn input)
(rf result 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 (defn ^:export logjs
([str] (tap (partial logjs str))) ([str] (tap (partial logjs str)))
([str val] ([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)) val))
(when (exists? js/window) (when (exists? js/window)
(set! (.-dbg ^js js/window) clj->js) (set! (.-dbg ^js js/window) json/->js)
(set! (.-pp ^js js/window) pprint)) (set! (.-pp ^js js/window) pprint))
(defonce widget-style " (defonce widget-style "
@ -479,7 +467,7 @@
(let [result (map (fn [row] (let [result (map (fn [row]
(update row :id str)) (update row :id str))
result)] result)]
(js/console.table (clj->js result)))) (js/console.table (json/->js result))))
(fn [cause] (fn [cause]
(js/console.log "EE:" cause)))) (js/console.log "EE:" cause))))
nil)) nil))