refactor: finish frontend independence from worker and add lint

Remaining fixes worker all file related. Fixes LOG-3717
pull/10981/head
Gabriel Horner 2024-08-09 12:16:20 -04:00
parent 20eac03cea
commit 261118d4dc
15 changed files with 87 additions and 64 deletions

View File

@ -55,6 +55,8 @@
frontend.components.class class-component frontend.components.class class-component
frontend.components.property property-component frontend.components.property property-component
frontend.common.date common-date frontend.common.date common-date
frontend.common.file.core common-file
frontend.common.file.util wfu
frontend.common.missionary-util c.m frontend.common.missionary-util c.m
frontend.common.schema-register sr frontend.common.schema-register sr
frontend.common.search-fuzzy fuzzy frontend.common.search-fuzzy fuzzy
@ -134,9 +136,6 @@
frontend.worker.util worker-util frontend.worker.util worker-util
frontend.worker.state worker-state frontend.worker.state worker-state
frontend.worker.handler.page worker-page frontend.worker.handler.page worker-page
frontend.worker.handler.page.rename worker-page-rename
frontend.worker.handler.file.util wfu
logseq.outliner.batch-tx batch-tx
lambdaisland.glogi log lambdaisland.glogi log
logseq.common.config common-config logseq.common.config common-config
logseq.common.graph common-graph logseq.common.graph common-graph
@ -169,6 +168,7 @@
logseq.graph-parser.block gp-block logseq.graph-parser.block gp-block
logseq.graph-parser.mldoc gp-mldoc logseq.graph-parser.mldoc gp-mldoc
logseq.graph-parser.property gp-property logseq.graph-parser.property gp-property
logseq.outliner.batch-tx batch-tx
logseq.outliner.core outliner-core logseq.outliner.core outliner-core
logseq.outliner.op outliner-op logseq.outliner.op outliner-op
logseq.outliner.pipeline outliner-pipeline logseq.outliner.pipeline outliner-pipeline

View File

@ -122,11 +122,12 @@ The main convention is that file and db specific files go under directories name
### Separate Worker from Frontend ### Separate Worker from Frontend
The worker and frontend code share common code from deps/ and `frontend.common.*`. However, the worker should never depend on other frontend namespaces as it could pull in libraries like React which cause it to fail hard. Run this linter to ensure worker namespaces are not dependent on other frontend namespaces: The worker and frontend code share common code from deps/ and `frontend.common.*`. However, the worker should never depend on other frontend namespaces as it could pull in libraries like React which cause it to fail hard. Likewise the frontend should never depend on worker namespaces. Run this linter to ensure worker and frontend namespaces don't require each other:
``` ```
$ bb lint:worker-and-frontend-separate $ bb lint:worker-and-frontend-separate
Success! Valid worker namespaces!
Valid frontend namespaces!
``` ```
## Testing ## Testing

View File

@ -21,8 +21,7 @@
(println cmd) (println cmd)
(shell cmd))) (shell cmd)))
(defn worker-and-frontend-separate (defn- validate-frontend-not-in-worker
"Ensures worker is independent of frontend"
[] []
(let [res (shell {:out :string} (let [res (shell {:out :string}
"git grep -h" "\\[frontend.*:as" "src/main/frontend/worker") "git grep -h" "\\[frontend.*:as" "src/main/frontend/worker")
@ -32,8 +31,26 @@
(if (seq req-lines) (if (seq req-lines)
(do (do
(println "The following requires should not be in worker namespaces:") (println "The following frontend requires should not be in worker namespaces:")
(println (string/join "\n" req-lines)) (println (string/join "\n" req-lines))
(System/exit 1)) (System/exit 1))
(println "Success!")))) (println "Valid worker namespaces!"))))
(defn- validate-worker-not-in-frontend
[]
(let [res (shell {:out :string :continue true}
"grep -r --exclude-dir=worker" "\\[frontend.worker.*:" "src/main/frontend")
req-lines (->> (:out res) string/split-lines)]
(if-not (and (= 1 (:exit res)) (= "" (:out res)))
(do
(println "The following worker requires should not be in frontend namespaces:")
(println (:out res))
(System/exit 1))
(println "Valid frontend namespaces!"))))
(defn worker-and-frontend-separate
"Ensures worker is independent of frontend"
[]
(validate-frontend-not-in-worker)
(validate-worker-not-in-frontend))

View File

@ -5,7 +5,7 @@
[clojure.pprint :as pprint] [clojure.pprint :as pprint]
[clojure.test :refer [deftest testing]] [clojure.test :refer [deftest testing]]
[fipp.edn :as fipp] [fipp.edn :as fipp]
[frontend.worker.file.util :as wfu])) [frontend.common.file.util :as wfu]))
(def onboarding (def onboarding
(edn/read-string (slurped "resources/whiteboard/onboarding.edn"))) (edn/read-string (slurped "resources/whiteboard/onboarding.edn")))

