Merge branch 'master' into feat/pdf-shape

This commit is contained in:
Konstantinos Kaloutas
2023-06-26 14:25:04 +03:00
38 changed files with 575 additions and 214 deletions

View File

@@ -213,6 +213,7 @@
(second (re-find #"(?:\.)(\w+)[^.]*$" path-or-file-name)))
(defn get-format
"File path to format keyword, :org, :markdown, etc."
[file]
(when file
(normalize-format (keyword (some-> (path->file-ext file) string/lower-case)))))

View File

@@ -47,7 +47,7 @@
(fs/mkdirSync (path/join dir "journals"))
(fs/mkdirSync (path/join dir "pages")))
(deftest ^:focus build-graph-files
(deftest build-graph-files
(create-logseq-graph "tmp/test-graph")
;; Create files that are recognized
(fs/writeFileSync "tmp/test-graph/pages/foo.md" "")

View File

@@ -519,7 +519,7 @@
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 0.9.9;
MARKETING_VERSION = 0.9.10;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -546,7 +546,7 @@
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 0.9.9;
MARKETING_VERSION = 0.9.10;
PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
@@ -571,7 +571,7 @@
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 0.9.9;
MARKETING_VERSION = 0.9.10;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController;
@@ -598,7 +598,7 @@
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 0.9.9;
MARKETING_VERSION = 0.9.10;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.logseq.logseq.ShareViewController;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -90,8 +90,8 @@
"@capawesome/capacitor-background-task": "^2.0.0",
"@excalidraw/excalidraw": "0.12.0",
"@hugotomazi/capacitor-navigation-bar": "^2.0.0",
"@logseq/capacitor-file-sync": "0.0.24",
"@logseq/diff-merge": "^0.0.2",
"@logseq/capacitor-file-sync": "0.0.30",
"@logseq/diff-merge": "0.1.0",
"@logseq/react-tweet-embed": "1.3.1-1",
"@radix-ui/colors": "^0.1.8",
"@sentry/react": "^6.18.2",
@@ -117,7 +117,7 @@
"highlight.js": "10.4.1",
"ignore": "5.1.8",
"jszip": "3.8.0",
"mldoc": "^1.5.5",
"mldoc": "1.5.7",
"path": "0.12.7",
"path-complete-extname": "1.0.0",
"pixi-graph-fork": "0.2.0",

View File

@@ -37,7 +37,7 @@
"https-proxy-agent": "5.0.0",
"@sentry/electron": "2.5.1",
"posthog-js": "1.10.2",
"@logseq/rsapi": "0.0.70",
"@logseq/rsapi": "0.0.73",
"electron-deeplink": "1.0.10",
"abort-controller": "3.0.0",
"fastify": "latest",

View File

@@ -38,6 +38,7 @@
frontend.modules.instrumentation.sentry/SENTRY-DSN #shadow/env "LOGSEQ_SENTRY_DSN"
frontend.modules.instrumentation.posthog/POSTHOG-TOKEN #shadow/env "LOGSEQ_POSTHOG_TOKEN"
frontend.config/ENABLE-PLUGINS #shadow/env ["ENABLE_PLUGINS" :as :bool :default true]
;; Set to switch file sync server to dev, set this to false in `yarn watch`
frontend.config/ENABLE-FILE-SYNC-PRODUCTION #shadow/env ["ENABLE_FILE_SYNC_PRODUCTION" :as :bool :default true]
frontend.config/TEST #shadow/env ["LOGSEQ_CI" :as :bool :default false]
frontend.config/REVISION #shadow/env ["LOGSEQ_REVISION" :default "dev"]} ;; set by git-revision-hook

View File

@@ -26,6 +26,9 @@
(defn delete-local-files [graph-uuid base-path file-paths]
(rsapi/deleteLocalFiles graph-uuid base-path (clj->js file-paths)))
(defn fetch-remote-files [graph-uuid base-path file-paths token]
(rsapi/fetchRemoteFiles graph-uuid base-path (clj->js file-paths) token))
(defn update-local-files [graph-uuid base-path file-paths token]
(rsapi/updateLocalFiles graph-uuid base-path (clj->js file-paths) token))

View File

@@ -96,6 +96,10 @@
(catch :default _e
false)))
(defmethod handle :copyFile [_window [_ _repo from-path to-path]]
(logger/info ::copy-file from-path to-path)
(fs-extra/copy from-path to-path))
(defmethod handle :writeFile [window [_ repo path content]]
(let [^js Buf (.-Buffer buffer)
^js content (if (instance? js/ArrayBuffer content)
@@ -636,6 +640,9 @@
(defmethod handle :delete-local-files [_ args]
(apply rsapi/delete-local-files (rest args)))
(defmethod handle :fetch-remote-files [_ args]
(apply rsapi/fetch-remote-files (rest args)))
(defmethod handle :update-local-files [_ args]
(apply rsapi/update-local-files (rest args)))

View File

@@ -89,7 +89,7 @@
(if favorited?
(page-handler/unfavorite-page! page-original-name)
(page-handler/favorite-page! page-original-name)))}})
(when (or (util/electron?) file-sync-graph-uuid)
{:title (t :page/version-history)
:options {:on-click
@@ -117,12 +117,12 @@
(when (and (not (mobile-util/native-platform?))
(state/get-current-page))
{:title (t :page/presentation-mode)
{:title (t :page/slide-view)
:options {:on-click (fn []
(state/sidebar-add-block!
repo
(:db/id page)
:page-presentation))}})
:page-slide-view))}})
;; TODO: In the future, we'd like to extract file-related actions
;; (such as open-in-finder & open-with-default-app) into a sub-menu of

View File

