♻️ Replace format string with version integer in library export API

Use version (1 for legacy, 2 for compact) instead of format strings
("compact" / "legacy") throughout the export pipeline. Matches the
backend pattern where version alone determines format behavior. Added
validation that rejects invalid versions with a clear error.

AI-assisted-by: deepseek-v4-pro
This commit is contained in:
Andrey Antukh 2026-07-20 07:32:18 +00:00
parent 8504bb58bf
commit 29345fd381
2 changed files with 27 additions and 25 deletions

View File

@ -95,7 +95,7 @@
(-> shape encode-shape json/encode)))
(defn- generate-file-export-procs
[format {:keys [id data] :as file}]
[version {:keys [id data] :as file}]
(cons
(let [file (cond-> (select-keys file file-attrs)
(:options data)
@ -106,7 +106,7 @@
(concat
(let [pages (get data :pages)
pages-index (get data :pages-index)
compact? (= format "compact")]
compact? (= version 2)]
(->> (d/enumerate pages)
(mapcat
@ -175,9 +175,9 @@
json/encode))])))))
(defn- generate-files-export-procs
[state format]
[state version]
(->> (vals (get state ::fb/files))
(mapcat #(generate-file-export-procs format %))))
(mapcat #(generate-file-export-procs version %))))
(defn- generate-media-export-procs
[state]
@ -201,7 +201,7 @@
(json/encode)))]))))))
(defn- generate-manifest-procs
[state format]
[state version]
(let [opts (get state :options)
files (->> (get state ::fb/files)
(mapv (fn [[file-id file]]
@ -209,7 +209,7 @@
:name (:name file)
:features (:features file)})))
params {:type "penpot/export-files"
:version (if (= format "compact") 2 1)
:version version
:generated-by "penpot-library/%version%"
:referer (get opts :referer)
:files files
@ -221,11 +221,11 @@
(delay (json/encode params))]))
(defn- generate-procs
[state format]
[state version]
(let [state (deref state)]
(cons (generate-manifest-procs state format)
(cons (generate-manifest-procs state version)
(concat
(generate-files-export-procs state format)
(generate-files-export-procs state version)
(generate-media-export-procs state)))))
(def ^:private
@ -238,8 +238,10 @@
(constantly nil))
(defn- export
[state writer progress-fn format]
(let [procs (into [] xf:add-proc-index (generate-procs state format))
[state writer progress-fn version]
(when-not (or (= version 1) (= version 2))
(throw (js/Error. (str "export: invalid version " version ", expected 1 or 2"))))
(let [procs (into [] xf:add-proc-index (generate-procs state version))
total (count procs)]
(->> (p/reduce (fn [writer [path data index]]
(let [data (if (delay? data) (deref data) data)
@ -257,7 +259,7 @@
(defn export-bytes
([state]
(export state (zip/writer (zip/bytes-writer)) noop-fn "legacy"))
(export state (zip/writer (zip/bytes-writer)) noop-fn 1))
([state options]
(let [options
(if (object? options)
@ -267,14 +269,14 @@
progress-fn
(get options :on-progress noop-fn)
format
(get options :format "legacy")]
version
(get options :version 1)]
(export state (zip/writer (zip/bytes-writer)) progress-fn format))))
(export state (zip/writer (zip/bytes-writer)) progress-fn version))))
(defn export-blob
([state]
(export state (zip/writer (zip/blob-writer)) noop-fn "legacy"))
(export state (zip/writer (zip/blob-writer)) noop-fn 1))
([state options]
(let [options
(if (object? options)
@ -284,14 +286,14 @@
progress-fn
(get options :on-progress noop-fn)
format
(get options :format "legacy")]
version
(get options :version 1)]
(export state (zip/writer (zip/blob-writer)) progress-fn format))))
(export state (zip/writer (zip/blob-writer)) progress-fn version))))
(defn export-stream
([state stream]
(export state (zip/writer stream) noop-fn "legacy"))
(export state (zip/writer stream) noop-fn 1))
([state stream options]
(let [options
(if (object? options)
@ -301,7 +303,7 @@
progress-fn
(get options :on-progress noop-fn)
format
(get options :format "legacy")]
version
(get options :version 1)]
(export state (zip/writer stream) progress-fn format))))
(export state (zip/writer stream) progress-fn version))))

View File

@ -227,7 +227,7 @@ test("export compact format produces page-level objects", async () => {
context.addRect({name: "rect1", x: 100, y: 200, width: 50, height: 30});
const blob = await penpot.exportAsBlob(context, {format: "compact"});
const blob = await penpot.exportAsBlob(context, {version: 2});
const zipReader = new ZipReader(new BlobReader(new Blob([blob])));
const entries = await zipReader.getEntries();
@ -262,7 +262,7 @@ test("export legacy format produces per-shape entries", async () => {
context.addRect({name: "rect1", x: 100, y: 200, width: 50, height: 30});
const blob = await penpot.exportAsBlob(context, {format: "legacy"});
const blob = await penpot.exportAsBlob(context, {version: 1});
const zipReader = new ZipReader(new BlobReader(new Blob([blob])));
const entries = await zipReader.getEntries();