소스 검색

feat(export): export markdown

- exported contents include embed-blocks & embed-pages
- translate ref-blocks uuid to block-title
rcmerci 4 년 전
부모
커밋
cff78f5ffb
4개의 변경된 파일130개의 추가작업 그리고 3개의 파일을 삭제
  1. 3 1
      src/main/frontend/format/adoc.cljs
  2. 17 1
      src/main/frontend/format/mldoc.cljs
  3. 2 1
      src/main/frontend/format/protocol.cljs
  4. 108 0
      src/main/frontend/handler/export.cljs

+ 3 - 1
src/main/frontend/format/adoc.cljs

@@ -26,4 +26,6 @@
   (lazyLoad [this ok-handler]
     (loader/load
      "https://cdnjs.cloudflare.com/ajax/libs/asciidoctor.js/1.5.9/asciidoctor.min.js"
-     ok-handler)))
+     ok-handler))
+  (exportMarkdown [this content config references]
+    (throw "not support")))

+ 17 - 1
src/main/frontend/format/mldoc.cljs

@@ -14,6 +14,7 @@
 (defonce parseInlineJson (gobj/get Mldoc "parseInlineJson"))
 (defonce parseHtml (gobj/get Mldoc "parseHtml"))
 (defonce anchorLink (gobj/get Mldoc "anchorLink"))
+(defonce parseAndExportMarkdown (gobj/get Mldoc "parseAndExportMarkdown"))
 
 (defn default-config
   [format]
@@ -25,6 +26,12 @@
               :keep_line_break true}
              :format format)))))
 
+(def default-references
+  (js/JSON.stringify
+   (clj->js {:embed_blocks []
+             :embed_pages []
+             :refer_blocks []})))
+
 (defn parse-json
   [content config]
   (parseJson content (or config default-config)))
@@ -33,6 +40,12 @@
   [text config]
   (parseInlineJson text (or config default-config)))
 
+(defn parse-export-markdown
+  [content config references]
+  (parseAndExportMarkdown content
+                          (or config default-config)
+                          (or references default-references)))
+
 ;; Org-roam
 (defn get-tags-from-definition
   [ast]
@@ -178,7 +191,10 @@
   (loaded? [this]
     true)
   (lazyLoad [this ok-handler]
-    true))
+    true)
+  (exportMarkdown [this content config references]
+    (parse-export-markdown content config references))
+  )
 
 (defn plain->text
   [plains]

+ 2 - 1
src/main/frontend/format/protocol.cljs

@@ -4,4 +4,5 @@
   (toEdn [this content config])
   (toHtml [this content config])
   (loaded? [this])
-  (lazyLoad [this ok-handler]))
+  (lazyLoad [this ok-handler])
+  (exportMarkdown [this content config references]))

+ 108 - 0
src/main/frontend/handler/export.cljs

@@ -1,6 +1,9 @@
 (ns frontend.handler.export
   (:require [frontend.state :as state]
             [frontend.db :as db]
+            [frontend.format.protocol :as fp]
+            [frontend.format :as f]
+            [datascript.core :as d]
             [frontend.util :as util]
             [cljs-bean.core :as bean]
             [clojure.string :as string]
@@ -102,3 +105,108 @@
           (.setAttribute anchor "href" (js/window.URL.createObjectURL zipfile))
           (.setAttribute anchor "download" (.-name zipfile))
           (.click anchor))))))