@@ -16,7 +16,7 @@
[frontend.handler.ui :as ui-handler]
[frontend.state :as state]
[frontend.ui :as ui]
[frontend.util :as util]
[frontend.util :as util]
[frontend.config :as config]
[frontend.modules.editor.undo-redo :as undo-redo]
[goog.object :as gobj]
@@ -159,7 +159,7 @@
[:div.ml-2
(page-cp repo page-name)]])
:page-presentation
:page-slide-view
(let [page-name (:block/name (db/entity db-id))]
[[:a.page-title {:href (rfe/href :page {:name page-name})}
(db-model/get-page-original-name page-name)]

View File

@@ -137,6 +137,22 @@
new-fpath (path/path-join repo-dir new-path)]
(protocol/rename! (get-fs old-fpath) repo old-fpath new-fpath)))))
(defn stat
([fpath]
(protocol/stat (get-fs fpath) fpath))
([dir path]
(let [fpath (path/path-join dir path)]
(protocol/stat (get-fs dir) fpath))))
(defn mkdir-if-not-exists
[dir]
(when dir
(util/p-handle
(stat dir)
(fn [_stat])
(fn [_error]
(mkdir-recur! dir)))))
(defn copy!
"Only used by Logseq Sync"
[repo old-path new-path]
@@ -149,15 +165,13 @@
(map #(if (or (util/electron?) (mobile-util/native-platform?))
%
(str (config/get-repo-dir repo) "/" %))
[old-path new-path])]
(protocol/copy! (get-fs old-path) repo old-path new-path))))
[old-path new-path])
new-dir (path/dirname new-path)]
(p/do!
(mkdir-if-not-exists new-dir)
(protocol/copy! (get-fs old-path) repo old-path new-path)))))
(defn stat
([fpath]
(protocol/stat (get-fs fpath) fpath))
([dir path]
(let [fpath (path/path-join dir path)]
(protocol/stat (get-fs dir) fpath))))
(defn open-dir
[dir]
@@ -192,15 +206,6 @@
[dir]
(protocol/unwatch-dir! (get-fs dir) dir))
(defn mkdir-if-not-exists
[dir]
(when dir
(util/p-handle
(stat dir)
(fn [_stat])
(fn [_error]
(mkdir! dir)))))
;; FIXME: counterintuitive return value
(defn create-if-not-exists
"Create a file if it doesn't exist. return false on written, true on already exists"

View File

@@ -1,24 +1,17 @@
(ns frontend.fs.diff-merge
"Implementation of text (file) based content diff & merge for conflict resolution"
(:require ["@logseq/diff-merge" :refer [Differ attach_uuids]]
(:require ["@logseq/diff-merge" :refer [attach_uuids Differ Merger]]
[cljs-bean.core :as bean]
[frontend.db.model :as db-model]
[frontend.db.utils :as db-utils]
[logseq.graph-parser.block :as gp-block]
[logseq.graph-parser.mldoc :as gp-mldoc]
[logseq.graph-parser.property :as gp-property]
[logseq.graph-parser.utf8 :as utf8]
[cljs-bean.core :as bean]
[frontend.db.utils :as db-utils]
[frontend.db.model :as db-model]))
[clojure.string :as string]))
;; (defn diff-merge
;; "N-ways diff & merge
;; Accept: blocks
;; https://github.com/logseq/diff-merge/blob/44546f2427f20bd417b898c8ba7b7d10a9254774/lib/mldoc.ts#L17-L22
;; https://github.com/logseq/diff-merge/blob/85ca7e9bf7740d3880ed97d535a4f782a963395d/lib/merge.ts#L40"
;; [base & branches]
;; ()
;; (let [merger (Merger.)]
;; (.mergeBlocks merger (bean/->js base) (bean/->js branches))))
(defn diff
(defn diff
"2-ways diff
Accept: blocks in the struct with the required info
Please refer to the `Block` struct in the link below
@@ -46,6 +39,7 @@
blocks levels)]
blocks))
;; TODO: Switch to ast->diff-blocks-alt
;; Diverged from gp-block/extract-blocks for decoupling
;; The process of doing 2 way diff is like:
;; 1. Given a base ver. of page (AST in DB), and a branch ver. of page (externally modified file content)
@@ -71,7 +65,7 @@
pos-meta (assoc pos-meta :end_pos end-pos)]
(cond
(gp-block/heading-block? block)
(let [content (gp-block/get-block-content encoded-content block format pos-meta block-pattern)]
(let [content (gp-block/get-block-content encoded-content (second block) format pos-meta block-pattern)]
(recur (conj headings {:body content
:level (:level (second block))
:uuid (:id properties)})
@@ -87,6 +81,7 @@
(recur headings (rest blocks) properties (:end_pos pos-meta))))
(if (empty? properties)
(reverse headings)
;; Add pre-blocks
(let [[block _] (first blocks)
pos-meta {:start_pos 0 :end_pos end-pos}
content (gp-block/get-block-content encoded-content block format pos-meta block-pattern)
@@ -95,3 +90,107 @@
:level 1
:uuid uuid}
(reverse headings))))))))
(defn- get-sub-content-from-pos-meta
"Replace gp-block/get-block-content, return bare content, without any trim"
[raw-content pos-meta]
(let [{:keys [start_pos end_pos]} pos-meta]
(utf8/substring raw-content start_pos end_pos)))
;; Diverged from ast->diff-blocks
;; Add :meta :raw-body to the block
(defn- ast->diff-blocks-alt
"Prepare the blocks for diff-merge
blocks: ast of blocks
content: corresponding raw content"
[blocks content format {:keys [user-config block-pattern]}]
{:pre [(string? content) (contains? #{:markdown :org} format)]}
(let [utf8-encoded-content (utf8/encode content)]
(loop [headings []
blocks (reverse blocks)
properties {}
end-pos (.-length utf8-encoded-content)]
(cond
(seq blocks)
(let [[block pos-meta] (first blocks)
;; fix start_pos for properties
fixed-pos-meta (assoc pos-meta :end_pos end-pos)]
(cond
(gp-block/heading-block? block)
(let [content (gp-block/get-block-content utf8-encoded-content (second block) format fixed-pos-meta block-pattern)
content-raw (get-sub-content-from-pos-meta utf8-encoded-content fixed-pos-meta)]
(recur (conj headings {:body content
:meta {:raw-body (string/trimr content-raw)}
:level (:level (second block))
:uuid (:id properties)})
(rest blocks)
{}
(:start_pos fixed-pos-meta))) ;; The current block's start pos is the next block's end pos
(gp-property/properties-ast? block)
(let [new-props (:properties (gp-block/extract-properties (second block) (assoc user-config :format format)))]
;; sending the current end pos to next, as it's not finished yet
;; supports multiple properties sub-block possible in future
(recur headings (rest blocks) (merge properties new-props) (:end_pos fixed-pos-meta)))
:else
(recur headings (rest blocks) properties (:end_pos fixed-pos-meta))))
(empty? properties)
(reverse headings)
;; Add pre-blocks
:else ;; ??? unreachable
(let [[block _] (first blocks)
pos-meta {:start_pos 0 :end_pos end-pos}
content (gp-block/get-block-content utf8-encoded-content block format pos-meta block-pattern)
content-raw (get-sub-content-from-pos-meta utf8-encoded-content pos-meta)
uuid (:id properties)]
(cons {:body content
:meta {:raw-body (string/trimr content-raw)}
:level 1
:uuid uuid}
(reverse headings)))))))
(defn- rebuild-content
"translate [[[op block]]] to merged content"
[_base-diffblocks diffs _format]
;; [[[0 {:body "attrib:: xxx", :level 1, :uuid nil}] ...] ...]
(let [ops-fn (fn [ops]
(map (fn [[op {:keys [meta]}]]
(when (or (= op 0) (= op 1)) ;; equal or insert
(:raw-body meta)))
ops))]
(->> diffs
(mapcat ops-fn)
(filter seq)
(string/join "\n"))))
(defn three-way-merge
[base income current format]
(let [->ast (fn [text] (if (= format :org)
(gp-mldoc/->edn text (gp-mldoc/default-config :org))
(gp-mldoc/->edn text (gp-mldoc/default-config :markdown))))
options (if (= format :org)
{:block-pattern "*"}
{:block-pattern "-"})
merger (Merger.)
base-ast (->ast base)
base-diffblocks (ast->diff-blocks-alt base-ast base format options)
income-ast (->ast income)
income-diffblocks (ast->diff-blocks-alt income-ast income format options)
current-ast (->ast current)
current-diffblocks (ast->diff-blocks-alt current-ast current format options)
branch-diffblocks [income-diffblocks current-diffblocks]
merged (.mergeBlocks merger (bean/->js base-diffblocks) (bean/->js branch-diffblocks))
;; For extracting diff-merge test cases
;; _ (prn "input:")
;; _ (prn (js/JSON.stringify (bean/->js base-diffblocks)))
;; _ (prn (js/JSON.stringify (bean/->js branch-diffblocks)))
;; _ (prn "logseq diff merge version: " version)
;; _ (prn "output:")
;; _ (prn (js/JSON.stringify merged))
merged-diff (bean/->clj merged)
merged-content (rebuild-content base-diffblocks merged-diff format)]
merged-content))

View File

@@ -118,7 +118,9 @@
(rename! [_this _repo old-path new-path]
(ipc/ipc "rename" old-path new-path))
;; copy with overwrite, without confirmation
(copy! [_this repo old-path new-path]
(ipc/ipc "copyFile" repo old-path new-path))
(stat [_this fpath]
(-> (ipc/ipc "stat" fpath)
(p/then bean/->clj)))

View File

@@ -1,41 +1,45 @@
(ns frontend.fs.sync
"Main ns for providing file sync functionality"
(:require [cljs-http.client :as http]
(:require ["@capawesome/capacitor-background-task" :refer [BackgroundTask]]
["path" :as node-path]
[cljs-http.client :as http]
[cljs-time.coerce :as tc]
[cljs-time.core :as t]
[cljs-time.format :as tf]
[cljs-time.coerce :as tc]
[cljs.core.async :as async :refer [go timeout go-loop offer! poll! chan <! >!]]
[cljs.core.async :as async :refer [<! >! chan go go-loop offer!
poll! timeout]]
[cljs.core.async.impl.channels]
[cljs.core.async.interop :refer [p->c]]
[cljs.spec.alpha :as s]
[clojure.pprint :as pp]
[clojure.set :as set]
[clojure.string :as string]
[clojure.pprint :as pp]
[electron.ipc :as ipc]
[goog.string :as gstring]
[frontend.config :as config]
[frontend.debug :as debug]
[frontend.handler.user :as user]
[frontend.state :as state]
[frontend.mobile.util :as mobile-util]
[frontend.util :as util]
[frontend.util.persist-var :as persist-var]
[frontend.util.fs :as fs-util]
[frontend.handler.notification :as notification]
[frontend.context.i18n :refer [t]]
[frontend.diff :as diff]
[frontend.db :as db]
[frontend.fs :as fs]
[frontend.debug :as debug]
[frontend.diff :as diff]
[frontend.encrypt :as encrypt]
[frontend.fs :as fs]
[frontend.fs.capacitor-fs :as capacitor-fs]
[frontend.fs.diff-merge :as diff-merge]
[frontend.handler.file :as file-handler]
[frontend.handler.notification :as notification]
[frontend.handler.user :as user]
[frontend.mobile.util :as mobile-util]
[frontend.pubsub :as pubsub]
[frontend.state :as state]
[frontend.util :as util]
[frontend.util.fs :as fs-util]
[frontend.util.persist-var :as persist-var]
[goog.string :as gstring]
[lambdaisland.glogi :as log]
[logseq.common.path :as path]
[logseq.graph-parser.util :as gp-util]
[medley.core :refer [dedupe-by]]
[rum.core :as rum]
[promesa.core :as p]
[lambdaisland.glogi :as log]
[frontend.fs.capacitor-fs :as capacitor-fs]
["@capawesome/capacitor-background-task" :refer [BackgroundTask]]
["path" :as node-path]))
[rum.core :as rum]))
;;; ### Commentary
;; file-sync related local files/dirs:
@@ -606,7 +610,7 @@
(defn diff-file-metadata-sets
"Find the `FileMetadata`s that exists in s1 and does not exist in s2,
compare by path+checksum+last-modified,
if s1.path = s2.path & s1.checksum <> s2.checksum & s1.last-modified > s2.last-modified
if s1.path = s2.path & s1.checksum <> s2.checksum
(except some default created files),
keep this `FileMetadata` in result"
[s1 s2]
@@ -632,7 +636,11 @@
(and (contains? ignore-default-value-files path)
(#{config/config-default-content-md5 empty-custom-css-md5} (:etag %)))
false
(< last-modified (:last-modified %))
;; special handling for css & edn files
(and
(or (string/ends-with? lower-case-path ".css")
(string/ends-with? lower-case-path ".edn"))
(< last-modified (:last-modified %)))
true)
s2)
result
@@ -719,6 +727,7 @@
(<get-local-all-files-meta [this graph-uuid base-path] "get all local files' metadata")
(<rename-local-file [this graph-uuid base-path from to])
(<update-local-files [this graph-uuid base-path filepaths] "remote -> local")
(<fetch-remote-files [this graph-uuid base-path filepaths] "remote -> local version-db")
(<download-version-files [this graph-uuid base-path filepaths])
(<delete-local-files [this graph-uuid base-path filepaths])
(<update-remote-files [this graph-uuid base-path filepaths local-txid] "local -> remote, return err or txid")
@@ -850,6 +859,12 @@
(<! (<rsapi-cancel-all-requests))
(let [token (<! (<get-token this))]
(<! (p->c (ipc/ipc "update-local-files" graph-uuid base-path filepaths token))))))
(<fetch-remote-files [this graph-uuid base-path filepaths]
(go
(<! (<rsapi-cancel-all-requests))
(let [token (<! (<get-token this))]
(<! (p->c (ipc/ipc "fetch-remote-files" graph-uuid base-path filepaths token))))))
(<download-version-files [this graph-uuid base-path filepaths]
(go
(let [token (<! (<get-token this))
@@ -944,7 +959,16 @@
:basePath base-path
:filePaths filepaths'
:token token})))))))
(<fetch-remote-files [this graph-uuid base-path filepaths]
(go
(let [token (<! (<get-token this))
r (<! (<retry-rsapi
#(p->c (.fetchRemoteFiles mobile-util/file-sync
(clj->js {:graphUUID graph-uuid
:basePath base-path
:filePaths filepaths
:token token})))))]
(js->clj (.-value r)))))
(<download-version-files [this graph-uuid base-path filepaths]
(go
(let [token (<! (<get-token this))
@@ -980,12 +1004,13 @@
r
(get (js->clj r) "txid"))))))
(<delete-remote-files [this graph-uuid _base-path filepaths local-txid]
(<delete-remote-files [this graph-uuid base-path filepaths local-txid]
(let [normalized-filepaths (mapv path-normalize filepaths)]
(go
(let [token (<! (<get-token this))
r (<! (p->c (.deleteRemoteFiles mobile-util/file-sync
(clj->js {:graphUUID graph-uuid
:basePath base-path
:filePaths normalized-filepaths
:txid local-txid
:token token}))))]
@@ -1461,7 +1486,10 @@
(let [rpath (relative-path filetxn)
repo (state/get-current-repo)
repo-dir (config/get-repo-dir repo)
content (<! (p->c (fs/read-file repo-dir rpath)))]
content (<! (p->c (-> (fs/file-exists? repo-dir rpath)
(p/then (fn [exists?]
(when exists?
(fs/read-file repo-dir rpath)))))))]
(and (seq origin-db-content)
(or (nil? content)
(some :removed (diff/diff origin-db-content content))))))))
@@ -1539,6 +1567,117 @@
delete-filetxns)]
(set (concat update-file-items rename-file-items delete-file-items))))
(defn- <apply-remote-deletion
"Apply remote deletion, if the file is not deleted locally, delete it locally.
if the file is changed locally, leave the changed part.
To replace <delete-local-files"
[graph-uuid base-path relative-paths]
(go
(p->c (p/all (->> relative-paths
(map (fn [rpath]
(p/let [base-file (path/path-join "logseq/version-files/base" rpath)
current-change-file rpath
format (gp-util/get-format current-change-file)
repo (state/get-current-repo)
repo-dir (config/get-repo-dir repo)
base-exists? (fs/file-exists? repo-dir base-file)]
(if base-exists?
(p/let [base-content (fs/read-file repo-dir base-file)
current-content (-> (fs/read-file repo-dir current-change-file)
(p/catch (fn [_] nil)))]
(if (= base-content current-content)
;; base-content == current-content, delete current-change-file
(p/do!
(<delete-local-files rsapi graph-uuid base-path [rpath])
(fs/unlink! repo (path/path-join repo-dir base-file) {}))
;; base-content != current-content, merge, do not delete
(p/let [merged-content (diff-merge/three-way-merge base-content "" current-content format)]
(fs/write-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
(file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
:from-disk? true
:fs/event :fs/remote-file-change}))))
;; no base-version, use legacy approach, delete it
(<delete-local-files rsapi graph-uuid base-path [rpath]))))))))))
(defn- <fetch-remote-and-update-local-files
[graph-uuid base-path relative-paths]
(go
(let [fetched-file-rpaths-or-ex (<! (<fetch-remote-files rsapi graph-uuid base-path relative-paths))]
(if (instance? ExceptionInfo fetched-file-rpaths-or-ex)
fetched-file-rpaths-or-ex
(<!
(p->c (p/all (->> fetched-file-rpaths-or-ex
(map (fn [rpath]
(p/let [incoming-file (path/path-join "logseq/version-files/incoming" rpath)
base-file (path/path-join "logseq/version-files/base" rpath)
current-change-file rpath
format (gp-util/get-format current-change-file)
repo (state/get-current-repo)
repo-dir (config/get-repo-dir repo)
base-exists? (fs/file-exists? repo-dir base-file)]
(cond
base-exists?
(p/let [base-content (fs/read-file repo-dir base-file)
current-content (-> (fs/read-file repo-dir current-change-file)
(p/catch (fn [_] nil)))
incoming-content (fs/read-file repo-dir incoming-file)]
(if (= base-content current-content)
(do
(prn "[diff-merge]base=current, write directly")
(p/do!
(fs/copy! repo
(path/path-join repo-dir incoming-file)
(path/path-join repo-dir current-change-file))
(fs/copy! repo
(path/path-join repo-dir incoming-file)
(path/path-join repo-dir base-file))
(file-handler/alter-file repo current-change-file incoming-content {:re-render-root? true
:from-disk? true
:fs/event :fs/remote-file-change})))
(do
(prn "[diff-merge]base!=current, 3-way merge")
(p/let [current-content (or current-content "")
incoming-content (fs/read-file repo-dir incoming-file)
merged-content (diff-merge/three-way-merge base-content incoming-content current-content format)]
(when (seq merged-content)
(p/do!
(fs/write-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
(file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
:from-disk? true
:fs/event :fs/remote-file-change})))))))
:else
(do
(prn "[diff-merge]no base found, use empty content as base, avoid loosing data")
(p/let [current-content (-> (fs/read-file repo-dir current-change-file)
(p/catch (fn [_] nil)))
current-content (or current-content "")
incoming-content (fs/read-file repo-dir incoming-file)
merged-content (diff-merge/three-way-merge "" current-content incoming-content format)]
(if (= incoming-content merged-content)
(p/do!
(fs/copy! repo
(path/path-join repo-dir incoming-file)
(path/path-join repo-dir current-change-file))
(fs/copy! repo
(path/path-join repo-dir incoming-file)
(path/path-join repo-dir base-file))
(file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
:from-disk? true
:fs/event :fs/remote-file-change}))
;; else
(p/do!
(fs/write-file! repo repo-dir current-change-file merged-content {:skip-compare? true})
(file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
:from-disk? true
:fs/event :fs/remote-file-change})
(file-handler/alter-file repo current-change-file merged-content {:re-render-root? true
:from-disk? true
:fs/event :fs/remote-file-change})))))))))))))))))
(defn- apply-filetxns
[*sync-state graph-uuid base-path filetxns *paused]
(go
@@ -1574,7 +1713,7 @@
(swap! *sync-state sync-state--remove-recent-remote->local-files
[recent-remote->local-file-item])))))
(let [update-local-files-ch (<update-local-files rsapi graph-uuid base-path (map relative-path filetxns))
(let [update-local-files-ch (<fetch-remote-and-update-local-files graph-uuid base-path (map relative-path filetxns))
r (<! (<with-pause update-local-files-ch *paused))]
(doseq [[filetxn origin-db-content] txn->db-content-vec]
(when (<! (need-add-version-file? filetxn origin-db-content))
@@ -1592,7 +1731,7 @@
(if (<! (<local-file-not-exist? graph-uuid rsapi base-path (relative-path filetxn)))
;; not exist, ignore
true
(let [r (<! (<delete-local-files rsapi graph-uuid base-path [(relative-path filetxn)]))]
(let [r (<! (<apply-remote-deletion graph-uuid base-path [(relative-path filetxn)]))]
(if (and (instance? ExceptionInfo r)
(string/index-of (str (ex-cause r)) "No such file or directory"))
true
@@ -2714,20 +2853,20 @@
;;; ### put all stuff together
(defrecord ^:large-vars/cleanup-todo
SyncManager [user-uuid graph-uuid base-path *sync-state
^Local->RemoteSyncer local->remote-syncer ^Remote->LocalSyncer remote->local-syncer remoteapi
^:mutable ratelimit-local-changes-chan
*txid *txid-for-get-deletion-log
^:mutable state ^:mutable remote-change-chan ^:mutable *ws *stopped? *paused?
^:mutable ops-chan ^:mutable app-awake-from-sleep-chan
SyncManager [user-uuid graph-uuid base-path *sync-state
^Local->RemoteSyncer local->remote-syncer ^Remote->LocalSyncer remote->local-syncer remoteapi
^:mutable ratelimit-local-changes-chan
*txid *txid-for-get-deletion-log
^:mutable state ^:mutable remote-change-chan ^:mutable *ws *stopped? *paused?
^:mutable ops-chan ^:mutable app-awake-from-sleep-chan
;; control chans
private-full-sync-chan private-remote->local-sync-chan
private-remote->local-full-sync-chan private-pause-resume-chan]
private-full-sync-chan private-remote->local-sync-chan
private-remote->local-full-sync-chan private-pause-resume-chan]
Object
(schedule [this next-state args reason]
{:pre [(s/valid? ::state next-state)]}
(println (str "[SyncManager " graph-uuid "]")
(and state (name state)) "->" (and next-state (name next-state)) :reason reason :local-txid @*txid :now (tc/to-string (t/now)))
(and state (name state)) "->" (and next-state (name next-state)) :reason reason :local-txid @*txid :args args :now (tc/to-string (t/now)))
(set! state next-state)
(swap! *sync-state sync-state--update-state next-state)
(go
@@ -2925,7 +3064,7 @@
:epoch (tc/to-epoch (t/now))}})
(.schedule this ::idle nil nil))))))
(remote->local-full-sync [this _]
(remote->local-full-sync [this {:keys [retry-count]}]
(go
(let [{:keys [succ unknown stop pause]}
(<! (<sync-remote->local-all-files! remote->local-syncer))]
@@ -2952,12 +3091,19 @@
:data {:graph-uuid graph-uuid
:exp unknown
:epoch (tc/to-epoch (t/now))}})
(let [next-state (if (string/includes? (str (ex-cause unknown)) "404 Not Found")
;; TODO: this should never happen
::stop
;; if any other exception occurred, re-exec remote->local-full-sync
::remote->local-full-sync)]
(.schedule this next-state nil nil)))))))
(let [next-state
(cond
(string/includes? (str (ex-cause unknown)) "404 Not Found")
;; TODO: this should never happen
::stop
(> retry-count 3)
::stop
:else ;; if any other exception occurred, re-exec remote->local-full-sync
::remote->local-full-sync)]
(.schedule this next-state
(when (= ::remote->local-full-sync next-state) {:retry-count (inc retry-count)})
nil)))))))
(remote->local [this _next-state {remote-val :remote}]
(go
@@ -3002,7 +3148,7 @@
(let [distincted-local-changes (distinct-file-change-events local-changes)
_ (swap! *sync-state #(sync-state-reset-full-local->remote-files % distincted-local-changes))
change-events-partitions
(sequence (partition-file-change-events upload-batch-size) distincted-local-changes)
(sequence (partition-file-change-events upload-batch-size) distincted-local-changes)
_ (put-sync-event! {:event :start
:data {:type :local->remote
:graph-uuid graph-uuid

View File

@@ -72,8 +72,8 @@
Decide how to treat the parsed file based on the file's triggering event
options -
:fs/reset-event - the event that triggered the file update
:fs/local-file-change - file changed on local disk
:fs/remote-file-change - file changed on remote"
:fs/local-file-change - file changed on local disk
:fs/remote-file-change - file changed on remote"
[repo-url file-path content {:fs/keys [event] :as options}]
(let [db-conn (db/get-db repo-url false)]
(case event

View File

@@ -23,7 +23,6 @@
:right-side-bar/switch-theme "Skakel oor na die {1} tema"
:right-side-bar/contents "Inhoud"
:right-side-bar/block-ref "Blok verwysing"
:page/presentation-mode "Aanbiedings modus"
:page/delete-confirmation "Is jy seker jy wil die bladsy uitvee?"
:page/show-journals "Wys joernale"
:file/name "Lêer naam"
@@ -60,7 +59,7 @@
:language "Taal"
:file-sync/other-user-graph "Huidige plaaslike grafiek is gebonde aan ander gebruiker se afgeleë grafiek. So kan nie begin om te sinkroniseer nie."
:file-sync/graph-deleted "Huidige afstandgrafiek is geskrap"
:file-sync/graph-deleted "Huidige afstandgrafiek is geskrap"
:shortcut.category/formatting "Formatering"
:command.editor/indent "Ingekeepte blok oortjie"
@@ -84,4 +83,4 @@
:command.ui/toggle-document-mode "Wissel dokument modus"
:command.go/journals "Spring na joernale"
:command.ui/toggle-theme "Wissel tussen donker/lig temas"
:command.ui/toggle-right-sidebar "Wissel regter sybalk"}
:command.ui/toggle-right-sidebar "Wissel regter sybalk"}

View File

@@ -193,7 +193,6 @@
:page/open-backup-directory "Verzeichnis für Seiten-Backups öffnen"
:page/open-in-finder "Im Verzeichnis öffnen"
:page/open-with-default-app "Mit Standard-Anwendung öffnen"
:page/presentation-mode "Präsentationsmodus"
:page/show-journals "Journal anzeigen"
:page/show-whiteboards "Whiteboards anzeigen"
:page/unfavorite "Seite aus Favoriten entfernen"
@@ -498,4 +497,4 @@
:shortcut.category/formatting "Formatierung"
:shortcut.category/navigating "Navigation"
:shortcut.category/others "Sonstiges"
:shortcut.category/toggle "Umschalten"}
:shortcut.category/toggle "Umschalten"}

View File

@@ -152,7 +152,7 @@
:page/logseq-is-having-a-problem "Logseq is having a problem. To try to get it back to a working state, please try the following safe steps in order:"
:page/step "Step {1}"
:page/try "Try"
:page/presentation-mode "Presentation"
:page/slide-view "View as slides"
:page/delete-confirmation "Are you sure you want to delete this page and its file?"
:page/open-in-finder "Open in directory"
:page/open-with-default-app "Open with default app"

View File

@@ -53,7 +53,6 @@
:left-side-bar/new-page "Nueva página"
:left-side-bar/nav-favorites "Favoritos"
:left-side-bar/nav-recent-pages "Recientes"
:page/presentation-mode "Modo presentación"
:page/delete-confirmation "¿Está seguro que desea eliminar esta página y su archivo?"
:page/open-in-finder "Abrir ubicación del archivo"
:page/open-with-default-app "Abrir con la aplicación predeterminada"

View File

@@ -33,7 +33,6 @@
:right-side-bar/flashcards "Cartes-mémoire"
:right-side-bar/new-page "Nouvelle page"
:left-side-bar/journals "Journaux"
:page/presentation-mode "Mode présentation"
:page/delete-confirmation "Etes-vous sûr de vouloir supprimer la page ?"
:page/make-public "Rendre la page publique"
:page/make-private "Rendre la page privée"
@@ -437,4 +436,4 @@
:shortcut.category/others "Autres"
:shortcut.category/toggle "Basculer"
:command.editor/select-parent "Sélectionnez le bloc parent"
:command.sidebar/close-top "Ferme l'élément supérieur dans la barre latérale droite"}
:command.sidebar/close-top "Ferme l'élément supérieur dans la barre latérale droite"}

View File

@@ -51,7 +51,6 @@
:left-side-bar/new-page "Nuova pagina"
:left-side-bar/nav-favorites "Preferiti"
:left-side-bar/nav-recent-pages "Recenti"
:page/presentation-mode "Presentazione"
:page/delete-confirmation "Sei sicuro di voler eliminare questa pagina e i suoi dati?"
:page/open-in-finder "Apri nella cartella"
:page/open-with-default-app "Apri con l'app predefinita"
@@ -343,4 +342,4 @@
:shortcut.category/others "Altri"
:command.editor/copy-embed "Copia un incorporamento di blocco che punta al blocco corrente"
:command.editor/copy-text "Copia le selezioni come testo"
:command.pdf/close "Chiudi anteprima PDF"}
:command.pdf/close "Chiudi anteprima PDF"}

View File

@@ -49,7 +49,6 @@
:left-side-bar/new-page "新規ページ"
:left-side-bar/nav-favorites "お気に入り"
:left-side-bar/nav-recent-pages "最新"
:page/presentation-mode "プレゼンテーション"
:page/delete-confirmation "このページとページのファイルを削除してもよいですか?"
:page/open-in-finder "ディレクトリで開く"
:page/open-with-default-app "デフォルトのアプリで開く"
@@ -362,4 +361,4 @@
:command.editor/strike-through "打ち消し線"
:command.misc/copy "コピー"
:command.ui/goto-plugins "プラグインへ"
:command.ui/select-theme-color "利用可能なテーマ色を選択"}
:command.ui/select-theme-color "利用可能なテーマ色を選択"}

