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,113 @@
(ns logseq.tasks.db-graph.create-graph-with-clojure-irc-history-test
(:require ["fs" :as fs]
["os" :as node-os]
["path" :as node-path]
[cljs.test :refer [deftest is testing]]
[logseq.tasks.db-graph.create-graph-with-clojure-irc-history :as sut]))
(deftest extract-day-paths-returns-sorted-unique-day-pages
(let [index-html (str "<a href=\"2008/2008-02-03.html\">3</a>"
"<a href=\"2008/2008-02-01.html\">1</a>"
"<a href=\"index.html\">home</a>"
"<a href=\"2008/2008-02-01.html\">1</a>")]
(is (= ["2008/2008-02-01.html" "2008/2008-02-03.html"]
(sut/extract-day-paths index-html)))))
(deftest extract-chat-rows-parses-time-nick-and-message
(let [day-html (str "<tr id=\"t1245A\"><td><a href=\"#t1245A\">12:45</a></td>"
"<td class=\"n2\">otwieracz</td>"
"<td>Hello &quot;there&quot; &amp; <a href=\"https://example.com\">https://example.com</a></td></tr>"
"<tr id=\"t1249A\" class=\"h\"><td><a href=\"#t1249A\">12:49</a></td>"
"<td class=\"n6\">lxsameer</td>"
"<td>otwieracz: selmer</td></tr>")]
(is (= [{:time "12:45"
:nick "otwieracz"
:message "Hello \"there\" & https://example.com"}
{:time "12:49"
:nick "lxsameer"
:message "otwieracz: selmer"}]
(sut/extract-chat-rows day-html)))))
(deftest select-day-paths-downloads-all-by-default
(let [paths ["2008/2008-02-01.html"
"2008/2008-02-02.html"
"2008/2008-02-03.html"
"2008/2008-02-04.html"]]
(is (= paths
(sut/select-day-paths paths {})))
(is (= ["2008/2008-02-01.html" "2008/2008-02-02.html"]
(sut/select-day-paths paths {:limit-days 2})))))
(deftest build-page-and-blocks-uses-journal-page-and-chat-timestamps
(testing "Each chat block stores created-by-ref and timestamp derived from date/time"
(let [chouser-uuid #uuid "11111111-1111-1111-1111-111111111111"
rhickey-uuid #uuid "22222222-2222-2222-2222-222222222222"
page (sut/build-page-and-blocks {:date "2008-02-01"
:day-path "2008/2008-02-01.html"
:base-url "https://chouser.us/clojure-log/"
:user->uuid {"Chouser" chouser-uuid
"rhickey" rhickey-uuid}
:chat-rows [{:time "20:46"
:nick "Chouser"
:message "Hi"}
{:time "20:47"
:nick "rhickey"
:message "hello"}]})]
(is (= 20080201
(get-in page [:page :build/journal])))
(is (= "20:46 Chouser: Hi"
(get-in page [:blocks 0 :block/title])))
(is (= "20:47 rhickey: hello"
(get-in page [:blocks 1 :block/title])))
(is (= [:block/uuid chouser-uuid]
(get-in page [:blocks 0 :build/properties :logseq.property/created-by-ref])))
(is (= [:block/uuid rhickey-uuid]
(get-in page [:blocks 1 :build/properties :logseq.property/created-by-ref])))
(is (= (sut/date-time->timestamp-ms "2008-02-01" "20:46")
(get-in page [:blocks 0 :block/created-at])))
(is (= (sut/date-time->timestamp-ms "2008-02-01" "20:47")
(get-in page [:blocks 1 :block/created-at])))
(is (= (sut/date-time->timestamp-ms "2008-02-01" "20:46")
(get-in page [:blocks 0 :block/updated-at])))
(is (= (sut/date-time->timestamp-ms "2008-02-01" "20:47")
(get-in page [:blocks 1 :block/updated-at]))))))
(deftest build-user-pages-creates-user-page-entities
(let [chouser-uuid #uuid "11111111-1111-1111-1111-111111111111"
rhickey-uuid #uuid "22222222-2222-2222-2222-222222222222"
pages (sut/build-user-pages {"Chouser" chouser-uuid
"rhickey" rhickey-uuid})
pages-by-title (into {} (map (fn [{:keys [page]}] [(:block/title page) page])) pages)]
(is (= #{"Chouser" "rhickey"} (set (keys pages-by-title))))
(is (= chouser-uuid (get-in pages-by-title ["Chouser" :block/uuid])))
(is (= "Chouser" (get-in pages-by-title ["Chouser" :build/properties :logseq.property.user/name])))
(is (= rhickey-uuid (get-in pages-by-title ["rhickey" :block/uuid])))
(is (= "rhickey" (get-in pages-by-title ["rhickey" :build/properties :logseq.property.user/name])))))
(deftest build-page-and-blocks-handles-empty-chat-day
(let [page (sut/build-page-and-blocks {:date "2008-02-01"
:day-path "2008/2008-02-01.html"
:base-url "https://chouser.us/clojure-log/"
:user->uuid {}
:chat-rows []})]
(is (= 20080201
(get-in page [:page :build/journal])))
(is (= []
(:blocks page)))))
(deftest resolve-source-dir-supports-root-and-direct-clojure-log-path
(let [tmp-root (str (fs/mkdtempSync (node-path/join (node-os/tmpdir) "clj-log-test-")))
repo-root (node-path/join tmp-root "chouser.github.io-master")
clojure-log-dir (node-path/join repo-root "clojure-log")
index-html "<html></html>"]
(try
(fs/mkdirSync clojure-log-dir #js {:recursive true})
(fs/writeFileSync (node-path/join clojure-log-dir "index.html") index-html)
(is (= clojure-log-dir
(sut/resolve-source-dir clojure-log-dir)))
(is (= clojure-log-dir
(sut/resolve-source-dir repo-root)))
(is (= clojure-log-dir
(sut/resolve-source-dir tmp-root)))
(finally
(fs/rmSync tmp-root #js {:recursive true :force true})))))

View File

@@ -0,0 +1,69 @@
(ns logseq.tasks.db-graph.create-graph-with-large-sizes-test
(:require [cljs.test :refer [deftest is testing]]
[logseq.tasks.db-graph.create-graph-with-large-sizes :as sut]))
(deftest build-page-and-blocks-batch-builds-the-requested-graph-slice
(let [id-seq (map #(str "id-" %) (range))
next-id (let [ids (atom id-seq)]
(fn []
(let [id (first @ids)]
(swap! ids rest)
id)))
batch (#'sut/build-page-and-blocks-batch 10 2 3 next-id)]
(is (= 2 (count batch)))
(is (= ["Page-10" "Page-11"]
(map (comp :block/title :page) batch)))
(is (= ["id-0" "id-4"]
(map (comp :block/uuid :page) batch)))
(is (= [[(#'sut/build-block-title 10 0) (#'sut/build-block-title 10 1) (#'sut/build-block-title 10 2)]
[(#'sut/build-block-title 11 0) (#'sut/build-block-title 11 1) (#'sut/build-block-title 11 2)]]
(map (fn [{:keys [blocks]}]
(mapv :block/title blocks))
batch)))
(is (= [["id-1" "id-2" "id-3"]
["id-5" "id-6" "id-7"]]
(map (fn [{:keys [blocks]}]
(mapv :block/uuid blocks))
batch)))))
(deftest page-and-block-batches-only-realize-requested-batches
(let [calls (atom 0)
next-id (fn []
(swap! calls inc)
(str "id-" @calls))
batches (#'sut/page-and-block-batches {:pages 50000
:blocks 50
:batch-pages 100}
next-id)
first-batch (first batches)]
(is (= 100 (count first-batch)))
(is (= (* 100 51) @calls)
"Only the first batch should be realized")
(is (= "Page-0" (get-in first-batch [0 :page :block/title])))
(is (= "Page-99" (get-in first-batch [99 :page :block/title])))))
(deftest default-batching-keeps-large-graphs-bounded
(testing "50k pages with 50 blocks are split into many batches instead of one giant tx"
(let [batch-pages (#'sut/default-batch-pages 50)]
(is (< batch-pages 50000))
(is (pos? batch-pages))
(is (= batch-pages
(count (first (#'sut/page-and-block-batches {:pages 50000
:blocks 50}
(constantly "id")))))))))
(deftest page-and-block-batches-handle-empty-input
(is (= []
(into [] (#'sut/page-and-block-batches {:pages 0
:blocks 50}
(constantly "id"))))))
(deftest parse-args-keeps-the-graph-name-separate-from-cli-options
(let [{:keys [graph-dir options]} (sut/parse-args ["large-graph"
"-p" "3"
"-b" "2"
"-t" "1"])]
(is (= "large-graph" graph-dir))
(is (= 3 (:pages options)))
(is (= 2 (:blocks options)))
(is (= 1 (:batch-pages options)))))

View File

@@ -0,0 +1,12 @@
(ns logseq.tasks.dev-mobile-test
(:require [clojure.test :refer [deftest is run-tests]]
[logseq.tasks.dev.mobile :as mobile]))
(deftest dev-server-url-keeps-mobile-assets-relative-to-mobile-path
(is (= "https://192.0.2.1:3002/mobile/"
(mobile/dev-server-url "192.0.2.1"))))
(defn -main
[& _]
(let [{:keys [fail error]} (run-tests 'logseq.tasks.dev-mobile-test)]
(System/exit (+ fail error))))

View File

@@ -0,0 +1,197 @@
(ns logseq.tasks.dev-test
(:require [clojure.string :as string]
[clojure.test :refer [deftest is run-tests]]
[logseq.tasks.dev :as dev]
[logseq.tasks.dev.lint :as dev-lint]))
(deftest lint-and-test-starts-tests-while-lint-is-running
(let [lint-started (promise)
test-started (promise)
release-tasks (promise)
parallel-test-args (atom nil)]
(with-redefs [dev-lint/dev (fn []
(deliver lint-started true)
@test-started
@release-tasks)
dev/parallel-test (fn [& args]
(reset! parallel-test-args args)
(deliver test-started true)
@lint-started
@release-tasks)]
(let [runner (future (dev/lint-and-test))]
(is (deref lint-started 1000 false))
(is (deref test-started 100 false))
(deliver test-started true)
(deliver release-tasks true)
@runner
(is (= ["-e" "long" "-e" "fix-me"] @parallel-test-args))))))
(def test-namespaces
["frontend.alpha-test"
"frontend.beta-test"
"frontend.gamma-test"
"frontend.delta-test"
"frontend.epsilon-test"])
(deftest run-test-namespaces-batches-namespaces-across-workers
(let [started-node-runs (atom [])]
(with-redefs [dev/test-jobs 2
dev/test-batches-per-job 1
dev/run-shell (fn [& args]
(let [cmd-args (mapv str args)]
(if (some #{"--list-namespaces"} cmd-args)
{:out (string/join "\n" test-namespaces)}
(swap! started-node-runs conj cmd-args))))]
(dev/run-test-namespaces)
(is (= 2 (count @started-node-runs)))
(is (= (set test-namespaces)
(->> @started-node-runs
(mapcat identity)
(filter (set test-namespaces))
set))))))
(deftest run-test-namespaces-isolates-stateful-namespaces
(let [namespaces ["frontend.alpha-test"
"frontend.components.block.drop-boundary-test"
"frontend.handler.editor-test"
"frontend.worker.db-core-test"]
started-node-runs (atom [])]
(with-redefs [dev/test-jobs 2
dev/test-batches-per-job 1
dev/run-shell (fn [& args]
(let [cmd-args (mapv str args)]
(if (some #{"--list-namespaces"} cmd-args)
{:out (string/join "\n" namespaces)}
(swap! started-node-runs conj cmd-args))))]
(dev/run-test-namespaces)
(is (= 4 (count @started-node-runs)))
(doseq [isolated-ns ["frontend.components.block.drop-boundary-test"
"frontend.handler.editor-test"
"frontend.worker.db-core-test"]]
(is (= 1 (count (filter #(some #{isolated-ns} %) @started-node-runs))))
(is (= 1 (->> @started-node-runs
(some #(when (some #{isolated-ns} %) %))
(filter (set namespaces))
count)))))))
(deftest run-test-namespaces-runs-performance-tests-after-parallel-tests
(let [namespaces ["frontend.alpha-test"
"frontend.db.query-dsl-test"
"frontend.worker.search-test"]
completed-runs (atom [])
parallel-finished? (atom false)]
(with-redefs [dev/test-jobs 2
dev/test-batches-per-job 1
dev/run-shell (fn [& args]
(let [cmd-args (mapv str args)]
(if (some #{"--list-namespaces"} cmd-args)
{:out (string/join "\n" namespaces)}
(let [selected (filter (set namespaces) cmd-args)]
(when (some #{"frontend.alpha-test"} selected)
(reset! parallel-finished? true))
(when (some dev/serial-test-namespaces selected)
(is @parallel-finished?))
(swap! completed-runs into selected)))))]
(dev/run-test-namespaces)
(is (= namespaces @completed-runs)))))
(deftest run-test-namespaces-handles-an-empty-selection
(let [node-runs (atom 0)]
(with-redefs [dev/test-jobs 2
dev/test-batches-per-job 1
dev/run-shell (fn [& args]
(if (some #{"--list-namespaces"} (map str args))
{:out ""}
(swap! node-runs inc)))]
(dev/run-test-namespaces)
(is (zero? @node-runs)))))
(deftest parallel-test-runs-test-namespaces-concurrently
(let [compile-ran? (atom false)
listed-namespaces? (atom false)
started-node-runs (atom [])
release-node-runs (promise)
wait-for-started-runs (fn [n]
(loop [remaining-attempts 20]
(when (and (< (count @started-node-runs) n)
(pos? remaining-attempts))
(Thread/sleep 50)
(recur (dec remaining-attempts)))))]
(with-redefs [dev/test-jobs 2
dev/test-batches-per-job 1
dev/run-shell (fn [& args]
(let [cmd-text (string/join " " (map str args))]
(cond
(string/includes? cmd-text "pnpm cljs:test")
(reset! compile-ran? true)
(string/includes? cmd-text "--list-namespaces")
(do
(is (string/includes? cmd-text "^(?!logseq.db-sync.).*"))
(reset! listed-namespaces? true)
{:out (string/join "\n" test-namespaces)})
(string/includes? cmd-text "static/tests.js")
(do
(swap! started-node-runs conj args)
@release-node-runs))))]
(let [runner (future (dev/parallel-test "-e" "long" "-e" "fix-me"))]
(wait-for-started-runs dev/test-jobs)
(is @compile-ran?)
(is @listed-namespaces?)
(is (= dev/test-jobs (count @started-node-runs)))
(is (every? #(some #{"-n"} (map str %)) @started-node-runs))
(is (every? #(= ["-e" "long" "-e" "fix-me"]
(take-last 4 (mapv str %)))
@started-node-runs))
(deliver release-node-runs true)
@runner
(is (= dev/test-jobs (count @started-node-runs)))
(is (= (set test-namespaces)
(->> @started-node-runs
(mapcat #(map str %))
(filter (set test-namespaces))
set)))))))
(deftest parallel-test-reraises-namespace-failure-after-running-namespaces
(let [started-node-runs (atom [])
release-node-runs (promise)
wait-for-started-runs (fn [n]
(loop [remaining-attempts 20]
(when (and (< (count @started-node-runs) n)
(pos? remaining-attempts))
(Thread/sleep 50)
(recur (dec remaining-attempts)))))]
(with-redefs [dev/test-jobs 2
dev/test-batches-per-job 1
dev/run-shell (fn [& args]
(let [cmd-text (string/join " " (map str args))]
(cond
(string/includes? cmd-text "--list-namespaces")
(do
(is (string/includes? cmd-text "^(?!logseq.db-sync.).*"))
{:out (string/join "\n" test-namespaces)})
(string/includes? cmd-text "static/tests.js")
(let [run-number (count (swap! started-node-runs conj args))]
@release-node-runs
(when (= 2 run-number)
(throw (ex-info "namespace failed" {})))))))]
(let [runner (future
(try
(dev/parallel-test "-e" "long" "-e" "fix-me")
:passed
(catch Throwable e
e)))]
(wait-for-started-runs dev/test-jobs)
(is (= dev/test-jobs (count @started-node-runs)))
(deliver release-node-runs true)
(let [result @runner]
(is (= dev/test-jobs (count @started-node-runs)))
(is (instance? clojure.lang.ExceptionInfo result))
(is (= "namespace failed" (ex-message result))))))))
(defn -main
[& _]
(let [{:keys [fail error]} (run-tests 'logseq.tasks.dev-test)]
(System/exit (+ fail error))))

View File

@@ -0,0 +1,127 @@
(ns logseq.tasks.lang-test
(:require [cljs.test :refer [deftest is testing]]
[logseq.tasks.lang-lint :as lang-lint]))
(deftest translation-placeholders-detect-placeholder-sets
(is (= #{"1" "2"}
(lang-lint/translation-placeholders "Open {1} from {2}")))
(is (= #{}
(lang-lint/translation-placeholders "Search with Google"))))
(deftest placeholder-mismatch-findings-detect-non-default-locale-errors
(testing "a localized value must match English placeholders exactly once it is defined"
(let [findings (lang-lint/placeholder-mismatch-findings
{:en {:electron/link-open-confirm "Are you sure?\n\n{1}"
:electron/write-file-failed-with-backup "Write failed {1} {2} {3}."}
:zh-Hant {:electron/link-open-confirm "確定要開啟此外部連結嗎?"
:electron/write-file-failed-with-backup "寫入失敗。備份檔案:{1}"}
:zh-CN {:electron/link-open-confirm "确定要打开此链接吗?\n\n{1}"
:electron/write-file-failed-with-backup "写入文件 {1} 失败,{2}。备份文件已保存到 {3}。"}})]
(is (= [{:lang :zh-Hant
:translation-key :electron/link-open-confirm
:expected-placeholders ["1"]
:actual-placeholders []
:default-value "Are you sure?\n\n{1}"
:localized-value "確定要開啟此外部連結嗎?"}
{:lang :zh-Hant
:translation-key :electron/write-file-failed-with-backup
:expected-placeholders ["1" "2" "3"]
:actual-placeholders ["1"]
:default-value "Write failed {1} {2} {3}."
:localized-value "寫入失敗。備份檔案:{1}"}]
findings)))))
(deftest translation-rich-validation-findings-report-rich-contract-mismatches
(testing "a localized rich translation must remain a zero-arg function once defined"
(is (= [{:lang :zh-Hant
:translation-key :e2ee/cloud-password-rich
:expected-value-kind :fn
:actual-value-kind :string}
{:lang :zh-Hant
:translation-key :on-boarding/main-title
:expected-value-kind :fn
:actual-value-kind :string}]
(lang-lint/rich-translation-mismatch-findings
{:en {:on-boarding/main-title (fn [] ["Welcome to " [:strong "Logseq!"]])
:e2ee/cloud-password-rich (fn [] ["Cloud sentence " [:span "Local sentence"]])
:e2ee/remember-password-rich (fn [] [[:span "Remember "] "your password."])}
:zh-Hant {:on-boarding/main-title "歡迎使用 Logseq"
:e2ee/cloud-password-rich "雲端密碼"
:e2ee/remember-password-rich (fn [] [[:span "請記住"] "你的密碼。"])}})))))
(deftest identical-translation-findings-report-defined-values-equal-to-english
(is (= [{:lang :ko
:translation-key :ui/cancel
:default-value "Cancel"}
{:lang :ko
:translation-key :ui/save
:default-value "Save"}]
(lang-lint/identical-translation-findings
{:en {:ui/cancel "Cancel"
:ui/save "Save"
:ui/close "Close"}
:ko {:ui/cancel "Cancel"
:ui/save "Save"
:ui/close "닫기"}
:fr {:ui/cancel "Annuler"}}
:ko))))
(deftest identical-translation-stats-count-defined-values-equal-to-english
(is (= [{:lang :en
:translation-count 2
:same-as-en-count 2}
{:lang :ko
:translation-count 2
:same-as-en-count 1}
{:lang :fr
:translation-count 1
:same-as-en-count 0}]
(lang-lint/identical-translation-stats
{:en {:ui/cancel "Cancel"
:ui/save "Save"}
:ko {:ui/cancel "Cancel"
:ui/save "저장"}
:fr {:ui/cancel "Annuler"}}))))
(deftest translation-summary-stats-report-untranslated-and-same-as-en-count
(is (= [{:lang :en
:translation-count 4
:untranslated-count nil
:same-as-en-count nil}
{:lang :fr
:translation-count 2
:untranslated-count 2
:same-as-en-count 1}
{:lang :ko
:translation-count 3
:untranslated-count 1
:same-as-en-count 2}]
(->> (lang-lint/translation-summary-stats
{:en {:ui/cancel "Cancel"
:ui/save "Save"
:ui/close "Close"
:ui/delete "Delete"}
:ko {:ui/cancel "Cancel"
:ui/save "저장"
:ui/close "Close"}
:fr {:ui/cancel "Annuler"
:ui/save "Save"}})
(sort-by :lang)
vec))))
(deftest sort-translation-summary-stats-keeps-en-first-then-sorts-by-untranslated-and-same-as-en-count
(is (= [:en :ko :fr :zh-Hant]
(->> [{:lang :fr
:untranslated-count 3
:same-as-en-count 1}
{:lang :en
:untranslated-count nil
:same-as-en-count nil}
{:lang :zh-Hant
:untranslated-count 1
:same-as-en-count 3}
{:lang :ko
:untranslated-count 3
:same-as-en-count 2}]
lang-lint/sort-translation-summary-stats
(mapv :lang)))))

View File

@@ -0,0 +1,15 @@
(ns logseq.tasks.test-runner
(:require [cljs.test :as test]
[logseq.tasks.db-graph.create-graph-with-clojure-irc-history-test]
[logseq.tasks.db-graph.create-graph-with-large-sizes-test]
[logseq.tasks.lang-test]
[logseq.tasks.util-test]))
(defn -main [& _]
(let [{:keys [fail error]}
(test/run-tests 'logseq.tasks.db-graph.create-graph-with-large-sizes-test
'logseq.tasks.db-graph.create-graph-with-clojure-irc-history-test
'logseq.tasks.lang-test
'logseq.tasks.util-test)]
(when (pos? (+ fail error))
(js/process.exit 1))))

View File

@@ -0,0 +1,19 @@
(ns logseq.tasks.util-test
(:require [cljs.test :refer [deftest is]]
[logseq.tasks.util :as util]))
(deftest display-width-handles-wide-and-combining-characters
(is (= 5 (util/display-width "hello")))
(is (= 4 (util/display-width "中文")))
(is (= 4 (util/display-width "한국")))
(is (= 1 (util/display-width "e\u0301"))))
(deftest render-table-right-aligns-columns-using-display-width
(is (= (str "| :locale | :language |\n"
"|---------+-----------|\n"
"| :en | English |\n"
"| :ja | 日本語 |\n"
"| :ko | 한국 |\n")
(util/render-table [{:locale :en :language "English"}
{:locale :ja :language "日本語"}
{:locale :ko :language "한국"}]))))