diff --git a/app/docs/block-sync.md b/app/docs/block-sync.md index 536e82f..b949fe1 100644 --- a/app/docs/block-sync.md +++ b/app/docs/block-sync.md @@ -43,7 +43,7 @@ The status (`LogStatus`: each writer directory's state, and the paths skipped) i None of these block convergence — every device agrees on the same answer. They are about the answer being the one a person expected. Ranked by how much they will actually bite. 1. **`block.outdented` moves blocks it does not name.** Trailing siblings become children, so its effect is defined over whoever the siblings happened to be at fold time, which differs per device. Carrying the explicit ids it moves makes it mergeable. Payload `v: 3` — `v: 2` is the one that dropped `page`. **Do this one before relying on sync daily.** -2. **`block.deleted` has no tombstone.** Device A deletes X while device B writes a block `after: X`. The fallback in `reduce` (`packages/pages/blocks.ts`) keeps the content — the right instinct — but the block lands at the bottom of the page instead of where it was written. A tombstone restores the placement. +2. **`block.deleted` has no tombstone.** Device A deletes X while device B writes a block `after: X`. The fallback in `reduce` (`packages/pages/src/blocks/blocks.ts`) keeps the content — the right instinct — but the block lands at the bottom of the page instead of where it was written. A tombstone restores the placement. 3. **`block.indented` no-ops when its `parent` is gone**, silently dropping the user's intent. Deterministic, so both devices drop it identically. Still surprising. 4. **Text is last-writer-wins per block.** Concurrent edits to one block lose one side. The loser is still on disk forever, so it can be surfaced rather than pretended away. @@ -55,7 +55,7 @@ None of these block convergence — every device agrees on the same answer. They ## Tests -The ledger's tests cover the order, the stalls and convergence, with events of their own that are not blocks. The block fold is tested without a log in `packages/pages/blocks.test.ts` and `packages/pages/pages.test.ts`, and through one in `src/main/features/projects/pages/pages-store/pages-store.test.ts`. Both write from a single device. Nothing yet tests two devices' block events interleaving, so each deferred item above lands with a test that folds its events in both orders. +The ledger's tests cover the order, the stalls and convergence, with events of their own that are not blocks. The block fold is tested without a log in `packages/pages/src/blocks/blocks.test.ts` and `packages/pages/src/pages.test.ts`, and through one in `src/main/features/projects/pages/pages-store/pages-store.test.ts`. Both write from a single device. Nothing yet tests two devices' block events interleaving, so each deferred item above lands with a test that folds its events in both orders. ## Order of work diff --git a/packages/pages/package.json b/packages/pages/package.json index 2d9fdc1..d504a9a 100644 --- a/packages/pages/package.json +++ b/packages/pages/package.json @@ -4,10 +4,10 @@ "description": "What pbnotes events mean: the pages fold, the queries over it, and the commands that write it.", "private": true, "type": "module", - "main": "./pages.ts", - "exports": "./pages.ts", + "main": "./src/pages.ts", + "exports": "./src/pages.ts", "scripts": { - "test": "node --test '*.test.ts'" + "test": "node --test '**/*.test.ts'" }, "dependencies": { "mdast-util-gfm-autolink-literal": "^2.0.1", diff --git a/packages/pages/blocks.test.ts b/packages/pages/src/blocks/blocks.test.ts similarity index 99% rename from packages/pages/blocks.test.ts rename to packages/pages/src/blocks/blocks.test.ts index 7cc9c37..fe93d27 100644 --- a/packages/pages/blocks.test.ts +++ b/packages/pages/src/blocks/blocks.test.ts @@ -15,7 +15,7 @@ import { predict, reduce, } from "./blocks.ts"; -import { getPage, getReferences, searchPages } from "./pages.ts"; +import { getPage, getReferences, searchPages } from "../pages.ts"; import type { Block, PageEvent, Pages } from "./blocks.ts"; const TODAY = "2026-09-21"; diff --git a/packages/pages/blocks.ts b/packages/pages/src/blocks/blocks.ts similarity index 97% rename from packages/pages/blocks.ts rename to packages/pages/src/blocks/blocks.ts index dc1692b..cceee2f 100644 --- a/packages/pages/blocks.ts +++ b/packages/pages/src/blocks/blocks.ts @@ -20,9 +20,9 @@ * fold, or they drift: that is why this is a package and not a copy. */ -import { canonicalize } from "./canonicalize.ts"; -import { read } from "./reading.ts"; -import type { Properties } from "./properties.ts"; +import { canonicalize } from "../canonicalize/canonicalize.ts"; +import { read } from "../reading/reading.ts"; +import type { Properties } from "../properties/properties.ts"; export type Block = { id: string; @@ -123,7 +123,10 @@ export function titleOf(pages: Pages, title: string): string { * * Exported for the property fold, which spells a page the same way. */ -export function spell(titles: Pages["titles"], names: string[]): Pages["titles"] { +export function spell( + titles: Pages["titles"], + names: string[], +): Pages["titles"] { let next = titles; for (const name of names) { const key = canonicalize(name); @@ -345,7 +348,10 @@ function onBlock( if (!found) return state; const blocks = change(found); return blocks - ? { ...state, blocks: new Map(state.blocks).set(canonicalize(found.page), blocks) } + ? { + ...state, + blocks: new Map(state.blocks).set(canonicalize(found.page), blocks), + } : state; } @@ -531,7 +537,8 @@ export function outdented( * children all over again. */ function landed(state: Pages, event: PageEvent): boolean { - if (event.type === `${NAMESPACE}block.created`) return !!find(state, event.payload.id); + if (event.type === `${NAMESPACE}block.created`) + return !!find(state, event.payload.id); const found = find(state, event.payload.id); if (event.type === `${NAMESPACE}block.indented`) { return found?.parent?.id === event.payload.parent; diff --git a/packages/pages/canonicalize.test.ts b/packages/pages/src/canonicalize/canonicalize.test.ts similarity index 100% rename from packages/pages/canonicalize.test.ts rename to packages/pages/src/canonicalize/canonicalize.test.ts diff --git a/packages/pages/canonicalize.ts b/packages/pages/src/canonicalize/canonicalize.ts similarity index 100% rename from packages/pages/canonicalize.ts rename to packages/pages/src/canonicalize/canonicalize.ts diff --git a/packages/pages/pages.test.ts b/packages/pages/src/pages.test.ts similarity index 100% rename from packages/pages/pages.test.ts rename to packages/pages/src/pages.test.ts diff --git a/packages/pages/pages.ts b/packages/pages/src/pages.ts similarity index 96% rename from packages/pages/pages.ts rename to packages/pages/src/pages.ts index 5e34c06..b2fc7e9 100644 --- a/packages/pages/pages.ts +++ b/packages/pages/src/pages.ts @@ -23,7 +23,7 @@ import { outdented, reduce, titleOf, -} from "./blocks.ts"; +} from "./blocks/blocks.ts"; import type { Block, BlockIndented, @@ -31,13 +31,13 @@ import type { Page, PageEvent, Pages, -} from "./blocks.ts"; -import { canonicalize } from "./canonicalize.ts"; -import { linking, read } from "./reading.ts"; -import { PROPERTY_HANDLES, reduceProperties } from "./properties.ts"; -import type { PropertyEvent } from "./properties.ts"; +} from "./blocks/blocks.ts"; +import { canonicalize } from "./canonicalize/canonicalize.ts"; +import { linking, read } from "./reading/reading.ts"; +import { PROPERTY_HANDLES, reduceProperties } from "./properties/properties.ts"; +import type { PropertyEvent } from "./properties/properties.ts"; -export { canonicalize } from "./canonicalize.ts"; +export { canonicalize } from "./canonicalize/canonicalize.ts"; export { beside, blocksOn, @@ -51,7 +51,7 @@ export { reduce, titleOf, without, -} from "./blocks.ts"; +} from "./blocks/blocks.ts"; export type { Block, BlockCreated, @@ -63,8 +63,8 @@ export type { Page, PageEvent, Pages, -} from "./blocks.ts"; -export { inCode, linking, read } from "./reading.ts"; +} from "./blocks/blocks.ts"; +export { inCode, linking, read } from "./reading/reading.ts"; export { children, get, @@ -73,7 +73,7 @@ export { list, path, showPath, -} from "./properties.ts"; +} from "./properties/properties.ts"; export type { Entry, Properties, @@ -86,8 +86,8 @@ export type { PropertyUnset, Scalar, Seen, -} from "./properties.ts"; -export { remarkPlugins, remarkWikilink } from "./wikilink.ts"; +} from "./properties/properties.ts"; +export { remarkPlugins, remarkWikilink } from "./wikilink/wikilink.ts"; /** * What makes a title a journal day. Whoever writes picks the day, so the fold diff --git a/packages/pages/properties.test.ts b/packages/pages/src/properties/properties.test.ts similarity index 99% rename from packages/pages/properties.test.ts rename to packages/pages/src/properties/properties.test.ts index e5b6454..baca5ef 100644 --- a/packages/pages/properties.test.ts +++ b/packages/pages/src/properties/properties.test.ts @@ -19,8 +19,8 @@ import { pagesFold, path, showPath, -} from "./pages.ts"; -import type { Pages } from "./pages.ts"; +} from "../pages.ts"; +import type { Pages } from "../pages.ts"; const PAGE = "Mira"; const DAY = "2026-10-29"; diff --git a/packages/pages/properties.ts b/packages/pages/src/properties/properties.ts similarity index 99% rename from packages/pages/properties.ts rename to packages/pages/src/properties/properties.ts index 24ae723..8be081d 100644 --- a/packages/pages/properties.ts +++ b/packages/pages/src/properties/properties.ts @@ -18,8 +18,8 @@ * Like `blocks.ts`, nothing here touches a log, a clock or a window. */ -import { NAMESPACE, spell } from "./blocks.ts"; -import { canonicalize } from "./canonicalize.ts"; +import { NAMESPACE, spell } from "../blocks/blocks.ts"; +import { canonicalize } from "../canonicalize/canonicalize.ts"; /** * A value or an item. The four types stay distinct: `1`, `"1"`, `true` and diff --git a/packages/pages/reading.ts b/packages/pages/src/reading/reading.ts similarity index 96% rename from packages/pages/reading.ts rename to packages/pages/src/reading/reading.ts index 3c5538b..9107d5b 100644 --- a/packages/pages/reading.ts +++ b/packages/pages/src/reading/reading.ts @@ -7,9 +7,9 @@ */ import { unified } from "unified"; import remarkParse from "remark-parse"; -import { canonicalize } from "./canonicalize.ts"; -import type { Block } from "./blocks.ts"; -import { remarkPlugins } from "./wikilink.ts"; +import { canonicalize } from "../canonicalize/canonicalize.ts"; +import type { Block } from "../blocks/blocks.ts"; +import { remarkPlugins } from "../wikilink/wikilink.ts"; /** * The pages a text links to and the blocks it refers to, read with the same parser that renders it, so diff --git a/packages/pages/wikilink.test.ts b/packages/pages/src/wikilink/wikilink.test.ts similarity index 100% rename from packages/pages/wikilink.test.ts rename to packages/pages/src/wikilink/wikilink.test.ts diff --git a/packages/pages/wikilink.ts b/packages/pages/src/wikilink/wikilink.ts similarity index 100% rename from packages/pages/wikilink.ts rename to packages/pages/src/wikilink/wikilink.ts