5.1 KiB
Logseq CLI Add Reference UUID Rewrite Plan
Goal: For logseq-cli add block/page content, replace every [[<reference-name>]] with [[block-uuid]] before calling db-worker-node thread-api, creating missing pages when needed.
Architecture: logseq-cli (src/main/logseq/cli/command/add.cljs) sends :thread-api/apply-outliner-ops calls through logseq.cli.transport. db-worker-node executes outliner-op/apply-ops! without normalizing refs. Frontend already normalizes refs using logseq.db.frontend.content/title-ref->id-ref, but CLI does not.
Tech Stack: ClojureScript, logseq-cli, db-worker-node, Datascript.
Problem statement
Today logseq-cli passes block content to db-worker-node as-is. If content includes [[Page Name]], db-worker-node does not automatically resolve or create that page for outliner ops. We need to normalize content refs to uuid references up front so db-worker-node receives canonical refs and missing pages are created deterministically.
Current behavior summary
logseq-cli add blockbuilds blocks and calls:thread-api/apply-outliner-opswith:insert-blocks.logseq-cli add pagecalls:thread-api/apply-outliner-opswith:create-pageonly (no content normalization).- db-worker-node
:thread-api/apply-outliner-opsapplies ops verbatim and does not resolve page refs in block content. - Frontend editor normalizes refs using
logseq.db.frontend.content/title-ref->id-ref, but CLI paths do not use it.
Requirements
- For add block and add page content, replace every
[[<reference-name>]]with[[block-uuid]]before invoking db-worker-node thread-api. - Page reference:
- If
<reference-name>is not a UUID, treat it as a page title. - If the page does not exist, create it first.
- Replace
[[Page Title]]with[[page-uuid]](case-insensitive).
- If
- Block reference:
- If
<reference-name>is a UUID, treat it as a block ref. - The block must exist; otherwise return a CLI error.
- If
- Do not change other syntax (e.g.
((uuid))block refs, tags, or macros) unless they are inside[[...]].
Non-goals
- Do not alter how
((uuid))block refs are parsed or stored. - Do not introduce automatic block creation for missing block UUIDs.
- Do not change CLI command flags or output format.
Design decisions
- Reuse
logseq.db.frontend.content/title-ref->id-refso CLI behavior matches frontend normalization rules. - Extract
[[...]]refs using the existing page-ref regex fromlogseq.common.util.page-refto avoid implementing a new parser. - Resolve refs once per CLI action, cache page-name -> uuid, and then update all affected blocks before the first
:thread-api/apply-outliner-opscall. - Handle page creation with the existing
ensure-page!helper insrc/main/logseq/cli/command/add.cljsfor consistent behavior.
Implementation plan
1) Add reference extraction and resolution helpers
src/main/logseq/cli/command/add.cljs- Add a helper to extract
[[...]]tokens from a block title usinglogseq.common.util.page-ref/page-ref-re. - Add a helper that partitions refs into:
uuid-refs:[[<uuid>]]valuespage-refs:[[<page-title>]]values
- Add a resolver that:
- For
page-refs, callsensure-page!(once per unique title) and returns{:block/uuid uuid :block/title title}. - For
uuid-refs, pulls the entity by[:block/uuid uuid]and errors if missing.
- For
- Add a helper to extract
2) Normalize add block content before outliner ops
src/main/logseq/cli/command/add.cljs- In
execute-add-block, before building ops:- Walk the
:blockstree (top-level and any nested:block/children) and collect all[[...]]refs. - Resolve refs once per action using the resolver from step 1.
- For each block with
:block/title, rewrite it withdb-content/title-ref->id-refusing the resolved refs and{:replace-tag? false}.
- Walk the
- Use the rewritten blocks in the
:insert-blocksop.
- In
3) Normalize add page content (when present)
src/main/logseq/cli/command/add.cljs- If add page grows to accept initial blocks/content (or if
:create-pageoptions start supporting content), reuse the same ref normalization flow from step 2 before invoking:create-pageor:insert-blocks. - If no content is provided, no change is needed in the current implementation.
- If add page grows to accept initial blocks/content (or if
4) Tests
test/logseq/cli/integration_test.cljs- Add an integration test for
add blockwith content"See [[New Page]]":- Assert the page is created.
- Pull the inserted block and verify its title contains
[[<page-uuid>]]instead of[[New Page]].
- Add an integration test for
add blockwith content"See [[<existing-block-uuid>]]":- Assert the UUID is preserved and no new page is created.
- Add an integration test for
add blockwith content"See [[<missing-block-uuid>]]":- Assert CLI returns an error with a clear message.
- Add an integration test for
Notes
- If we later decide to normalize tags (
#tag) or macro-based refs, we can extend the resolver to calldb-content/title-ref->id-refwith:replace-tag? trueand add tests accordingly. - Keep all normalization in CLI to avoid changing db-worker-node semantics for other callers.