Initial import of LogDarioSeq baseline

Establishes version control for the personal Logseq DB fork before
starting the server-client architecture migration and domain features
described in docs/agent-guide and the approved implementation plan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-25 15:32:15 +02:00
commit 40631362b3
2016 changed files with 543898 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
(ns logseq.graph-parser.block-test
(:require [cljs.test :refer [deftest are testing is]]
[datascript.core :as d]
[logseq.common.uuid :as common-uuid]
[logseq.db.test.helper :as db-test]
[logseq.graph-parser.block :as gp-block]
[logseq.graph-parser.mldoc :as gp-mldoc]))
(defn- extract-properties
[properties user-config]
(gp-block/extract-properties
(map
(fn [[k v]]
(let [mldoc-ast (gp-mldoc/get-references v (gp-mldoc/default-config :markdown))]
[k v mldoc-ast]))
properties)
user-config))
(deftest test-fix-duplicate-id
(are [x y]
(let [result (gp-block/fix-duplicate-id (gp-block/block-keywordize x))]
(and (:block/uuid result)
(not= (:uuid x) (:block/uuid result))
(= (select-keys result
[:block/properties :block/title :block/properties-text-values :block/properties-order]) (gp-block/block-keywordize y))))
{:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :markdown, :meta {:start_pos 51, :end_pos 101}, :macros [], :title "bar\nid:: 63f199bc-c737-459f-983d-84acfcda14fe", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
{:properties {},
:title "bar",
:properties-text-values {},
:properties-order []}
{:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :org, :meta {:start_pos 51, :end_pos 101}, :macros [], :title "bar\n:id: 63f199bc-c737-459f-983d-84acfcda14fe", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
{:properties {},
:title "bar",
:properties-text-values {},
:properties-order []}
{:properties {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :tags [], :format :markdown, :meta {:start_pos 51, :end_pos 101}, :macros [], :title "bar\n \n id:: 63f199bc-c737-459f-983d-84acfcda14fe\nblock body", :properties-text-values {:id "63f199bc-c737-459f-983d-84acfcda14fe"}, :level 1, :uuid #uuid "63f199bc-c737-459f-983d-84acfcda14fe", :properties-order [:id]}
{:properties {},
:title "bar\nblock body",
:properties-text-values {},
:properties-order []}))
(deftest test-extract-properties
(are [x y] (= (:properties (extract-properties x {})) y)
;; Built-in properties
[["background-color" "#000000"]] {:background-color "#000000"}
[["alias" "[[name/with space]]"]] {:alias #{"name/with space"}}
[["tags" "[[foo]], [[bar]]"]] {:tags #{"foo" "bar"}}
[["tags" "[[foo]] [[bar]]"]] {:tags #{"foo" "bar"}}
[["tags" "bar"]] {:tags #{"bar"}}
[["file-path" "file:///home/x, y.pdf"]] {:file-path "file:///home/x, y.pdf"}
;; User properties
[["year" "1000"]] {:year 1000}
[["year" "\"1000\""]] {:year "\"1000\""}
[["year" "1000"] ["alias" "[[name/with space]]"]] {:year 1000, :alias #{"name/with space"}}
[["year" "1000"] ["tags" "[[name/with space]]"]] {:year 1000, :tags #{"name/with space"}}
[["year" "1000"] ["tags" "[[name/with space]], [[another]]"]] {:year 1000, :tags #{"name/with space" "another"}}
[["year" "1000"] ["alias" "[[name/with space]], [[another]]"]] {:year 1000, :alias #{"name/with space" "another"}}
[["year" "1000"] ["alias" "[[name/with space]], [[another [[nested]]]]"]] {:year 1000, :alias #{"name/with space" "another [[nested]]"}}
[["year" "1000"] ["alias" "[[name/with space]], [[[[nested]] another]]"]] {:year 1000, :alias #{"name/with space" "[[nested]] another"}}
[["foo" "bar"]] {:foo "bar"}
[["foo" "[[bar]], [[baz]]"]] {:foo #{"bar" "baz"}}
[["foo" "[[bar]], [[baz]]"]] {:foo #{"bar" "baz"}}
[["foo" "[[bar]], [[baz]]"]] {:foo #{"bar" "baz"}}
[["foo" "[[bar]], [[nested [[baz]]]]"]] {:foo #{"bar" "nested [[baz]]"}}
[["foo" "[[bar]], [[nested [[baz]]]]"]] {:foo #{"bar" "nested [[baz]]"}}
[["foo" "[[bar]], [[baz, test]]"]] {:foo #{"bar" "baz, test"}}
[["foo" "[[bar]], [[baz, test, [[nested]]]]"]] {:foo #{"bar" "baz, test, [[nested]]"}})
(testing "page-refs"
(are [x y] (= (vec (:page-refs
(extract-properties x {:property-pages/enabled? true}))) y)
[["year" "1000"]] ["year"]
[["year" "\"1000\""]] ["year"]
[["year" "1000"] ["month" "12"]] ["year" "month"]
[["foo" "[[bar]] test"]] ["bar" "foo"]
[["foo" "[[bar]] test [[baz]]"]] ["bar" "baz" "foo"]
[["foo" "[[bar]] test [[baz]] [[nested [[baz]]]]"]] ["bar" "baz" "nested [[baz]]" "foo"]
[["foo" "#bar, #baz"]] ["bar" "baz" "foo"]
[["foo" "[[nested [[page]]]], test"]] ["nested [[page]]" "foo"])
(are [x y] (= (vec (:page-refs
(extract-properties x {:property-pages/enabled? false}))) y)
[["year" "1000"]] []
[["year" "1000"] ["month" "12"]] []
[["foo" "[[bar]] test"]] ["bar"])
(is (= ["year"]
(:page-refs
(extract-properties [["year" "1000"] ["month" "12"]]
{:property-pages/enabled? true
:property-pages/excludelist #{:month :day}})))
":property-pages/exclude-list excludes specified properties")
(is (= ["year"]
(:page-refs
(extract-properties [["year" "1000"]]
{})))
"Default to enabled when :property-pages/enabled? is not in config")
(is (= ["foo" "bar" "tags"]
(:page-refs
(extract-properties
;; tags is linkable and background-color is not
[["tags" "[[foo]], [[bar]]"] ["background-color" "#008000"]]
{:property-pages/enabled? true})))
"Only editable linkable built-in properties have page-refs in property values")))
(deftest test-page-name-map-namespace-for-slash-journals
(testing "slash-formatted journals do not keep namespace metadata"
(let [journal (gp-block/page-name->map "2026/05/18" nil false "yyyy/MM/dd")]
(is (= 20260518 (:block/journal-day journal)))
(is (= "2026/05/18" (:block/title journal)))
(is (= "may 18th, 2026" (:block/name journal)))
(is (= (common-uuid/gen-uuid :journal-page-uuid 20260518)
(:block/uuid journal)))
(is (nil? (:block/namespace journal)))))
(testing "non-journal slash pages keep namespace metadata"
(is (= {:block/name "project"}
(:block/namespace (gp-block/page-name->map "project/child" nil false "yyyy/MM/dd"))))))
(deftest existing-journal-reference-reuses-stored-identity-test
(testing "a legacy journal name is not rewritten while parsing a reference"
(let [conn (db-test/create-conn-with-blocks
{:pages-and-blocks [{:page {:build/journal 20260727}}]})
journal (db-test/find-journal-by-journal-day @conn 20260727)
journal-uuid (:block/uuid journal)]
(d/transact! conn [[:db/add :logseq.class/Journal
:logseq.property.journal/title-format "yyyy-MM-dd"]
{:db/id (:db/id journal)
:block/title "2026-07-27"
:block/name "2026-07-27"}])
(let [reference (gp-block/page-name->map "2026-07-27" @conn false "yyyy-MM-dd")]
(is (= {:block/uuid journal-uuid
:block/title "2026-07-27"
:block/name "2026-07-27"
:block/journal-day 20260727}
(select-keys reference
[:block/uuid :block/title :block/name :block/journal-day]))))))
(testing "an existing journal is found by day after the configured format changes"
(let [conn (db-test/create-conn-with-blocks
{:pages-and-blocks [{:page {:build/journal 20260727}}]})
journal (db-test/find-journal-by-journal-day @conn 20260727)
journal-uuid (:block/uuid journal)]
(d/transact! conn [[:db/add :logseq.class/Journal
:logseq.property.journal/title-format "yyyy-MM-dd"]
{:db/id (:db/id journal)
:block/title "2026-07-27"
:block/name "2026-07-27"}])
(d/transact! conn [[:db/add :logseq.class/Journal
:logseq.property.journal/title-format "dd/MM/yyyy"]])
(let [reference (gp-block/page-name->map "27/07/2026" @conn false "dd/MM/yyyy")]
(is (= {:block/uuid journal-uuid
:block/title "2026-07-27"
:block/name "2026-07-27"
:block/journal-day 20260727}
(select-keys reference
[:block/uuid :block/title :block/name :block/journal-day])))))))
(defn find-block-for-content
[db content]
(->> (d/q '[:find (pull ?b [* {:block/refs [:block/uuid]}])
:in $ ?content
:where [?b :block/title ?content]]
db
content)
(map first)
first))

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
(ns logseq.graph-parser.extract-test
(:require [cljs.test :refer [deftest is are]]
[datascript.core :as d]
[logseq.graph-parser.extract :as extract]))
;; This is a copy of frontend.components.repo/multiplatform-reserved-chars for reserved chars testing
(def multiplatform-reserved-chars ":\\*\\?\"<>|\\#\\\\")
;; Stuffs should be parsable (don't crash) when users dump some random files
(deftest page-name-parsing-tests
(is (string? (#'extract/tri-lb-title-parsing "___-_-_-_---___----")))
(is (string? (#'extract/tri-lb-title-parsing "_____///____---___----")))
(is (string? (#'extract/tri-lb-title-parsing "/_/////---/_----")))
(is (string? (#'extract/tri-lb-title-parsing "/\\#*%lasdf\\//__--dsll_____----....-._0x2B")))
(is (string? (#'extract/tri-lb-title-parsing "/\\#*%l;;&&;&\\//__--dsll_____----....-._0x2B")))
(is (string? (#'extract/tri-lb-title-parsing multiplatform-reserved-chars)))
(is (string? (#'extract/tri-lb-title-parsing "dsa&amp&semi;l dsalfjk jkl"))))
(deftest uri-decoding-tests
(is (= (#'extract/safe-url-decode "%*-sd%%%saf%=lks") "%*-sd%%%saf%=lks")) ;; Contains %, but invalid
(is (= (#'extract/safe-url-decode "%2FDownloads%2FCNN%3AIs%5CAll%3AYou%20Need.pdf") "/Downloads/CNN:Is\\All:You Need.pdf"))
(is (= (#'extract/safe-url-decode "asldkflksdaf啦放假啦睡觉啦啊啥的都撒娇浪费;dla") "asldkflksdaf啦放假啦睡觉啦啊啥的都撒娇浪费;dla")))
(deftest page-name-sanitization-backward-tests
(is (= "abc.def.ghi.jkl" (#'extract/tri-lb-title-parsing "abc.def.ghi.jkl")))
(is (= "abc/def/ghi/jkl" (#'extract/tri-lb-title-parsing "abc%2Fdef%2Fghi%2Fjkl")))
(is (= "abc%/def/ghi/jkl" (#'extract/tri-lb-title-parsing "abc%25%2Fdef%2Fghi%2Fjkl")))
(is (= "abc%2——ef/ghi/jkl" (#'extract/tri-lb-title-parsing "abc%2——ef%2Fghi%2Fjkl")))
(is (= "abc&amp;2Fghi/jkl" (#'extract/tri-lb-title-parsing "abc&amp;2Fghi%2Fjkl")))
(is (= "abc&lt;2Fghi/jkl" (#'extract/tri-lb-title-parsing "abc&lt;2Fghi%2Fjkl")))
(is (= "abc&percnt;2Fghi/jkl" (#'extract/tri-lb-title-parsing "abc&percnt;2Fghi%2Fjkl")))
(is (= "abc&semi;&;2Fghi/jkl" (#'extract/tri-lb-title-parsing "abc&semi;&;2Fghi%2Fjkl")))
;; happens when importing some compatible files on *nix / macOS
(is (= multiplatform-reserved-chars (#'extract/tri-lb-title-parsing multiplatform-reserved-chars))))
(deftest path-utils-tests
(is (= "asldk lakls " (#'extract/path->file-body "/data/app/asldk lakls .lsad")))
(is (= "asldk lakls " (#'extract/path->file-body "asldk lakls .lsad")))
(is (= "asldk lakls" (#'extract/path->file-body "asldk lakls")))
(is (= "asldk lakls" (#'extract/path->file-body "/data/app/asldk lakls")))
(is (= "asldk lakls" (#'extract/path->file-body "file://data/app/asldk lakls.as")))
(is (= "中文asldk lakls" (#'extract/path->file-body "file://中文data/app/中文asldk lakls.as"))))
;; Bare minimum schema to test extract
(def file-schema
{:block/uuid {:db/unique :db.unique/identity}
:block/name {:db/unique :db.unique/identity}})
(defn- extract [file content & [options]]
(extract/extract file
content
(merge {:block-pattern "-" :db (d/empty-db file-schema)
:verbose false}
options)))
(defn- extract-block-content
[text]
(let [{:keys [blocks]} (extract "a.md" text)]
(mapv :block/title blocks)))
(defn- extract-title [file text]
(-> (extract file text) :pages first :block/properties :title))
(deftest extract-blocks-for-headings
(is (= ["a" "b" "c"]
(extract-block-content
"- a
- b
- c")))
(is (= ["## hello" "world" "nice" "nice" "bingo" "world"]
(extract-block-content "## hello
- world
- nice
- nice
- bingo
- world")))
(is (= ["# a" "## b" "### c" "#### d" "### e" "f" "g" "h" "i" "j"]
(extract-block-content "# a
## b
### c
#### d
### e
- f
- g
- h
- i
- j"))))
(deftest parse-page-title
(is (= nil
(extract-title "foo.org" "")))
(is (= "Howdy"
(extract-title "foo.org" "#+title: Howdy")))
(is (= "Howdy"
(extract-title "foo.org" "#+TITLE: Howdy")))
(is (= "Howdy"
(extract-title "foo.org" "#+TiTlE: Howdy")))
(is (= "diagram/abcdef"
(extract-title "foo.org" ":PROPERTIES:
:ID: 72289d9a-eb2f-427b-ad97-b605a4b8c59b
:END:
#+TITLE: diagram/abcdef")))
(is (= "diagram/abcdef"
(extract-title "foo.org" ":PROPERTIES:
:ID: 72289d9a-eb2f-427b-ad97-b605a4b8c59b
:END:
#+title: diagram/abcdef"))))
(deftest extract-blocks-with-property-pages-config
(are [extract-args expected-refs]
(= expected-refs
(->> (apply extract extract-args)
:blocks
(mapcat #(->> % :block/refs (map :block/name)))
set))
["a.md" "foo:: #bar\nbaz:: #bing" {:user-config {:property-pages/enabled? true}}]
#{"bar" "bing" "foo" "baz"}
["a.md" "foo:: #bar\nbaz:: #bing" {:user-config {:property-pages/enabled? false}}]
#{"bar" "bing"}))
(deftest test-regression-1902
(is (= ["line1" "line2" "line3" "line4"]
(extract-block-content
"- line1
- line2
- line3
- line4"))))

View File

@@ -0,0 +1,150 @@
(ns logseq.graph-parser.mldoc-test
(:require [cljs.test :refer [testing deftest are is]]
[logseq.graph-parser.mldoc :as gp-mldoc]
[logseq.graph-parser.text :as text]))
(def md-config (gp-mldoc/default-config :markdown))
(deftest src-test
(is (= [["Src"
{:lines [": hello" "\n"],
:pos_meta {:start_pos 4, :end_pos 12},
:full_content "```\n: hello\n```"}]
{:start_pos 0, :end_pos 15}]
(first (gp-mldoc/->edn "```
: hello
```" md-config)))
"Basic src example")
(is (= [["Src"
{:lines [" hello" "\n" " world" "\n"],
:pos_meta {:start_pos 7, :end_pos 25},
:full_content "```\nhello\nworld\n```"}]
{:start_pos 1, :end_pos 29}]
(second (gp-mldoc/->edn "
```
hello
world
```
" md-config)))
"Src example with leading whitespace"))
(defn- get-properties
[x]
(->> (gp-mldoc/->edn x md-config)
ffirst second
(map (fn [[k v ast]]
[(keyword k) (text/parse-property k v ast {})]))
(into {})))
(deftest md-properties-test
(are [x y] (= y (get-properties x))
;; reference values
"property:: [[foo]], [[bar]]"
{:property #{"foo" "bar"}}
;; comma separated
"tags:: foo, bar, foo"
{:tags #{"foo" "bar"}}))
(deftest name-definition-test
(is (= [["List"
[{:content [["Paragraph" [["Plain" "definition"]]]],
:items [],
:name [["Plain" "term"]],
:indent 0,
:ordered false}]]
{:start_pos 0, :end_pos 17}]
(first (gp-mldoc/->edn "term
: definition" md-config)))))
(deftest macro-with-script-markup-test
(testing "inline macros can contain superscript and subscript markup"
(are [content ast] (= ast (gp-mldoc/inline->edn content md-config))
"{{cloze Ca^{ +2} ions}}"
[["Macro" {:name "cloze" :arguments ["Ca^{ +2} ions"]}]]
"{{cloze H_{2}O}}"
[["Macro" {:name "cloze" :arguments ["H_{2}O"]}]]
"{{cloze Ca^{+2}}}"
[["Macro" {:name "cloze" :arguments ["Ca^{+2}"]}]]
"{{foo Ca^{ +2} ions, [[a, b]], \"c, d\"}}"
[["Macro" {:name "foo" :arguments ["Ca^{ +2} ions" "[[a, b]]" "\"c, d\""]}]]
;; page ref inside a macro that also has script markup — exercises
;; the Nested_link case in inline-ast->source
"{{cloze Ca^{ +2} [[water]]}}"
[["Macro" {:name "cloze" :arguments ["Ca^{ +2} [[water]]"]}]]))
(testing "normal macros without script markup are not modified"
(are [content ast] (= ast (gp-mldoc/inline->edn content md-config))
"{{cloze simple text}}"
[["Macro" {:name "cloze" :arguments ["simple text"]}]]
"{{foo a, b, c}}"
[["Macro" {:name "foo" :arguments ["a" "b" "c"]}]]
"{{cloze [[page name]]}}"
[["Macro" {:name "cloze" :arguments ["[[page name]]"]}]]))
(testing "block parsing keeps the issue reproduction as macro nodes"
(is (= [["Plain" "This is usually highlighted by the accumulation of the "]
["Macro" {:name "cloze" :arguments ["Ca^{ +2} ions"]}]
["Plain" " . This will be seen as "]
["Macro" {:name "cloze" :arguments ["<ins>large flocculent amorphous densities in TEM</ins>"]}]]
(-> (gp-mldoc/->edn
"- This is usually highlighted by the accumulation of the {{cloze Ca^{ +2} ions}} . This will be seen as {{cloze <ins>large flocculent amorphous densities in TEM</ins>}}"
md-config)
ffirst
second
:title)))
(is (= [["Plain" "Water formula is "]
["Macro" {:name "cloze" :arguments ["H_{2}O"]}]]
(-> (gp-mldoc/->edn
"- Water formula is {{cloze H_{2}O}}"
md-config)
ffirst
second
:title)))))
(defn- parse-properties
[text]
(->> (gp-mldoc/->edn text (gp-mldoc/default-config :org))
(filter #(= "Properties" (ffirst %)))
ffirst
second))
(deftest org-properties-test
(testing "just title"
(let [content "#+TITLE: some title "
props (parse-properties content)]
(is (= "some title " (second (first props))))))
(testing "filetags"
(let [content "#+FILETAGS: :tag1:tag2:@tag:
#+TAGS: tag3
body"
props (parse-properties content)]
(is ["@tag" "tag1" "tag2"] (sort (:filetags props)))
(is ["@tag" "tag1" "tag2" "tag3"] (sort (:tags props))))))
(deftest remove-indentation-spaces
(testing "Remove indentations for every line"
(is (= "block 1.1\n line 1\n line 2\nline 3\nline 4"
(let [s "block 1.1
line 1
line 2
line 3
line 4"]
(gp-mldoc/remove-indentation-spaces s 2 false))))
(is (= "\t- block 1.1\n line 1\n line 2\nline 3\nline 4"
(let [s "\t- block 1.1
\t line 1
\t line 2
\t line 3
\tline 4"]
(gp-mldoc/remove-indentation-spaces s 3 false))))))

View File

@@ -0,0 +1,62 @@
(ns logseq.graph-parser.property-test
(:require [cljs.test :refer [are deftest testing]]
[logseq.graph-parser.property :as gp-property]))
(def test-db "test-db")
(deftest test->new-properties
(are [x y] (= (gp-property/->new-properties x) y)
":PROPERTIES:\n:foo: bar\n:END:"
"foo:: bar"
"hello\n:PROPERTIES:\n:foo: bar\n:END:"
"hello\nfoo:: bar"
"hello\n:PROPERTIES:\n:foo: bar\n:nice: bingo\n:END:"
"hello\nfoo:: bar\nnice:: bingo"
"hello\n:PROPERTIES:\n:foo: bar\n:nice: bingo\n:END:"
"hello\nfoo:: bar\nnice:: bingo"
"hello\n:PROPERTIES:\n:foo: bar\n:nice: bingo\n:END:\nnice"
"hello\nfoo:: bar\nnice:: bingo\nnice"
"hello\n:PROPERTIES:\n:foo: bar\n:nice:\n:END:\nnice"
"hello\nfoo:: bar\nnice:: \nnice"
"hello\n:PROPERTIES:\n:foo: bar\n:nice\n:END:\nnice"
"hello\nfoo:: bar\n:nice\nnice"))
(deftest test-remove-properties
(testing "properties with non-blank lines"
(are [x y] (= x y)
(gp-property/remove-properties :org "** hello\n:PROPERTIES:\n:x: y\n:END:\n")
"** hello"
(gp-property/remove-properties :org "** hello\n:PROPERTIES:\n:x: y\na:b\n:END:\n")
"** hello"
(gp-property/remove-properties :markdown "** hello\nx:: y\na:: b\n")
"** hello"
(gp-property/remove-properties :markdown "** hello\nx:: y\na::b\n")
"** hello"))
(testing "properties with blank lines"
(are [x y] (= x y)
(gp-property/remove-properties :org "** hello\n:PROPERTIES:\n\n:x: y\n:END:\n")
"** hello"
(gp-property/remove-properties :org "** hello\n:PROPERTIES:\n:x: y\n\na:b\n:END:\n")
"** hello"))
(testing "invalid-properties"
(are [x y] (= x y)
(gp-property/remove-properties :markdown "hello\nnice\nfoo:: bar")
"hello\nnice\nfoo:: bar"
(gp-property/remove-properties :markdown "hello\nnice\nfoo:: bar\ntest")
"hello\nnice\nfoo:: bar\ntest"
(gp-property/remove-properties :markdown "** hello\nx:: y\n\na:: b\n")
"** hello\n\na:: b")))

View File

@@ -0,0 +1,20 @@
(ns logseq.graph-parser.test.docs-graph-helper
"Helper fns for setting up and running tests against docs graph"
(:require ["child_process" :as child-process]
["fs" :as fs]))
;; Helper fns for test setup
;; =========================
(defn- sh
"Run shell cmd synchronously and print to inherited streams by default. Aims
to be similar to babashka.tasks/shell"
[cmd opts]
(child-process/spawnSync (first cmd)
(clj->js (rest cmd))
(clj->js (merge {:stdio "inherit"} opts))))
(defn clone-docs-repo-if-not-exists
[dir branch]
(when-not (.existsSync fs dir)
(sh ["git" "clone" "--depth" "1" "-b" branch "-c" "advice.detachedHead=false"
"https://github.com/logseq/docs" dir] {})))

View File

@@ -0,0 +1,25 @@
(ns logseq.graph-parser.test.helper)
;; Copied from https://github.com/babashka/nbb/blob/e5d84b0fac59774f5d7a4a9e807240cce04bf252/test/nbb/test_macros.clj
(defmacro deftest-async
"A wrapper around deftest that handles async and done in all cases.
Importantly, it prevents unexpected failures in an async test from abruptly
ending a test suite"
[name opts & body]
(let [[opts body]
(if (map? opts)
[opts body]
[nil (cons opts body)])]
`(cljs.test/deftest ~name
~@(when-let [pre (:before opts)]
[pre])
(cljs.test/async
~'done
(-> (do ~@body)
(.catch (fn [err#]
(cljs.test/is (= 1 0) (str err# (.-stack err#)))))
(.finally
(fn []
~@(when-let [post (:after opts)]
[post])
(~'done))))))))

View File

@@ -0,0 +1,6 @@
(ns logseq.graph-parser.test-runner
"Test runner which enables https://github.com/PEZ/baldr by default"
(:require [nextjournal.test-runner :as next-runner]
[pez.baldr]))
(def -main next-runner/-main)

View File

@@ -0,0 +1,117 @@
(ns logseq.graph-parser.text-test
(:require [cljs.test :refer [are deftest testing]]
[logseq.graph-parser.text :as text]
[logseq.graph-parser.mldoc :as gp-mldoc]))
(deftest test-get-page-name
(are [x y] (= (text/get-page-name x) y)
"[[page]]" "page"
"[[another page]]" "another page"
"[single bracket]" nil
"no brackets" nil
"[[another page]]" "another page"
"[[nested [[page]]]]" "nested [[page]]"
"[[file:./page.org][page]]" "page"
"[[file:./pages/page.org][page]]" "page"
"[[file:./namespace.page.org][namespace/page]]" "namespace/page"
"[[file:./pages/namespace.page.org][namespace/page]]" "namespace/page"
"[[file:./pages/namespace.page.org][please don't change me]]" "namespace/page"
"[page](file:./page.md)" "page"
"[page](file:.pages/page.md)" "page"
"[logseq/page](file:./logseq.page.md)" "logseq/page"
"[logseq/page](file:./pages/logseq.page.md)" "logseq/page"))
(deftest page-ref-un-brackets!
(are [x y] (= (text/page-ref-un-brackets! x) y)
"[[page]]" "page"
"[[another page]]" "another page"
"[[nested [[page]]]]" "nested [[page]]"
"[single bracket]" "[single bracket]"
"no brackets" "no brackets"))
(def block-patterns
{:markdown "-"
:org "*"})
(deftest remove-level-spaces
(testing "markdown"
(are [x y] (= (text/remove-level-spaces x :markdown (block-patterns :markdown) true) y)
"- foobar" "foobar"
" - foobar" "foobar"))
(testing "markdown without spaces between the `#` and title"
(are [x y] (= (text/remove-level-spaces x :markdown (block-patterns :markdown)) y)
"-foobar" "foobar"))
(testing "org"
(are [x y] (= (text/remove-level-spaces x :org (block-patterns :org) true) y)
"* foobar" "foobar"
"** foobar" "foobar"
"********************* foobar" "foobar"))
(testing "org without spaces between the `#` and title"
(are [x y] (= (text/remove-level-spaces x :org (block-patterns :org)) y)
"*foobar" "foobar"
"**foobar" "foobar"
"*********************foobar" "foobar")))
(defn- parse-property
[k v user-config]
(let [references (gp-mldoc/get-references v (gp-mldoc/default-config :markdown))]
(text/parse-property k v references user-config)))
(deftest test-parse-property
(testing "for default comma separated properties"
(are [k v y] (= (parse-property k v {}) y)
:tags "foo" #{"foo"}
:tags "comma, separated" #{"comma" "separated"}
:alias "one, two, one" #{"one" "two"}))
(testing "for user comma separated properties"
(are [k v y] (= (parse-property k v {:property/separated-by-commas #{:comma-prop}}) y)
:comma-prop "foo" #{"foo"}
:comma-prop "comma, separated" #{"comma" "separated"}
:comma-prop "one, two, one" #{"one" "two"}))
(testing "for user comma separated properties with mixed values"
(are [k v y] (= (parse-property k v {:property/separated-by-commas #{:comma-prop}}) y)
:comma-prop "foo, #bar" #{"foo", "bar"}
:comma-prop "comma, separated, [[page ref]], [[nested [[page]]]], #[[nested [[tag]]]], end" #{"page ref" "nested [[page]]" "nested [[tag]]" "comma" "separated" "end"}))
(testing "for normal properties"
(are [k v y] (= (parse-property k v {}) y)
:normal "[[foo]] [[bar]]" #{"foo" "bar"}
:normal "[[foo]], [[bar]]" #{"foo" "bar"}
:normal "[[foo]]" #{"foo"}
:normal "[[foo]], [[bar]], #baz" #{"foo" "bar" "baz"}
:normal "[[foo [[bar]]]]" #{"foo [[bar]]"}
:normal "[[foo [[bar]]]], [[baz]]" #{"baz" "foo [[bar]]"}
:title "comma, is ok" "comma, is ok"))
(testing "for tags in properties with punctuation"
(are [k v y] (= (parse-property k v {}) y)
:prop "#foo, #bar. #baz!" #{"foo" "bar" "baz"}
:prop "#foo: '#bar'" #{"foo" "bar"}))
(testing "parse-property with quoted strings"
(are [k v y] (= (parse-property k v {}) y)
:tags "\"foo, bar\"" "\"foo, bar\""
:tags "\"[[foo]], [[bar]]\"" "\"[[foo]], [[bar]]\""))
(testing "parse title property with square bracket"
(are [k v y] (= (parse-property k v {}) y)
:title "[[Jan 11th, 2022]] 21:26" "[[Jan 11th, 2022]] 21:26"
:title "[[[[aldsfkd]] a.b/c.d]]" "[[[[aldsfkd]] a.b/c.d]]"))
(testing "built-in properties parse as expected"
(are [k v y] (= (parse-property k v {}) y)
:id "62e98716-9c0b-4253-83e7-7f8e8a23fe19" "62e98716-9c0b-4253-83e7-7f8e8a23fe19"
:filters "{\"product process\" true}" "{\"product process\" true}"
:collapsed "false" false
:created-at "1609233702047" 1609233702047
:background-color "#533e7d" "#533e7d")))
#_(cljs.test/test-ns 'logseq.graph-parser.text-test)