First step of docs/git-sync-plan.md. New workspace package @docmost/git-sync vendoring the PURE parts from docmost-sync (HEAD b03eb35): - lib: markdown-converter, markdown-document, canonicalize, docmost-schema, node-ops, diff, and an extracted markdown-to-prosemirror (only the pure marked->HTML->generateJSON path from upstream collaboration.ts; no websocket). - engine (pure, no IO): reconcile, layout, sanitize, stabilize, loop-guard. Ported the upstream pure-module + round-trip corpus tests (vitest): 314 pass, 3 expected upstream known-limitation fails. tsc clean. No server wiring yet. docmost-schema inlines getStyleProperty (as packages/mcp does — @tiptap/core 3.20.4 doesn't export it). IO engine (pull/push/git/settings) deferred to later Phase A/B steps; the editor-ext idempotency gate (plan §13.1) is the next step. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
2.2 KiB
TypeScript
42 lines
2.2 KiB
TypeScript
/**
|
|
* docmost-sync ADDITION (not present in docmost-mcp).
|
|
*
|
|
* Semantic canonicalization of ProseMirror/TipTap documents for the Phase-0
|
|
* round-trip idempotency check (SPEC §11, "Задача №0", option (б): compare a
|
|
* CANONICALIZED form rather than raw bytes).
|
|
*
|
|
* `markdownToProseMirror` reconstructs schema DEFAULT attributes (e.g.
|
|
* `indent: null` where the source omitted it) and regenerates per-block ids on
|
|
* every import. A raw deep-equal of the source doc against the re-imported doc
|
|
* therefore diverges even when the two are semantically identical. This module
|
|
* normalizes a document so that two semantically-equal docs compare deep-equal
|
|
* regardless of block ids and absent-vs-explicit-default-null attributes.
|
|
*
|
|
* This file is intentionally a NEW, self-contained module so it is trivial to
|
|
* backport into docmost-mcp without touching existing code.
|
|
*/
|
|
/**
|
|
* Return a DEEP COPY of a ProseMirror node tree, canonicalized so that two
|
|
* semantically-equal documents compare deep-equal. Rules (applied recursively
|
|
* to the node, its `content`, and its `marks`):
|
|
*
|
|
* 1. Remove node-level `attrs.id` (regenerated on import). Mark attrs are NOT
|
|
* touched for `id` (marks carry no block id; only their meaningful attrs).
|
|
* 2. In any `attrs` object (node OR mark) drop keys whose value is `null`/
|
|
* `undefined` (absent ≡ explicit default null) OR equals that node/mark
|
|
* type's known non-null schema default (absent ≡ explicit default).
|
|
* Keep every non-default value. The type is passed into the attrs
|
|
* normalizer so it can look up `KNOWN_DEFAULTS`.
|
|
* 3. If an `attrs` object becomes empty after pruning, drop the `attrs` key.
|
|
* 4. Preserve `marks` (including the `comment` mark and its `commentId` — a
|
|
* meaningful anchor per SPEC §3; never strip it).
|
|
* 5. Preserve `text`, `type`, and `content` order exactly.
|
|
* 6. Never mutate the input.
|
|
*/
|
|
export declare function canonicalizeContent(node: any): any;
|
|
/**
|
|
* True when two ProseMirror documents are semantically equal: equal after
|
|
* canonicalization (block ids stripped, absent-vs-default-null normalized).
|
|
*/
|
|
export declare function docsCanonicallyEqual(a: any, b: any): boolean;
|