mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-09-21 01:35:57 +00:00
refactor(markdown-editor): rename Faithful* -> Tuned* (createTunedMarked etc.)
"faithful" connoted a byte-faithful round-trip, but the editor now deliberately normalizes some cases toward GFM (bare URLs autolink, named entities decode), so the output is no longer byte-exact. "tuned" names what the code actually does — tune marked's tokenizers + the code-block/table serializers for our content — without claiming a fidelity property the output no longer guarantees. Pure rename (createFaithfulMarked/FaithfulMarkdownText/parse+renderFaithfulCodeBlock/ StarterKitFaithful -> Tuned), no behavior change; 834 tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e4f80badd4
commit
a858d81cea
@@ -223,7 +223,7 @@ describe('nesting & sequencing — content preserved and converges (≤2 saves)'
|
||||
|
||||
// A code block nested in a list (ordered > bullet > code) has an indented opening fence, so
|
||||
// @tiptap/extension-code-block's `startsWith('```')` gate used to drop it — the same root cause as a
|
||||
// top-level indented fence, fixed by parseFaithfulCodeBlock (see markdown-editor-extensions.ts). This was
|
||||
// top-level indented fence, fixed by parseTunedCodeBlock (see markdown-editor-extensions.ts). This was
|
||||
// once a pinned KNOWN-BUG test asserting the loss; the fix now keeps the code.
|
||||
describe('ordered > bullet > code — indented nested code survives', () => {
|
||||
it('keeps the deeply-nested code block', () => {
|
||||
|
||||
@@ -37,7 +37,7 @@ const longestBacktickRun = (text: string): number =>
|
||||
// contains a ``` line (a doc demonstrating fenced markdown — common in knowledge/prompt examples) re-parses as
|
||||
// TWO blocks on the next load: the inner fence closes the outer one. CommonMark requires the fence to be longer
|
||||
// than any backtick run inside — widen it. Otherwise identical to upstream.
|
||||
const renderFaithfulCodeBlock = (node: MarkdownRenderNode, h: MarkdownRenderHelpers): string => {
|
||||
const renderTunedCodeBlock = (node: MarkdownRenderNode, h: MarkdownRenderHelpers): string => {
|
||||
const language = node.attrs?.language || '';
|
||||
|
||||
if (!node.content) {
|
||||
@@ -55,7 +55,7 @@ const renderFaithfulCodeBlock = (node: MarkdownRenderNode, h: MarkdownRenderHelp
|
||||
// token whose `raw` starts with that whitespace, the gate rejects it, and the block is dropped on load. When
|
||||
// a document mixes fences at different indents the mis-detection cascades and everything after the first
|
||||
// dropped fence vanishes too. Trim the leading indent before the gate; otherwise identical to upstream.
|
||||
const parseFaithfulCodeBlock = (token: MarkdownCodeToken, helpers: MarkdownParseHelpers): unknown => {
|
||||
const parseTunedCodeBlock = (token: MarkdownCodeToken, helpers: MarkdownParseHelpers): unknown => {
|
||||
const fence = token.raw?.trimStart() ?? '';
|
||||
|
||||
if (!fence.startsWith('```') && !fence.startsWith('~~~') && token.codeBlockStyle !== 'indented') {
|
||||
@@ -74,7 +74,7 @@ const parseFaithfulCodeBlock = (token: MarkdownCodeToken, helpers: MarkdownParse
|
||||
// `__init__`/`_word_` would emphasize (→ `**init**`/`*word*`) while the same text loaded stays literal,
|
||||
// breaking identifiers. Drop only the underscore rules (their `find` regex mentions `_`; the `*` rules stay)
|
||||
// so typing matches load. codeBlock gets the indented-fence fix above. (Underline off below.)
|
||||
const StarterKitFaithful = StarterKit.extend({
|
||||
const StarterKitTuned = StarterKit.extend({
|
||||
addExtensions() {
|
||||
return (this.parent?.() ?? []).map((extension) => {
|
||||
if (extension.name === 'bold' || extension.name === 'italic') {
|
||||
@@ -90,8 +90,8 @@ const StarterKitFaithful = StarterKit.extend({
|
||||
|
||||
if (extension.name === 'codeBlock') {
|
||||
return extension.extend({
|
||||
parseMarkdown: parseFaithfulCodeBlock,
|
||||
renderMarkdown: renderFaithfulCodeBlock,
|
||||
parseMarkdown: parseTunedCodeBlock,
|
||||
renderMarkdown: renderTunedCodeBlock,
|
||||
} as Parameters<typeof extension.extend>[0]);
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ const StarterKitFaithful = StarterKit.extend({
|
||||
// symmetric with the marked layer (which no longer neutralises autolink/url). Do NOT set false: it
|
||||
// diverges typing from load and re-freezes bare URLs as text.
|
||||
export const createMarkdownExtensions = (placeholder?: string) => [
|
||||
StarterKitFaithful.configure({
|
||||
StarterKitTuned.configure({
|
||||
codeBlock: { HTMLAttributes: { class: 'hljs' } },
|
||||
link: { autolink: true, linkOnPaste: true },
|
||||
underline: false,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Marked } from 'marked';
|
||||
// that must survive verbatim; marked silently swallows the ones whose names match real HTML elements
|
||||
// (`<input>`, `<br>`, …). Neutralising marked's block (`html`) and inline (`tag`) HTML tokenizers makes
|
||||
// every `<...>` fall through to plain text, recreating markdown-it's `html: false`.
|
||||
const createFaithfulMarked = () => {
|
||||
const createTunedMarked = () => {
|
||||
const instance = new Marked();
|
||||
|
||||
instance.use({
|
||||
@@ -41,7 +41,7 @@ const createFaithfulMarked = () => {
|
||||
return instance;
|
||||
};
|
||||
|
||||
// The serialize-side counterpart to createFaithfulMarked. @tiptap/markdown's MarkdownManager
|
||||
// The serialize-side counterpart to createTunedMarked. @tiptap/markdown's MarkdownManager
|
||||
// .encodeTextForMarkdown HTML-entity-encodes text (`<` → `<`) and backslash-escapes ``` ` * _ [ ] ~ \ ```.
|
||||
// Both are wrong here: the load side keeps `\`+punct literal (escape tokenizer off), so re-escaping on save
|
||||
// would double every backslash; and named HTML entities are DECODED on load (`<`→`<`), so re-encoding
|
||||
@@ -49,8 +49,8 @@ const createFaithfulMarked = () => {
|
||||
// replace that one method with identity — save emits exactly the text the doc holds.
|
||||
type ManagerWithEncode = { encodeTextForMarkdown: (text: string) => string };
|
||||
|
||||
const FaithfulMarkdownText = Extension.create({
|
||||
name: 'faithfulMarkdownText',
|
||||
const TunedMarkdownText = Extension.create({
|
||||
name: 'tunedMarkdownText',
|
||||
onBeforeCreate() {
|
||||
const manager = this.editor.markdown as unknown as ManagerWithEncode | undefined;
|
||||
|
||||
@@ -86,6 +86,6 @@ export const MarkdownTable = Table.extend({
|
||||
});
|
||||
|
||||
export const createMarkdownLayer = () => [
|
||||
Markdown.configure({ marked: createFaithfulMarked() as unknown as typeof import('marked').marked }),
|
||||
FaithfulMarkdownText,
|
||||
Markdown.configure({ marked: createTunedMarked() as unknown as typeof import('marked').marked }),
|
||||
TunedMarkdownText,
|
||||
];
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('shouldParseMarkdownOnPaste — markdown-parse plain text, defer rich s
|
||||
});
|
||||
});
|
||||
|
||||
describe('MarkdownPaste — the parsed payload matches load (same faithful markdown layer)', () => {
|
||||
describe('MarkdownPaste — the parsed payload matches load (same tuned markdown layer)', () => {
|
||||
const pasteEvent = (text: string, html = ''): ClipboardEvent =>
|
||||
({
|
||||
clipboardData: {
|
||||
|
||||
Reference in New Issue
Block a user