View File

@ -1,14 +1,16 @@
(ns frontend.worker.file.core (ns frontend.common.file.core
"Save file to disk. Used by both file and DB graphs" "Save file to disk. Used by both file and DB graphs and shared
by worker and frontend namespaces"
(:require [clojure.string :as string] (:require [clojure.string :as string]
[frontend.worker.file.util :as wfu] [frontend.common.file.util :as wfu]
[logseq.graph-parser.property :as gp-property] [logseq.graph-parser.property :as gp-property]
[logseq.common.path :as path] [logseq.common.path :as path]
[datascript.core :as d] [datascript.core :as d]
[logseq.db :as ldb] [logseq.db :as ldb]
[frontend.common.date :as common-date] [frontend.common.date :as common-date]
[frontend.worker.util :as worker-util] [logseq.db.frontend.content :as db-content]
[logseq.db.sqlite.util :as sqlite-util])) [logseq.db.sqlite.util :as sqlite-util]
[logseq.outliner.tree :as otree]))
(defonce *writes (atom {})) (defonce *writes (atom {}))
(defonce *request-id (atom 0)) (defonce *request-id (atom 0))
@ -174,10 +176,10 @@
(let [files [[file-path new-content]]] (let [files [[file-path new-content]]]
(when (seq files) (when (seq files)
(let [page-id (:db/id page-block)] (let [page-id (:db/id page-block)]
(worker-util/post-message :write-files {:request-id request-id (wfu/post-message :write-files {:request-id request-id
:page-id page-id :page-id page-id
:repo repo :repo repo
:files files}) :files files})
:sent))))) :sent)))))
;; In e2e tests, "card" page in db has no :file/path ;; In e2e tests, "card" page in db has no :file/path
(js/console.error "File path from page-block is not valid" page-block tree))] (js/console.error "File path from page-block is not valid" page-block tree))]
@ -195,3 +197,18 @@
(if file (if file
(ok-handler) (ok-handler)
(transact-file-tx-if-not-exists! conn page-block ok-handler context))))) (transact-file-tx-if-not-exists! conn page-block ok-handler context)))))
(defn block->content
"Converts a block including its children (recursively) to plain-text."
[repo db root-block-uuid tree->file-opts context]
(assert (uuid? root-block-uuid))
(let [init-level (or (:init-level tree->file-opts)
(if (ldb/page? (d/entity db [:block/uuid root-block-uuid]))
0
1))
blocks (->> (d/pull-many db '[*] (keep :db/id (ldb/get-block-and-children db root-block-uuid)))
(map #(db-content/update-block-content db % (:db/id %))))
tree (otree/blocks->vec-tree repo db blocks (str root-block-uuid))]
(tree->file-content repo db tree
(assoc tree->file-opts :init-level init-level)
context)))

View File

@ -1,7 +1,8 @@
(ns frontend.worker.file.util (ns frontend.common.file.util
"File name fns" "File name fns. Used by worker and frontend namespaces"
(:require [clojure.string :as string] (:require [clojure.string :as string]
[logseq.common.util :as common-util])) [logseq.common.util :as common-util]
[logseq.db :as ldb]))
;; Update repo/invalid-graph-name-warning if characters change ;; Update repo/invalid-graph-name-warning if characters change
(def multiplatform-reserved-chars ":\\*\\?\"<>|\\#\\\\") (def multiplatform-reserved-chars ":\\*\\?\"<>|\\#\\\\")
@ -88,3 +89,8 @@
[x] [x]
(with-redefs [print-prefix-map print-prefix-map*] (with-redefs [print-prefix-map print-prefix-map*]
(pr-str x))) (pr-str x)))
(defn post-message
[type data]
(when (exists? js/self)
(.postMessage js/self (ldb/write-transit-str [type data]))))

View File

@ -13,7 +13,7 @@
[frontend.persist-db.browser :as db-browser] [frontend.persist-db.browser :as db-browser]
[frontend.state :as state] [frontend.state :as state]
[frontend.util :as util :refer [concatv mapcatv removev]] [frontend.util :as util :refer [concatv mapcatv removev]]
[frontend.worker.export :as worker-export] [frontend.common.file.core :as common-file]
[malli.core :as m] [malli.core :as m]
[malli.util :as mu] [malli.util :as mu]
[promesa.core :as p])) [promesa.core :as p]))
@ -93,9 +93,9 @@
[page-uuid] [page-uuid]
(let [repo (state/get-current-repo) (let [repo (state/get-current-repo)
db (db/get-db repo)] db (db/get-db repo)]
(worker-export/block->content repo db page-uuid (common-file/block->content repo db page-uuid
nil nil
{:export-bullet-indentation (state/get-export-bullet-indentation)}))) {:export-bullet-indentation (state/get-export-bullet-indentation)})))
(defn- page-name->ast (defn- page-name->ast
[page-name] [page-name]

View File

@ -1,6 +1,6 @@
(ns frontend.modules.file.core (ns frontend.modules.file.core
"Convert block trees to content" "Convert block trees to content"
(:require [frontend.worker.file.core :as worker-file] (:require [frontend.common.file.core :as common-file]
[frontend.state :as state] [frontend.state :as state]
[frontend.db :as db])) [frontend.db :as db]))
@ -11,4 +11,4 @@
(when-let [repo (state/get-current-repo)] (when-let [repo (state/get-current-repo)]
(let [db (db/get-db repo) (let [db (db/get-db repo)
context {:export-bullet-indentation (state/get-export-bullet-indentation)}] context {:export-bullet-indentation (state/get-export-bullet-indentation)}]
(worker-file/tree->file-content repo db tree opts context)))) (common-file/tree->file-content repo db tree opts context))))

