Repository: penpot/penpot
File: frontend/src/app/main/ui/workspace/tokens/modals/import.cljs (ClojureScript)

Code before:

        on-display-file-explorer
        (mf/use-fn #(dom/click (mf/ref-val file-input-ref)))

        on-display-dir-explorer
        (mf/use-fn #(dom/click (mf/ref-val dir-input-ref)))

        on-import-directory
        (mf/use-fn
         (fn [event]
           (let [files (->> (dom/get-target event)
                            (dom/get-files)
                            ;; Read files as text, ignore files with json parse errors
                            (map (fn [file]
                                   (->> (wapi/read-file-as-text file)
                                        (rx/mapcat (fn [json]
                                                     (let [path (.-webkitRelativePath file)]
                                                       (rx/of
                                                        (try
                                                          {(file-path->set-name path) (sd/parse-json json)}
                                                          (catch js/Error e
                                                            {:path path :error e}))))))))))]

             (->> (apply rx/merge files)
                  (rx/reduce (fn [acc cur]
                               (if (:error cur)
                                 acc
                                 (conj acc cur)))
                             {})
                  (rx/map #(sd/decode-json-data (if (= 1 (count %))
                                                  (val (first %))
                                                  %)
                                                (ffirst %)))
                  (on-import-stream))

             (-> (mf/ref-val dir-input-ref)
                 (dom/set-value! "")))))

        on-import
        (mf/use-fn
         (fn [event]
           (let [file (-> (dom/get-target event)
                          (dom/get-files)
                          (first))
                 file-name (remove-path-extension (.-name file))]
             (->> (wapi/read-file-as-text file)
                  (sd/process-json-stream {:file-name file-name})
                  (on-import-stream))

             (-> (mf/ref-val file-input-ref)
                 (dom/set-value! "")))))]

Review comment (suggestion):
Perhaps we should filter out here any files without extension `.json` (it's a waste of time reading them and it may cause out of memory errors if accidentally a huge file is given).

Code after:

(mf/defc import-modal-body*
  {::mf/private true}
  []
  (let [file-input-ref (mf/use-ref)
        dir-input-ref (mf/use-ref)

        on-display-file-explorer
        (mf/use-fn #(dom/click (mf/ref-val file-input-ref)))

        on-display-dir-explorer
        (mf/use-fn #(dom/click (mf/ref-val dir-input-ref)))

        on-import-directory
        (mf/use-fn
         (fn [event]
           (let [files (->> (dom/get-target event)
                            (dom/get-files)
                            (filter (fn [file]
                                      (let [name (.-name file)
                                            type (.-type file)]
                                        (or
                                         (= type "application/json")
                                         (str/ends-with? name ".json")))))
                            ;; Read files as text, ignore files with json parse errors
                            (map (fn [file]
                                   (->> (wapi/read-file-as-text file)
                                        (rx/mapcat (fn [json]
                                                     (let [path (.-webkitRelativePath file)]
                                                       (rx/of
                                                        (try
                                                          {(file-path->set-name path) (sd/parse-json json)}
                                                          (catch js/Error e
                                                            {:path path :error e}))))))))))]

             (->> (apply rx/merge files)
                  (rx/reduce (fn [acc cur]
                               (if (:error cur)
                                 acc
                                 (conj acc cur)))
                             {})
                  (rx/map #(sd/decode-json-data (if (= 1 (count %))
                                                  (val (first %))
                                                  %)
                                                (ffirst %)))
                  (on-import-stream))

             (-> (mf/ref-val dir-input-ref)
                 (dom/set-value! "")))))

        on-import