feat(content): add progressive Markdown to Lexical migration - #2777
Conversation
|
|
||
| // Inline code is ignored by custom-token and unsupported-construct scans. | ||
| const inlineCodePattern = /(`+)([^\n]*?)\1/g | ||
| for (const match of markdown.matchAll(inlineCodePattern)) { |
| pattern: RegExp, | ||
| callback: (match: RegExpMatchArray, span: SourceSpan) => void, | ||
| ) => { | ||
| for (const match of markdown.matchAll(pattern)) { |
| /\*\*[^*]+\*\*|__[^_]+__|~~[^~]+~~|==[^=]+==|\+\+[^+]+\+\+|`[^`]+`|\[[^\]]+\]\([^)]+\)|\{(?:GH|TW|TG)@|\$[^$]+\$/.test( | ||
| value, | ||
| ) |
SafeDep Report SummaryPackage Details
This report is generated by SafeDep Github App |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4f4b57835b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await acquireContentFormatTransitionLock(tx, input) | ||
| const persisted = await this.lockSource(tx, input) |
There was a problem hiding this comment.
Coordinate ordinary source writes with the transition lock
When a normal Markdown save has already read the source before this transaction starts, it does not acquire this advisory lock or condition its repository update on the current format. If the migration commits first, the waiting normal PostRepository.update, NoteRepository.update, or PageRepository.update can subsequently write contentFormat: markdown over the Lexical source while the translations remain Lexical, breaking the atomic format invariant. All source writers need to participate in this lock or use a conditional update/revalidation after obtaining the row lock.
Useful? React with 👍 / 👎.
|
|
||
| scanPattern( | ||
| // eslint-disable-next-line unicorn/better-regex -- Escaped delimiters avoid non-Unicode parsing ambiguities. | ||
| /(?:\[([^\]\n]*)\])?\{(GH|TW|TG)@(\w+)\}[ \t]?/g, |
There was a problem hiding this comment.
Honor Markdown escapes before replacing mention tokens
For Markdown containing an escaped literal such as \{GH@alice}, this pattern still matches the text beginning at { and replaces it with a mention node, leaving only the preceding backslash as text. The dry run therefore reports the document as convertible even though publishing changes a deliberately escaped literal into a rich mention; the custom-token scans should skip delimiters preceded by an active Markdown escape.
Useful? React with 👍 / 👎.




Summary
Why
Existing non-empty Markdown documents could not switch formats. This change permits progressive migration when every syntax region in the active migration unit has a behavior-preserving mapping, while keeping unsupported documents in Markdown with actionable diagnostics.
Impact
Supported documents can be staged as Lexical without publishing immediately. Publishing the staged document commits the source and existing AI translations as one guarded transition; unsupported syntax remains unchanged.
Validation
pnpm -C packages/editor exec vitest run test/markdown-conversion.test.ts— 8 tests passedpnpm -C apps/core exec vitest run ...content-migration... note.service.spec.ts post.service.spec.ts— 25 tests passedpnpm -C apps/core exec vitest run test/src/modules/ai/ai-translation.repository.pg.e2e.spec.ts— 3 tests passed