View File

@@ -51,7 +51,6 @@
:left-side-bar/new-page "새 페이지"
:left-side-bar/nav-favorites "즐겨찾기"
:left-side-bar/nav-recent-pages "최근 페이지"
:page/presentation-mode "프레젠테이션 모드"
:page/delete-confirmation "이 페이지와 페이지의 파일들을 삭제하시겠습니까?"
:page/open-in-finder "디렉토리에서 열기"
:page/open-with-default-app "기본 앱으로 열기"
@@ -455,4 +454,4 @@
:command.pdf/find "PDF: 현재 PDF 문서에서 검색"
:command.sidebar/close-top "우축 사이드바의 최상단 항목 닫기"
:command.ui/clear-all-notifications "모든 알람 제거"
:command.ui/install-plugins-from-file "plugins.edn에서 플러그인 설치"}
:command.ui/install-plugins-from-file "plugins.edn에서 플러그인 설치"}

View File

@@ -53,7 +53,6 @@
:left-side-bar/new-page "Ny side"
:left-side-bar/nav-favorites "Favoritter"
:left-side-bar/nav-recent-pages "Nylig"
:page/presentation-mode "Presentasjonsmodus"
:page/delete-confirmation "Er du sikker på at du vil slette denne siden og filen dens?"
:page/open-in-finder "Åpne i mappe"
:page/open-with-default-app "Åpne med forhåndsvalgt app"
@@ -504,7 +503,7 @@
:command.whiteboard/zoom-out "Zoom ut"
:command.whiteboard/zoom-to-fit "Zoom til tegning"
:command.whiteboard/zoom-to-selection "Zoom for å passe seleksjonen"
:home "Hjem"
:importing "Importerer"
:port "Port"
@@ -634,4 +633,4 @@
:window/exit-fullscreen "Gå ut av fullskjerm"
:window/maximize "Maksimer"
:window/minimize "Minimer"
:window/restore "Gjenopprett"}
:window/restore "Gjenopprett"}

