CJK-friendly emphasis
Ensures bold and italic markers adjacent to CJK ideographs and kana are interpreted correctly.
CjkFriendlyPlugin is on by default. It post-processes the parsed markdown AST and re-tokenises emphasis flanking rules for CJK content. The same cjkFriendly gate also controls CjkAutolinkBoundaryPlugin, which prevents GFM bare URL autolinks from swallowing adjacent CJK text.
Why this exists
CommonMark's emphasis flanking rules treat CJK ideographs and kana as non-whitespace non-punctuation. This means a ** adjacent to CJK text — such as **テスト。**テスト — is not considered right-flanking by the base parser, and renders as literal stars instead of <strong>.
CjkFriendlyPlugin post-processes the parsed markdown AST and re-tokenises these cases. The result matches the intuitive expectation for Japanese, Chinese, and Korean content sites.
GFM autolink literals have a related boundary problem: a URL written flush against CJK text, such as 詳細はhttps:, can treat the trailing CJK run as part of the link. When cjkFriendly is enabled and gfm.autolinkLiteral is on, CjkAutolinkBoundaryPlugin splits the autolink at the first adjacent CJK character.
Behaviour
Default: always on. No configuration key required.
Opt-out (rare): set cjkFriendly: false in zfb.config.ts only when you need strict CommonMark/GFM output and your content has no CJK emphasis or bare-URL boundary cases:
import { defineConfig } from "zfb/config";
export default defineConfig({
markdown: {
cjkFriendly: false,
},
});Scope
This option handles:
**bold**and*italic*adjacent to CJK characters.GFM bare URL autolink boundaries adjacent to CJK characters, when
gfm.autolinkLiteralis enabled.Content reached through a secondary parse site — transcluded files (
:::include) and directive bodies re-parsed by the directive registry — now follows this setting too (#2398).
Literal * and ** repair can span supported parsed-inline siblings while preserving those nodes intact. For example:
知られる**[LA-2A](https://example.com)光学式コンプレッサー**と、**Neve 1073 EQ**というThe first strong span contains the preserved LA-2A link and 光学式コンプレッサー; the existing following strong span contains Neve 1073 EQ. Unsupported or opaque inline content remains a boundary.
GFM strikethrough (~~foo~~) does not need the toggle — markdown-rs's GFM tokeniser handles ~~ delimiter runs independently, so strikethrough works correctly at CJK boundaries in both modes.
Emphasis inside a directive body on the HTML render path
cjkFriendly re-tokenises the marker correctly, but a container directive body rendered through the HTML render path — renderHtml from @takazudo/zfb-md-wasm — reconstructs the directive's JSX body through a deliberately lossy stringifier that drops inline formatting. So this source:
:::note
これは**重要。**テスト
:::renders as:
<Note>これは重要。テスト</Note>No content is lost — every character of the body text survives, and only the <strong> wrapper is dropped. The same markers in ordinary prose render <p>これは<strong>重要。</strong>テスト</p>.
This is not specific to cjkFriendly, and not specific to collapsed (blank-line-less) directive bodies. Plain ASCII behaves identically with cjkFriendly off — :::note wrapping plain **bold** text renders <Note>plain bold text</Note> — and adding blank lines around the body does not change it. cjkFriendly only decides whether the ** is tokenised as emphasis at all; the HTML path's stringifier is what flattens it afterwards. With cjkFriendly: false the marker is never tokenised, so it stays literal ** instead.
Page builds are unaffected. zfb build compiles content through the MDX/JSX emit path, which renders the body recursively — the same source emits a nested <_.
Formatting-only loss is deliberate here. Content deletion on this path is treated as a bug instead: with hardBreaks enabled, a hard break inside a directive body used to vanish entirely and fuse the words on either side of it. That was fixed (zfb#2401) — such a break now renders as <br />.
See also
Customizing Markdown — full pipeline overview.