4b2af3d34a
Аудит при подготовке #413 нашёл дрейфующие дубли между packages/mcp и packages/prosemirror-markdown. Четыре дедупа (поведение тулов не меняется): 1. node-ops: форк ~960 строк сведён в ОДНУ копию в prosemirror-markdown (живая mcp-версия — строгое надмножество замороженного #293-seed'а пакета; сверено по git-истории, новая пакет-копия байт-в-байт == прежней mcp-копии). Barrel-экспорт полной поверхности; mcp/client.ts/page-search.ts/transforms.ts/collaboration.ts импортируют из пакета; тесты переехали. node-ops тянет stripInlineMarkdown -> пакет-локальная text-normalize.ts несёт только этот примитив (mcp-версия — домен #408; заголовок документирует дубликацию + источник истины). 2. footnote-lex/footnote-analyze (vestigial legacy [^id]: диагностика): сведены к одному fence-aware предупреждению 'reference-style footnotes -> use ^[...]' (полезно для класса #410); footnote-lex удалён. 3. footnote-authoring -> примитивы (footnoteContentKey/makeFootnoteDefinition/ generateFootnoteId) перенесены в пакетный footnote.ts, одна реализация конвенции. 4. parse-node-arg -> перенесён в prosemirror-markdown (не mcp: сервер CommonJS не импортирует ESM-only @docmost/mcp, но нативно импортирует пакет), обе копии удалены, консьюмеры перенаправлены. canonicalizeFootnotes/ENFORCEMENT RULE #228 и comment-anchor/json-edit/text-normalize (mcp) не тронуты. API-поверхность node-ops оставлена чистой для #409/#413. closes #414 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
70 lines
2.4 KiB
JavaScript
70 lines
2.4 KiB
JavaScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
footnoteWarningsField,
|
|
hasLegacyFootnoteDefinition,
|
|
} from "../../build/lib/footnote-analyze.js";
|
|
|
|
// #414: the legacy footnote diagnostics were reduced to ONE advisory that fires
|
|
// on the PRESENCE of legacy reference-style `[^id]:` definition syntax (inert on
|
|
// import since #293), nudging the author to inline `^[...]` footnotes.
|
|
|
|
test("inline `^[...]` footnotes produce no warning", () => {
|
|
const md = "A note here.^[the body] and reuse elsewhere.^[the body]";
|
|
assert.equal(hasLegacyFootnoteDefinition(md), false);
|
|
assert.deepEqual(footnoteWarningsField(md), {});
|
|
});
|
|
|
|
test("no footnotes at all produce no warning", () => {
|
|
const md = "Just a paragraph with [a link](https://x) and no footnotes.";
|
|
assert.equal(hasLegacyFootnoteDefinition(md), false);
|
|
assert.deepEqual(footnoteWarningsField(md), {});
|
|
});
|
|
|
|
test("a legacy `[^id]:` definition triggers the single advisory", () => {
|
|
const md = ["See[^a].", "", "[^a]: defined"].join("\n");
|
|
assert.equal(hasLegacyFootnoteDefinition(md), true);
|
|
const field = footnoteWarningsField(md);
|
|
assert.equal(field.footnoteWarnings.length, 1);
|
|
assert.match(field.footnoteWarnings[0], /reference-style footnotes/i);
|
|
assert.match(field.footnoteWarnings[0], /\^\[footnote text\]/);
|
|
});
|
|
|
|
test("a bare `[^id]` reference (no definition line) is not flagged", () => {
|
|
// Only the definition syntax `[^id]:` is a reliable signal of legacy authoring;
|
|
// a lone `[^x]` in prose is too ambiguous to warn on.
|
|
const md = "A sentence mentioning [^x] with no definition.";
|
|
assert.equal(hasLegacyFootnoteDefinition(md), false);
|
|
assert.deepEqual(footnoteWarningsField(md), {});
|
|
});
|
|
|
|
test("legacy syntax inside a code fence is ignored (fence-aware)", () => {
|
|
const md = [
|
|
"Intro.",
|
|
"",
|
|
"```",
|
|
"Example[^demo]",
|
|
"[^demo]: not a real definition",
|
|
"```",
|
|
"",
|
|
"Outro with an inline note.^[real]",
|
|
].join("\n");
|
|
assert.equal(hasLegacyFootnoteDefinition(md), false);
|
|
assert.deepEqual(footnoteWarningsField(md), {});
|
|
});
|
|
|
|
test("a legacy definition OUTSIDE a fence still warns even with a fenced sample", () => {
|
|
const md = [
|
|
"```",
|
|
"[^demo]: example inside a fence",
|
|
"```",
|
|
"",
|
|
"See[^a].",
|
|
"",
|
|
"[^a]: real definition outside the fence",
|
|
].join("\n");
|
|
assert.equal(hasLegacyFootnoteDefinition(md), true);
|
|
assert.equal(footnoteWarningsField(md).footnoteWarnings.length, 1);
|
|
});
|