View File

@@ -130,7 +130,6 @@
:page/open-backup-directory "Open backups map pagina"
:page/open-in-finder "Open in map"
:page/open-with-default-app "Open met standaard app"
:page/presentation-mode "Presentatiemodus"
:page/show-journals "Toon Journaals"
:page/unfavorite "Pagina uit favorieten verwijderen"
:page/updated-at "Bijgewerkt op"
@@ -341,4 +340,4 @@
:shortcut.category/block-selection "Blokselectie (druk op Esc om selectie te beëindigen)"
:shortcut.category/formatting "Formatteren"
:shortcut.category/navigating "Navigatie"
:shortcut.category/others "Anderen"}
:shortcut.category/others "Anderen"}

View File

@@ -53,7 +53,6 @@
:left-side-bar/new-page "Nowa strona"
:left-side-bar/nav-favorites "Ulubione"
:left-side-bar/nav-recent-pages "Ostatnio odwiedzane"
:page/presentation-mode "Tryb prezentacji"
:page/delete-confirmation "Czy jesteś pewien że chcesz usunąć tę stronę i jej plik?"
:page/open-in-finder "Otwórz w przeglądarce plików"
:page/open-with-default-app "Otwórz w domyślnej aplikacji"
@@ -343,4 +342,4 @@
:command.ui/toggle-wide-mode "Włącz / wyłącz tryb szeroki"
:command.ui/goto-plugins "Przejdź do dashboardu pluginów"
:command.ui/toggle-cards "Pokaż / Ukryj karty"
:command.git/commit "Wykonaj GIT COMMIT z wiadomością"}
:command.git/commit "Wykonaj GIT COMMIT z wiadomością"}