View File

@ -8,7 +8,7 @@
[frontend.config :as config] [frontend.config :as config]
[promesa.core :as p] [promesa.core :as p]
[cljs.reader :as reader] [cljs.reader :as reader]
[frontend.worker.file.util :as wfu])) [frontend.common.file.util :as wfu]))
;; NOTE: This is not the same ignored-path? as src/electron/electron/utils.cljs. ;; NOTE: This is not the same ignored-path? as src/electron/electron/utils.cljs.
;; The assets directory is ignored. ;; The assets directory is ignored.

View File

@ -8,6 +8,7 @@
[clojure.string :as string] [clojure.string :as string]
[datascript.core :as d] [datascript.core :as d]
[datascript.storage :refer [IStorage]] [datascript.storage :refer [IStorage]]
[frontend.common.file.core :as common-file]
[frontend.worker.db-listener :as db-listener] [frontend.worker.db-listener :as db-listener]
[frontend.worker.db-metadata :as worker-db-metadata] [frontend.worker.db-metadata :as worker-db-metadata]
[frontend.worker.db.migrate :as db-migrate] [frontend.worker.db.migrate :as db-migrate]
@ -601,9 +602,9 @@
(assert (common-util/uuid-string? block-uuid-str)) (assert (common-util/uuid-string? block-uuid-str))
(let [block-uuid (uuid block-uuid-str)] (let [block-uuid (uuid block-uuid-str)]
(when-let [conn (worker-state/get-datascript-conn repo)] (when-let [conn (worker-state/get-datascript-conn repo)]
(worker-export/block->content repo @conn block-uuid (common-file/block->content repo @conn block-uuid
(ldb/read-transit-str tree->file-opts) (ldb/read-transit-str tree->file-opts)
(ldb/read-transit-str context))))) (ldb/read-transit-str context)))))
(get-all-pages (get-all-pages
[this repo] [this repo]

View File

@ -1,26 +1,10 @@
(ns frontend.worker.export (ns frontend.worker.export
"Export data" "Export data"
(:require [datascript.core :as d] (:require [datascript.core :as d]
[frontend.worker.file.core :as worker-file] [frontend.common.file.core :as common-file]
[logseq.db :as ldb] [logseq.db :as ldb]
[logseq.graph-parser.property :as gp-property] [logseq.graph-parser.property :as gp-property]
[logseq.outliner.tree :as otree] [logseq.outliner.tree :as otree]))
[logseq.db.frontend.content :as db-content]))
(defn block->content
"Converts a block including its children (recursively) to plain-text."
[repo db root-block-uuid tree->file-opts context]
(assert (uuid? root-block-uuid))
(let [init-level (or (:init-level tree->file-opts)
(if (ldb/page? (d/entity db [:block/uuid root-block-uuid]))
0
1))
blocks (->> (d/pull-many db '[*] (keep :db/id (ldb/get-block-and-children db root-block-uuid)))
(map #(db-content/update-block-content db % (:db/id %))))
tree (otree/blocks->vec-tree repo db blocks (str root-block-uuid))]
(worker-file/tree->file-content repo db tree
(assoc tree->file-opts :init-level init-level)
context)))
(defn- safe-keywordize (defn- safe-keywordize
[block] [block]
@ -64,4 +48,4 @@
(map (fn [d] (map (fn [d]
(let [e (d/entity db (:e d))] (let [e (d/entity db (:e d))]
[(:block/title e) [(:block/title e)
(block->content repo db (:block/uuid e) {} {})]))))) (common-file/block->content repo db (:block/uuid e) {} {})])))))

View File

@ -3,7 +3,7 @@
(:require [clojure.core.async :as async] (:require [clojure.core.async :as async]
[clojure.string :as string] [clojure.string :as string]
[clojure.set :as set] [clojure.set :as set]
[frontend.worker.file.core :as file] [frontend.common.file.core :as common-file]
[logseq.outliner.tree :as otree] [logseq.outliner.tree :as otree]
[lambdaisland.glogi :as log] [lambdaisland.glogi :as log]
[cljs-time.core :as t] [cljs-time.core :as t]
@ -17,9 +17,9 @@
[goog.object :as gobj] [goog.object :as gobj]
[logseq.common.util :as common-util])) [logseq.common.util :as common-util]))
(def *writes file/*writes) (def *writes common-file/*writes)
(def dissoc-request! file/dissoc-request!) (def dissoc-request! common-file/dissoc-request!)
(def conj-page-write! file/conj-page-write!) (def conj-page-write! common-file/conj-page-write!)
(defonce file-writes-chan (defonce file-writes-chan
(let [coercer (m/coercer [:catn (let [coercer (m/coercer [:catn
@ -81,7 +81,7 @@
(let [tree-or-blocks (if whiteboard? blocks (let [tree-or-blocks (if whiteboard? blocks
(otree/blocks->vec-tree repo @conn blocks (:db/id page-block)))] (otree/blocks->vec-tree repo @conn blocks (:db/id page-block)))]
(if page-block (if page-block
(file/save-tree! repo conn page-block tree-or-blocks blocks-just-deleted? context request-id) (common-file/save-tree! repo conn page-block tree-or-blocks blocks-just-deleted? context request-id)
(do (do
(js/console.error (str "can't find page id: " page-db-id)) (js/console.error (str "can't find page id: " page-db-id))
(dissoc-request! request-id))))))) (dissoc-request! request-id)))))))

View File

@ -5,7 +5,7 @@
[clojure.string :as string] [clojure.string :as string]
[clojure.walk :as walk] [clojure.walk :as walk]
[logseq.common.util.page-ref :as page-ref] [logseq.common.util.page-ref :as page-ref]
[frontend.worker.file.util :as wfu] [frontend.common.file.util :as wfu]
[logseq.db :as ldb] [logseq.db :as ldb]
[logseq.common.util :as common-util] [logseq.common.util :as common-util]
[logseq.common.config :as common-config] [logseq.common.config :as common-config]

View File

@ -6,8 +6,8 @@
[goog.crypt :as crypt] [goog.crypt :as crypt]
[goog.crypt.Hmac] [goog.crypt.Hmac]
[goog.crypt.Sha256] [goog.crypt.Sha256]
[logseq.db :as ldb] [logseq.db.sqlite.common-db :as sqlite-common-db]
[logseq.db.sqlite.common-db :as sqlite-common-db]))) [frontend.common.file.util :as wfu])))
;; Copied from https://github.com/tonsky/datascript-todo ;; Copied from https://github.com/tonsky/datascript-todo
#?(:clj #?(:clj
@ -23,10 +23,7 @@
#?(:cljs #?(:cljs
(do (do
(defn post-message (def post-message wfu/post-message)
[type data]
(when (exists? js/self)
(.postMessage js/self (ldb/write-transit-str [type data]))))
(defn get-pool-name (defn get-pool-name
[graph-name] [graph-name]

View File

@ -4,7 +4,7 @@
[logseq.graph-parser.extract :as extract] [logseq.graph-parser.extract :as extract]
[frontend.worker.handler.page.file-based.rename :as worker-page-rename] [frontend.worker.handler.page.file-based.rename :as worker-page-rename]
[frontend.util.fs :as fs-util] [frontend.util.fs :as fs-util]
[frontend.worker.file.util :as wfu])) [frontend.common.file.util :as wfu]))
(defn- test-page-name (defn- test-page-name
"Check if page name can be preserved after escaping" "Check if page name can be preserved after escaping"