+
+
+
+(defn- get-file-contents-with-suffix
+  [repo]
+  (let [conn (db/get-conn repo)]
+    (->>
+     (filterv (fn [[path _]]
+                (or (string/ends-with? path ".md")
+                    (string/ends-with? path ".org")))
+              (db/get-file-contents repo))
+     (mapv (fn [[path content]] {:path path :content content
+                                   :names (d/q '[:find [?n ?n2]
+                                                 :in $ ?p
+                                                 :where [?e :file/path ?p]
+                                                 [?e2 :page/file ?e]
+                                                 [?e2 :page/name ?n]
+                                                 [?e2 :page/original-name ?n2]] conn path)
+                                   :format (f/get-format path)})))))
+
+(defn- get-embed-and-refs-blocks-pages-aux
+  [repo page-or-block is-block? exclude-blocks exclude-pages]
+  (let [[ref-blocks ref-pages]
+        (->> (if is-block?
+               [page-or-block]
+               (db/get-page-blocks
+                repo page-or-block {:use-cache? false
+                                    :pull-keys '[:block/ref-pages :block/ref-blocks]}))
+             (filterv #(or (:block/ref-blocks %) (:block/ref-pages %)))
+             (mapv (fn [b] [(:block/ref-blocks b), (:block/ref-pages b)]))
+             (apply mapv vector)
+             (mapv #(vec (distinct (flatten (remove nil? %))))))
+        ref-block-ids
+        (->> ref-blocks
+             (#(remove (fn [b] (contains? exclude-blocks (:db/id b))) %))
+             (mapv #(:db/id %)))
+        ref-page-ids
+        (->> ref-pages
+             (#(remove (fn [b] (contains? exclude-pages (:db/id b))) %))
+             (mapv #(:db/id %)))
+        ref-blocks
+        (->> ref-block-ids
+             (db/pull-many repo '[*])
+             (flatten))
+        ref-pages
+        (->> ref-page-ids
+             (db/pull-many repo '[*])
+             (flatten))
+        [next-ref-blocks1 next-ref-pages1]
+        (->> ref-blocks
+             (mapv #(get-embed-and-refs-blocks-pages-aux repo % true
+                                                         (set (concat ref-block-ids exclude-blocks)) exclude-pages))
+             (apply mapv vector))
+        [next-ref-blocks2 next-ref-pages2]
+        (->> ref-pages
+             (mapv #(get-embed-and-refs-blocks-pages-aux repo (:page/name %) false
+                                                         exclude-blocks (set (concat ref-page-ids exclude-pages))))
+             (apply mapv vector))]
+    [(->> (concat ref-block-ids next-ref-blocks1 next-ref-blocks2)
+          (flatten)
+          (distinct))
+     (->> (concat ref-page-ids next-ref-pages1 next-ref-pages2)
+          (flatten)
+          (distinct))]))
+
+
+(defn- get-embed-and-refs-blocks-pages
+  [repo page]
+  (let [[block-ids page-ids]
+        (get-embed-and-refs-blocks-pages-aux repo page false #{} #{})
+        blocks
+        (db/pull-many repo '[*] block-ids)
+        pages-name-and-content
+        (->> page-ids
+             (d/q '[:find ?n (pull ?p [:file/path])
+                    :in $ [?e ...]
+                    :where
+                    [?e :page/file ?p]
+                    [?e :page/name ?n]] (db/get-conn repo))
+             (mapv (fn [[page-name file-path]] [page-name (:file/path file-path)]))
+             (d/q '[:find ?n ?c
+                    :in $ [[?n ?p] ...]
+                    :where
+                    [?e :file/path ?p]
+                    [?e :file/content ?c]] @(db/get-files-conn repo)))
+        embed-blocks
+        (mapv (fn [b] [(str (:block/uuid b))
+                       [(apply str
+                               (mapv #(:block/content %)
+                                     (db/get-block-and-children repo (:block/uuid b))))
+                        (:block/title b)]])
+              blocks)]
+    {:embed_blocks embed-blocks
+     :embed_pages pages-name-and-content}))
+
+
+(defn export-repo-as-markdown!
+  [repo]
+  (when-let [repo (state/get-current-repo)]
+    (when-let [files (get-file-contents-with-suffix repo)]
+      (mapv (fn [{:keys [path content names format]}]
+              [path (fp/exportMarkdown f/mldoc-record content
+                                       (f/get-default-config format)
+                                       (js/JSON.stringify
+                                        (clj->js (get-embed-and-refs-blocks-pages repo (first names)))))]) files))))