View File

@@ -41,7 +41,6 @@
:right-side-bar/block-ref "Referência de bloco"
:right-side-bar/new-page "Nova página"
:left-side-bar/journals "Diários"
:page/presentation-mode "Modo de apresentação"
:page/delete-confirmation "Tem certeza que quer apagar esta página e o arquivo associado?"
:page/open-in-finder "Abrir em pasta"
:page/open-with-default-app "Abrir com a aplicação por omissão"
@@ -451,7 +450,7 @@
:command.pdf/find "PDF: Pesquisar no documento PDF atual"
:command.sidebar/close-top "Fechar item superior na barra lateral direita"
:command.ui/install-plugins-from-file "Instalar plugins de plugins.edn"
:home "Início"
:toggle-theme "Trocar tema"
:whiteboard "Quadro Branco"
@@ -650,7 +649,7 @@
:plugins "Plugins"
:right-side-bar/flashcards "Flashcards"
:settings-page/enable-flashcards "Flashcards"
:page/backlinks "Backlinks"
:page/backlinks "Backlinks"
:host "Host"
:settings-page/tab-editor "Editor"
:shortcut.category/plugins "Plugins"

View File

@@ -72,7 +72,6 @@
:page/logseq-is-having-a-problem "Logseq está tendo um problema. Para tentar colocá-lo de volta em um estado de funcionamento, por favor tente os seguintes passos seguros em ordem:"
:page/step "Passo {1}"
:page/try "Tentar"
:page/presentation-mode "Modo de apresentação"
:page/delete-confirmation "Tem a certeza de que quer apagar esta página e o respetivo ficheiro?"
:page/open-in-finder "Abrir em pasta"
:page/open-with-default-app "Abrir com a aplicação predefinida"
@@ -455,4 +454,4 @@
:command.graph/export-as-html "Exportar páginas de gráficos públicos como html"
:command.pdf/find "PDF: Pesquisar no documento PDF atual"
:command.sidebar/close-top "Fechar item superior na barra lateral direita"
:command.ui/install-plugins-from-file "Instalar plugins de plugins.edn"}
:command.ui/install-plugins-from-file "Instalar plugins de plugins.edn"}

View File

@@ -86,7 +86,6 @@
:page/logseq-is-having-a-problem "У Logseq возникла проблема. Чтобы попытаться вернуть его в рабочее состояние, пожалуйста, попробуйте выполнить следующие безопасные шаги по порядку:"
:page/step "Шаг {1}"
:page/try "Попробовать"
:page/presentation-mode "Презентация"
:page/delete-confirmation "Вы уверены, что хотите удалить эту страницу и её файл(ы)?"
:page/open-in-finder "Открыть в каталоге"
:page/open-with-default-app "Открыть в приложении по умолчанию"
@@ -267,7 +266,7 @@
:sync-from-local-files "Обновить"
:sync-from-local-files-detail "Импортировать изменения из локальных файлов"
:sync-from-local-changes-detected "При обновлении будут найдены и обработаны файлы, изменённые на диске и отличающиеся от текущего содержимого страниц Logseq. Продолжить?"
:search/publishing "Искать"
:search "Искать или создать страницу"
:whiteboard/link-whiteboard-or-block "Ссылка на доску/страницу/блок"
@@ -339,7 +338,7 @@
:whiteboard/circle "Круг"
:whiteboard/triangle "Треугольник"
:whiteboard/shape "Фигура"
:whiteboard/open-page "Открыть страницу"
:whiteboard/open-page "Открыть страницу"
:whiteboard/open-page-in-sidebar "Открыть страницу на боковой панели"
:whiteboard/remove-link "Удалить ссылку"
:whiteboard/link "Ссылка"
@@ -487,9 +486,9 @@
:file-sync/other-user-graph "Текущий локальный граф привязан к удаленному графу другого пользователя. Поэтому синхронизацию начать нельзя."
:file-sync/graph-deleted "Текущий удаленный граф был удален"
:file-sync/rsapi-cannot-upload-err "Не удалось начать синхронизацию, пожалуйста, проверьте, правильно ли установлено локальное время."
:notification/clear-all "Очистить всё"
:shortcut.category/basics "Базовые"
:shortcut.category/formatting "Форматирование"
:shortcut.category/navigating "Навигация"
@@ -663,4 +662,4 @@
:command.dev/show-block-data "(Dev) Показать данные блока"
:command.dev/show-block-ast "(Dev) Показать AST блока"
:command.dev/show-page-data "(Dev) Показать данные страницы"
:command.dev/show-page-ast "(Dev) Показать AST страницы"}
:command.dev/show-page-ast "(Dev) Показать AST страницы"}

View File

@@ -68,7 +68,6 @@
:left-side-bar/new-whiteboard "Nová tabuľa"
:left-side-bar/nav-favorites "Obľúbené"
:left-side-bar/nav-recent-pages "Posledné"
:page/presentation-mode "Prezentácia"
:page/delete-confirmation "Naozaj chcete odstrániť túto stránku a jej súbor?"
:page/open-in-finder "Otvoriť v adresári"
:page/open-with-default-app "Otvoriť pomocou predvolenej aplikácie"
@@ -443,4 +442,4 @@
:command.ui/install-plugins-from-file "Inštalovať doplnky z plugins.edn"
:command.editor/toggle-open-blocks "Prepnúť otvorené bloky (zbaliť alebo rozbaliť všetky bloky)"
:command.ui/toggle-cards "Zobraziť/Skryť karty"
:command.git/commit "Spusiť príkaz git commit so správou"}
:command.git/commit "Spusiť príkaz git commit so správou"}

