6dcc19ce59
git-sync's converter-core (src/lib) was a byte-identical duplicate of the new @docmost/prosemirror-markdown package (created in the previous commit). Switch git-sync to consume the package and delete its copy — ending the duplication that the whole #293 effort targets. Pure no-op: NO format/behavior change. - git-sync depends on @docmost/prosemirror-markdown (workspace:*); engine (stabilize/push/pull) + src/index barrel + 12 engine tests re-point their converter imports to the package. - Delete git-sync/src/lib (8 files) and the 23 duplicate converter-core test files + their fixtures — the converter and its ~440 tests now live once, in the package. git-sync keeps only its ENGINE tests, which exercise the converter through the package (the no-op proof). Kept roundtrip-helpers.ts (an engine test imports firstDivergence from it; pure helper, no double-run). - Added docmostExtensions to the package barrel (a kept engine schema-validity test needs it). Verified: editor-ext + prosemirror-markdown + git-sync all tsc EXIT 0; git-sync vitest 28 files, 268 passed, 0 failures (engine cycle/roundtrip/push/ pull/reconcile green = no-op proof); prosemirror-markdown vitest still 443 passed | 1 expected-fail; pnpm --frozen-lockfile EXIT 0; no ../lib refs remain in git-sync. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
58 lines
2.5 KiB
TypeScript
58 lines
2.5 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { getSchema } from "@tiptap/core";
|
|
|
|
import { markdownToProseMirror } from "@docmost/prosemirror-markdown";
|
|
import { docmostExtensions } from "@docmost/prosemirror-markdown";
|
|
|
|
// REGRESSION LOCK for the stripEmptyParagraphs schema-validity guard.
|
|
//
|
|
// markdownToProseMirror removes empty `paragraph` nodes that the import leaves
|
|
// behind when a block atom (e.g. a block image) is hoisted out of marked's
|
|
// wrapping <p> — they cause phantom blank-gap diffs on every sync. But several
|
|
// schema nodes REQUIRE non-empty block content (`content: "block+"`): tableCell,
|
|
// tableHeader, blockquote, column, callout, and the doc root. For an empty one of
|
|
// those, generateJSON materializes a single empty paragraph as its OBLIGATORY
|
|
// content. Stripping that would produce a schema-INVALID doc (`content: []`),
|
|
// which crashes any consumer that validates the public markdownToProseMirror
|
|
// output via ProseMirror's Node.check() / nodeFromJSON. The guard keeps one empty
|
|
// paragraph when removal would empty such a container; these tests pin that.
|
|
|
|
const schema = getSchema(docmostExtensions as any);
|
|
|
|
/** Throws if the JSON doc is not valid against the Docmost schema. */
|
|
function assertSchemaValid(doc: unknown): void {
|
|
schema.nodeFromJSON(doc).check();
|
|
}
|
|
|
|
describe("stripEmptyParagraphs keeps the import schema-valid", () => {
|
|
it("an empty GFM table cell round-trips to a schema-valid doc", async () => {
|
|
const doc = await markdownToProseMirror(
|
|
"| a | |\n|---|---|\n| x | y |\n",
|
|
);
|
|
expect(() => assertSchemaValid(doc)).not.toThrow();
|
|
});
|
|
|
|
it("an empty blockquote stays schema-valid", async () => {
|
|
const doc = await markdownToProseMirror("> \n");
|
|
expect(() => assertSchemaValid(doc)).not.toThrow();
|
|
});
|
|
|
|
it("an empty document stays schema-valid", async () => {
|
|
const doc = await markdownToProseMirror("\n\n");
|
|
expect(() => assertSchemaValid(doc)).not.toThrow();
|
|
});
|
|
|
|
it("still removes the empty hoist-artifact paragraph beside a block image", async () => {
|
|
const doc = await markdownToProseMirror("p\n\n\n\nq\n");
|
|
const emptyParas = ((doc as { content?: any[] }).content ?? []).filter(
|
|
(n: any) =>
|
|
n.type === "paragraph" &&
|
|
(!Array.isArray(n.content) || n.content.length === 0),
|
|
);
|
|
// The artifact paragraph must be gone (no phantom blank-gap on re-export)...
|
|
expect(emptyParas).toHaveLength(0);
|
|
// ...and the result is still a valid doc.
|
|
expect(() => assertSchemaValid(doc)).not.toThrow();
|
|
});
|
|
});
|