View File

@@ -152,7 +152,6 @@
:page/logseq-is-having-a-problem "Logseq'te bir sorun var. Tekrar çalışır duruma getirmek için lütfen aşağıdaki güvenli adımları sırayla deneyin:"
:page/step "{1}. Adım"
:page/try "Deneyin"
:page/presentation-mode "Sunu"
:page/delete-confirmation "Bu sayfayı ve dosyasını silmek istediğinizden emin misiniz?"
:page/open-in-finder "Dizini aç"
:page/open-with-default-app "Varsayılan uygulamayla aç"

View File

@@ -77,7 +77,6 @@
:page/logseq-is-having-a-problem "У Logseq виникла проблема. Щоб спробувати повернути його до робочого стану, виконайте такі безпечні кроки по порядку:"
:page/step "Крок {1}"
:page/try "Спробувати"
:page/presentation-mode "Презентація"
:page/delete-confirmation "Ви впевнені, що хочете видалити цю сторінку та її файл?"
:page/open-in-finder "Відкрити у директорії"
:page/open-with-default-app "Відкрити за допомогою програми за умовчанням"
@@ -520,4 +519,4 @@
:command.dev/show-block-ast "(Dev) Показати блок AST"
:command.dev/show-block-data "(Dev) Показати дані блоку"
:command.dev/show-page-ast "(Dev) Показати сторінку AST"
:command.dev/show-page-data "(Dev) Показати дані сторінки"}
:command.dev/show-page-data "(Dev) Показати дані сторінки"}

View File

@@ -82,7 +82,6 @@
:left-side-bar/nav-recent-pages "最近使用"
:left-side-bar/new-whiteboard "新建白板"
:left-side-bar/create "新建"
:page/presentation-mode "打开幻灯片"
:page/delete-confirmation "您确定要删除此页面和文件吗?"
:page/open-in-finder "打开文件对应目录"
:page/open-with-default-app "用默认应用打开文件"
@@ -462,4 +461,4 @@
:command.editor/backward-kill-word "向前删除一个单词"
:command.editor/open-edit "编辑选中块"
:command.editor/delete-selection "删除选中块"
:command.editor/toggle-open-blocks "切换折叠/展开所有块(非编辑状态)"}
:command.editor/toggle-open-blocks "切换折叠/展开所有块(非编辑状态)"}

View File

@@ -74,7 +74,6 @@
:page/logseq-is-having-a-problem "Logseq 出了些問題。請按照以下安全步驟將其恢復到正常狀態:"
:page/step "步驟 {1}"
:page/try "嘗試"
:page/presentation-mode "簡報模式"
:page/delete-confirmation "你確定想刪除此頁面檔案嗎?"
:page/open-in-finder "開啟資料夾"
:page/open-with-default-app "使用預設應用程式開啟"
@@ -345,4 +344,4 @@
:command.ui/toggle-document-mode "切換文檔模式"
:command.ui/toggle-theme "“在暗色/亮色主題之間切換”"
:command.ui/toggle-right-sidebar "啟用/關閉右側欄"
:command.go/journals "跳轉到日記"}
:command.go/journals "跳轉到日記"}

View File

@@ -1,12 +1,13 @@
(ns frontend.fs.diff-merge-test
(:require [cljs.test :refer [deftest are is]]
[logseq.db :as ldb]
[logseq.graph-parser :as graph-parser]
(:require [cljs-bean.core :as bean]
[cljs.test :refer [are deftest is]]
[frontend.db.conn :as conn]
[frontend.fs.diff-merge :as fs-diff]
[frontend.handler.common.file :as file-common-handler]
[frontend.db.conn :as conn]
[logseq.db :as ldb]
[logseq.graph-parser :as graph-parser]
[logseq.graph-parser.mldoc :as gp-mldoc]
[cljs-bean.core :as bean]))
[logseq.graph-parser.text :as text]))
(defn test-db->diff-blocks
"A hijacked version of db->diff-blocks for testing.
@@ -28,18 +29,18 @@
:ID: 72289d9a-eb2f-427b-ad97-b605a4b8c59b
:END:
#+tItLe: Well parsed!"
[{:body ":PROPERTIES:\n:ID: 72289d9a-eb2f-427b-ad97-b605a4b8c59b\n:END:\n#+tItLe: Well parsed!"
:uuid "72289d9a-eb2f-427b-ad97-b605a4b8c59b"
[{:body ":PROPERTIES:\n:ID: 72289d9a-eb2f-427b-ad97-b605a4b8c59b\n:END:\n#+tItLe: Well parsed!"
:uuid "72289d9a-eb2f-427b-ad97-b605a4b8c59b"
:level 1}]
"#+title: Howdy"
[{:body "#+title: Howdy" :uuid nil :level 1}]
":PROPERTIES:
:fiction: [[aldsjfklsda]]
:END:\n#+title: Howdy"
[{:body ":PROPERTIES:\n:fiction: [[aldsjfklsda]]\n:END:\n#+title: Howdy"
:uuid nil
[{:body ":PROPERTIES:\n:fiction: [[aldsjfklsda]]\n:END:\n#+title: Howdy"
:uuid nil
:level 1}]))
(deftest db<->ast-diff-blocks-test
@@ -68,13 +69,23 @@
{:body "b" :uuid nil :level 2}
{:body "c" :uuid nil :level 3}]
"- a
\t- b
\t\t- c
\t\t multiline
- d"
[{:body "a" :uuid nil :level 1}
{:body "b" :uuid nil :level 2}
{:body "c\nmultiline" :uuid nil :level 3}
{:body "d" :uuid nil :level 1}]
"## hello
\t- world
\t\t- nice
\t\t\t- nice
\t\t\t- bingo
\t\t\t- world"
[{:body "## hello" :uuid nil :level 2}
[{:body "## hello" :uuid nil :level 1}
{:body "world" :uuid nil :level 2}
{:body "nice" :uuid nil :level 3}
{:body "nice" :uuid nil :level 4}
@@ -92,23 +103,97 @@
\t- i
- j"
[{:body "# a" :uuid nil :level 1}
{:body "## b" :uuid nil :level 2}
{:body "### c" :uuid nil :level 3}
{:body "#### d" :uuid nil :level 4}
{:body "### e" :uuid nil :level 3}
{:body "## b" :uuid nil :level 1}
{:body "### c" :uuid nil :level 1}
{:body "#### d" :uuid nil :level 1}
{:body "### e" :uuid nil :level 1}
{:body "f" :uuid nil :level 1}
{:body "g" :uuid nil :level 2}
{:body "h" :uuid nil :level 3}
{:body "i" :uuid nil :level 2}
{:body "j" :uuid nil :level 1}]
"- a\n id:: 63e25526-3612-4fb1-8cf9-f66db1254a58
\t- b
\t\t- c"
[{:body "a\n id:: 63e25526-3612-4fb1-8cf9-f66db1254a58"
[{:body "a\nid:: 63e25526-3612-4fb1-8cf9-f66db1254a58"
:uuid "63e25526-3612-4fb1-8cf9-f66db1254a58" :level 1}
{:body "b" :uuid nil :level 2}
{:body "c" :uuid nil :level 3}]))
{:body "c" :uuid nil :level 3}]
"alias:: ⭐️\nicon:: ⭐️"
[{:body "alias:: ⭐️\nicon:: ⭐️", :level 1, :uuid nil}]))
(defn text->diffblocks-alt
[text]
(-> (gp-mldoc/->edn text (gp-mldoc/default-config :markdown))
(#'fs-diff/ast->diff-blocks-alt text :markdown {:block-pattern "-"})))
(deftest md->ast->diff-blocks-alt-test
(are [text diff-blocks]
(= (text->diffblocks-alt text)
diff-blocks)
"- a
\t- b
\t\t- c"
[{:body "a" :uuid nil :level 1 :meta {:raw-body "- a"}}
{:body "b" :uuid nil :level 2 :meta {:raw-body "\t- b"}}
{:body "c" :uuid nil :level 3 :meta {:raw-body "\t\t- c"}}]
"- a
\t- b
\t\t- c
\t\t multiline
- d"
[{:body "a" :uuid nil :level 1 :meta {:raw-body "- a"}}
{:body "b" :uuid nil :level 2 :meta {:raw-body "\t- b"}}
{:body "c\nmultiline" :uuid nil :level 3 :meta {:raw-body "\t\t- c\n\t\t multiline"}}
{:body "d" :uuid nil :level 1 :meta {:raw-body "- d"}}]
"## hello
\t- world
\t\t- nice
\t\t\t- nice
\t\t\t- bingo
\t\t\t- world"
[{:body "## hello" :uuid nil :level 1 :meta {:raw-body "## hello"}}
{:body "world" :uuid nil :level 2 :meta {:raw-body "\t- world"}}
{:body "nice" :uuid nil :level 3 :meta {:raw-body "\t\t- nice"}}
{:body "nice" :uuid nil :level 4 :meta {:raw-body "\t\t\t- nice"}}
{:body "bingo" :uuid nil :level 4 :meta {:raw-body "\t\t\t- bingo"}}
{:body "world" :uuid nil :level 4 :meta {:raw-body "\t\t\t- world"}}]
"# a
## b
### c
#### d
### e
- f
\t- g
\t\t- h
\t- i
- j"
[{:body "# a" :uuid nil :level 1 :meta {:raw-body "# a"}}
{:body "## b" :uuid nil :level 1 :meta {:raw-body "## b"}}
{:body "### c" :uuid nil :level 1 :meta {:raw-body "### c"}}
{:body "#### d" :uuid nil :level 1 :meta {:raw-body "#### d"}}
{:body "### e" :uuid nil :level 1 :meta {:raw-body "### e"}}
{:body "f" :uuid nil :level 1 :meta {:raw-body "- f"}}
{:body "g" :uuid nil :level 2 :meta {:raw-body "\t- g"}}
{:body "h" :uuid nil :level 3 :meta {:raw-body "\t\t- h"}}
{:body "i" :uuid nil :level 2 :meta {:raw-body "\t- i"}}
{:body "j" :uuid nil :level 1 :meta {:raw-body "- j"}}]
"- a\n id:: 63e25526-3612-4fb1-8cf9-f66db1254a58
\t- b
\t\t- c"
[{:body "a\nid:: 63e25526-3612-4fb1-8cf9-f66db1254a58"
:uuid "63e25526-3612-4fb1-8cf9-f66db1254a58" :level 1 :meta {:raw-body "- a\n id:: 63e25526-3612-4fb1-8cf9-f66db1254a58"}}
{:body "b" :uuid nil :level 2 :meta {:raw-body "\t- b"}}
{:body "c" :uuid nil :level 3 :meta {:raw-body "\t\t- c"}}]
"alias:: ⭐️\nicon:: ⭐️"
[{:body "alias:: ⭐️\nicon:: ⭐️", :meta {:raw-body "alias:: ⭐️\nicon:: ⭐️"}, :level 1, :uuid nil}]))
(deftest diff-test
(are [text1 text2 diffs]
@@ -127,11 +212,14 @@
\t\t\t- nice
\t\t\t- bingo
\t\t\t- world"
[[[-1 {:body "## hello"
:level 2
;; Empty op, because no insertion op before the first base block required
;; See https://github.com/logseq/diff-merge#usage
[[]
[[-1 {:body "## hello"
:level 1
:uuid nil}]
[1 {:body "## Halooooo"
:level 2
:level 1
:uuid nil}]]
[[0 {:body "world"
:level 2
@@ -148,7 +236,7 @@
[[0 {:body "world"
:level 4
:uuid nil}]]]
"## hello
\t- world
\t id:: 63e25526-3612-4fb1-8cf9-abcd12354abc
@@ -162,16 +250,19 @@
\t\t\t- nice
\t\t\t- bingo
\t\t\t- world"
[[[-1 {:body "## hello"
:level 2
;; Empty op, because no insertion op before the first base block required
;; See https://github.com/logseq/diff-merge#usage
[[]
[[-1 {:body "## hello"
:level 1
:uuid nil}]
[1 {:body "## Halooooo"
:level 2
:level 1
:uuid nil}]
[1 {:body "world"
:level 2
:uuid nil}]]
[[-1 {:body "world\n id:: 63e25526-3612-4fb1-8cf9-abcd12354abc"
[[-1 {:body "world\nid:: 63e25526-3612-4fb1-8cf9-abcd12354abc"
:level 2
:uuid "63e25526-3612-4fb1-8cf9-abcd12354abc"}]]
[[0 {:body "nice"
@@ -217,7 +308,7 @@
"bar"
[{:body "ghi\nid:: 11451411-1111-1111-1111-111111111111" :uuid "11451411-1111-1111-1111-111111111111" :level 1}
{:body "jkl\nid:: 63241234-1234-1234-1234-123412341234" :uuid "63241234-1234-1234-1234-123412341234" :level 2}])
{:body "jkl\nid:: 63241234-1234-1234-1234-123412341234" :uuid "63241234-1234-1234-1234-123412341234" :level 2}])
(are [page-name text new-uuids] (= (let [old-blks (test-db->diff-blocks conn page-name)
new-blks (text->diffblocks text)
@@ -254,7 +345,7 @@
[[["Properties" [["TiTlE" "Howdy" []]]] nil]]
"#+title: Howdy"
[{:body "#+title: Howdy", :level 1, :uuid nil}])
(are [ast text diff-blocks]
(= (fs-diff/ast->diff-blocks ast text :org {:block-pattern "-" :user-config {:property-pages/enabled? true}})
diff-blocks)
@@ -332,7 +423,7 @@
foo-new-content
"foo-persist"
(fn [db-uuids] (conj db-uuids nil))
;; Prepend a new line to bar
(gp-mldoc/->edn new-bar-content (gp-mldoc/default-config :markdown))
new-bar-content
@@ -358,3 +449,25 @@
(gp-mldoc/->edn foo-new-content (gp-mldoc/default-config :markdown))
foo-new-content
"foo-error-cap")))
(deftest test-remove-indentation-spaces
(is (= "" (gp-mldoc/remove-indentation-spaces "" 0 false)))
(is (= "" (gp-mldoc/remove-indentation-spaces "" 3 true)))
(is (= "- nice\n happy" (gp-mldoc/remove-indentation-spaces "\t\t\t- nice\n\t\t\t happy" 3 true)))
(is (= "\t\t\t- nice\n happy" (gp-mldoc/remove-indentation-spaces "\t\t\t- nice\n\t\t\t happy" 3 false)))
(is (= "\t\t\t- nice\n\t\t\t happy" (gp-mldoc/remove-indentation-spaces "\t\t\t- nice\n\t\t\t happy" 0 true))))
(deftest test-remove-level-spaces
;; Test when `format` is nil
(is (= "nice\n\t\t\t good" (text/remove-level-spaces "\t\t\t- nice\n\t\t\t good" :markdown "-")))
(is (= "- nice" (text/remove-level-spaces "\t\t\t- nice" :markdown "")))
(is (= "nice" (text/remove-level-spaces "\t\t\t- nice" :markdown "-"))))
(deftest test-three-way-merge
(is (= (fs-diff/three-way-merge
"- a\n id:: 648ab5e6-5e03-4c61-95d4-dd904a0a007f\n- b"
"- a\n id:: 648ab5e6-5e03-4c61-95d4-dd904a0a007f\n aaa:: 111\n- b"
"- c"
:markdown)
"- a\n id:: 648ab5e6-5e03-4c61-95d4-dd904a0a007f\n aaa:: 111\n- c")))

View File

@@ -27,17 +27,19 @@
#{(sync/->FileMetadata 1 2 "3" 4 5 nil nil nil)}
#{(sync/->FileMetadata 1 2 "3" 4 5 nil nil nil)}
#{}
#{(sync/->FileMetadata 1 2 "3" 4 5 nil nil nil)}
#{(sync/->FileMetadata 1 2 "3" 4 5 nil nil nil)}
#{(sync/->FileMetadata 1 22 "3" 4 6 nil nil nil)}
#{(sync/->FileMetadata 1 2 "3" 4 5 nil nil nil)}
#{(sync/->FileMetadata 1 2 "3" 4 5 nil nil nil)}
#{(sync/->FileMetadata 1 22 "3" 4 4 nil nil nil) (sync/->FileMetadata 1 22 "3" 44 5 nil nil nil)}
#{(sync/->FileMetadata 1 22 "3" 4 4 nil nil nil)
(sync/->FileMetadata 1 22 "3" 44 5 nil nil nil)}
#{}
#{(sync/->FileMetadata 1 2 "3" 4 5 nil nil nil)}
#{(sync/->FileMetadata 1 2 "3" 4 4 nil nil nil) (sync/->FileMetadata 1 2 "3" 4 6 nil nil nil)}
#{(sync/->FileMetadata 1 2 "3" 4 4 nil nil nil)
(sync/->FileMetadata 1 2 "3" 4 6 nil nil nil)}
)
)

View File

@@ -400,47 +400,47 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@logseq/rsapi-darwin-arm64@0.0.70":
version "0.0.70"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.70.tgz#9f0214d0d61081d287dee2d75c33b272270c82f1"
integrity sha512-N3wNhAwyoZuXu8O83y69vTzDxolciPpeoMJAmkokXq0+3L8+74lRm9+d/Rn2xzRoXwdPyogvRvG75HpG+vC2Ww==
"@logseq/rsapi-darwin-arm64@0.0.73":
version "0.0.73"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-arm64/-/rsapi-darwin-arm64-0.0.73.tgz#4753f05e2dc70f37a31dfb7440e9b2601acb7696"
integrity sha512-TvFwh3/fnwRAZwourk1UUgptcNN7FqmOcL07F373M2rWhTIOba/u1eBwjW9wNMRcXtgLWacaXzBmC4ENvAKDpg==
"@logseq/rsapi-darwin-x64@0.0.70":
version "0.0.70"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.70.tgz#270940af25f168a463d0e4eee68613aabe84a837"
integrity sha512-ZsvZymdUDMrRM4QYKG8yOBJn8CDpZhWu6CrwHX8FfXyCJfglZT9V4KPt97ortAyyTlnKpr8/flYTd9mOs+eUcg==
"@logseq/rsapi-darwin-x64@0.0.73":
version "0.0.73"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-darwin-x64/-/rsapi-darwin-x64-0.0.73.tgz#44180532e3ccf62a7fe597e385ee85a700b14bea"
integrity sha512-tnOSgQ1qgerwDTnR5v1TMbHnVXVabzZf9i3bxon0y9ItwlIY7j7OW80+1AfNoHu9Fbo/e+3bFg5Muq3/Gm7Yrw==
"@logseq/rsapi-freebsd-x64@0.0.70":
version "0.0.70"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-freebsd-x64/-/rsapi-freebsd-x64-0.0.70.tgz#8785dc753068074d16e7de17115d5c004a1ded4c"
integrity sha512-jkUXBlm+Z4VTJUtqenwTV4THFww2lNnHkfXDyFS4Zghnby2Cg/jDe/eUwVvgUIY9fPDTivkwWwx37SLtgMCIsA==
"@logseq/rsapi-freebsd-x64@0.0.73":
version "0.0.73"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-freebsd-x64/-/rsapi-freebsd-x64-0.0.73.tgz#3ff4f720eb05d9ffd32a5391ddf33034a05f42e0"
integrity sha512-YAjggQHzVCZYhXDybR/37Y5czTQbYDE5A5piwsg09Xt4/m5REFSVKqdeQpnOb2LX7wBGbnPxMhsg6QUV/y/eHA==
"@logseq/rsapi-linux-arm64-gnu@0.0.70":
version "0.0.70"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.70.tgz#5a25ef4cdd758a04a625a7d265674681314d5c7c"
integrity sha512-OXDwjfpT/oKrLEucnVxeIu1hIdAO4B371uA/33qCH8pNVCPNZffSITGfgPKY0dXJ3zT2i5s5+Z06AJMcsjiReg==
"@logseq/rsapi-linux-arm64-gnu@0.0.73":
version "0.0.73"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-arm64-gnu/-/rsapi-linux-arm64-gnu-0.0.73.tgz#1f423e296ca69e6e92a06afbb25f9f2f0e452b69"
integrity sha512-t5W9SBraKYU2iGPzBgUhSzVPtH98RwuE1tLW2MpAJh0QNb2DI4/axbc9nrC1IVc1dqAmTkuL8GGGN80VONisUA==
"@logseq/rsapi-linux-x64-gnu@0.0.70":
version "0.0.70"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.70.tgz#e453448bfadfd195df02f0c3b148b815010b61ea"
integrity sha512-rvCjREn2uHLESR3+UAgoKfkST7ysge9L4m4pol5eABczPB4BNiEGy0xpB3ML3/M/8t9Iaw9LcLdq2en80FM3fA==
"@logseq/rsapi-linux-x64-gnu@0.0.73":
version "0.0.73"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-linux-x64-gnu/-/rsapi-linux-x64-gnu-0.0.73.tgz#d33e621d7ea24089a9b863809e6dfbe4362443d5"
integrity sha512-WidDZv4mnG6Ys90KYLzJl0fwMWj/kEItGHjfR3FoDAVKkvu3mezNDWCsd+I2kMrh1dlIpPqcP+BJ9evI4Gbwkw==
"@logseq/rsapi-win32-x64-msvc@0.0.70":
version "0.0.70"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.70.tgz#c855a9e0aed512ae8c465c55ec698855f888deed"
integrity sha512-wRNBJblaZjX8G1cl7Nvn8b8uMuItqaHkrblyfGzsoEOzALyJIZB95zrJvC2tk8Kc47sriK/KzH16+bW/OBxbOA==
"@logseq/rsapi-win32-x64-msvc@0.0.73":
version "0.0.73"
resolved "https://registry.yarnpkg.com/@logseq/rsapi-win32-x64-msvc/-/rsapi-win32-x64-msvc-0.0.73.tgz#7734187c1b56da6373c947680a65b21551134bec"
integrity sha512-YQTE4ZMtlrbuDVfD/6DWtnsiC2uUZpNDqcy6LIN6Ui98yeZ88ktOsEV/lQJF4+4cAflrzW7Xr8ejl2SWSdX6EQ==
"@logseq/rsapi@0.0.70":
version "0.0.70"
resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.70.tgz#4eca5606318b2ab8c92611dc301cbb722281878c"
integrity sha512-w6eSfCLrewZ/8qE+b/GF8YIdvm+4vDurz/haHAR2qmscsXsZr7XoYOcT2eC2FcHyYYforzAppBvxpK9t7FO2ZA==
"@logseq/rsapi@0.0.73":
version "0.0.73"
resolved "https://registry.yarnpkg.com/@logseq/rsapi/-/rsapi-0.0.73.tgz#b02fc017bb12df3afa0fce60ba13e1b01bbf4342"
integrity sha512-ppQCCzc1pAgqlxkYg2CprcU5RTz01fWqba9lhEVg2FpeF9l8IVVCXhbBIUnWPEFTqkoySiwXpMU8kbkTgvEPIg==
optionalDependencies:
"@logseq/rsapi-darwin-arm64" "0.0.70"
"@logseq/rsapi-darwin-x64" "0.0.70"
"@logseq/rsapi-freebsd-x64" "0.0.70"
"@logseq/rsapi-linux-arm64-gnu" "0.0.70"
"@logseq/rsapi-linux-x64-gnu" "0.0.70"
"@logseq/rsapi-win32-x64-msvc" "0.0.70"
"@logseq/rsapi-darwin-arm64" "0.0.73"
"@logseq/rsapi-darwin-x64" "0.0.73"
"@logseq/rsapi-freebsd-x64" "0.0.73"
"@logseq/rsapi-linux-arm64-gnu" "0.0.73"
"@logseq/rsapi-linux-x64-gnu" "0.0.73"
"@logseq/rsapi-win32-x64-msvc" "0.0.73"
"@malept/cross-spawn-promise@^1.0.0", "@malept/cross-spawn-promise@^1.1.0":
version "1.1.1"

View File

@@ -487,15 +487,15 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@logseq/capacitor-file-sync@0.0.24":
version "0.0.24"
resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.24.tgz#be7b69492b92df9c4e899502c632deebe179746b"
integrity sha512-CBIXEPYVp1ddjyYN+Z2dTQ9gwF0KYwZwlvwnl+zmR0Q3ODXxg75BExh5vAU8khXkSNZjZXgZT/J61/kn9xN11w==
"@logseq/capacitor-file-sync@0.0.30":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@logseq/capacitor-file-sync/-/capacitor-file-sync-0.0.30.tgz#9441ad5689f6139acbc7444530b11e0648a586b3"
integrity sha512-rrk4CdSyS8y1M3WgqkFtdtoP3YWRhuaaQOPtO18roOTztbwdu/w7/+uEt7RDVcV92rwCjhCeg4yaTxbmgWwFYw==
"@logseq/diff-merge@^0.0.2":
version "0.0.2"
resolved "https://registry.yarnpkg.com/@logseq/diff-merge/-/diff-merge-0.0.2.tgz#0bf29a550921311f63754db65ea83b82c54b16c8"
integrity sha512-c6V7rTg/pEoqhByJxRv7yyZ7q3LylKmkiKxoU99R7Fr7Cf5j9dn7GUQW/RlOs68IqYv76BkTHR6EhrLf6cKtZg==
"@logseq/diff-merge@0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@logseq/diff-merge/-/diff-merge-0.1.0.tgz#fca282e3ff7c256a1f447d0463d78fb23ebee1d9"
integrity sha512-VNAJI7Mo/xHEw2LN6rpoWf/BbVfsC1wRpyyLbvm1jQbRxcwRgqYwWkSIVS0t1wswquDS64ZolJkCIFXeNXQbTA==
"@logseq/react-tweet-embed@1.3.1-1":
version "1.3.1-1"
@@ -4667,10 +4667,10 @@ mkdirp@^1.0.3:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
mldoc@^1.5.5:
version "1.5.5"
resolved "https://registry.yarnpkg.com/mldoc/-/mldoc-1.5.5.tgz#2f18439740cbcf474bf7d59266d4d98bbbc89412"
integrity sha512-hBVLgzlh/648l0b0Y2rkQ9KK65EBf4T+IINNFGERpn2MccXwIAiXTCZXuMIe4xfhWQ2C8KHb+k4Wb2Nw5O1TKQ==
mldoc@1.5.7:
version "1.5.7"
resolved "https://registry.yarnpkg.com/mldoc/-/mldoc-1.5.7.tgz#9b316f633a3032ce217a339621b98e70bb229235"
integrity sha512-Ph9y8t195UWtkn0hK/VVNvi/wjZUJCLXAaUGVE80KmaE9Rwp9wWBMSEg4wPgjCac3edMjaONucD52fHOFTU9UA==
dependencies:
yargs "^12.0.2"