cli-jaw 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ // CJK bold fix — CommonMark 6.2 right-flanking workaround
2
+ // Pure function, no browser dependencies — importable from Node.js tests.
3
+ //
4
+ // Problem: When closing ** is preceded by Unicode punctuation (e.g. ) . ! ?)
5
+ // and followed by a non-space non-punctuation char (e.g. CJK), CommonMark
6
+ // rejects it as right-flanking → bold fails to render.
7
+ //
8
+ // Fix: Insert ZWSP between the punctuation and ** so the parser sees **
9
+ // as preceded by non-punctuation (ZWSP is Cf, not Zs/P*).
10
+
11
+ export function fixCjkPunctuationBoundary(text: string): string {
12
+ // 1. Preserve fenced code blocks and inline code spans
13
+ const preserved: string[] = [];
14
+ let processed = text
15
+ .replace(/```[\s\S]*?```/g, (m) => {
16
+ preserved.push(m);
17
+ return `\x00P${preserved.length - 1}\x00`;
18
+ })
19
+ .replace(/`[^`]+`/g, (m) => {
20
+ preserved.push(m);
21
+ return `\x00P${preserved.length - 1}\x00`;
22
+ });
23
+
24
+ // 2. Insert ZWSP between punctuation (excluding *) and closing **
25
+ // when followed by non-space non-punctuation character
26
+ processed = processed.replace(
27
+ /([\p{P}])\*\*(?=[^\s\p{P}])/gu,
28
+ (m, punct) => (punct === '*' ? m : punct + '\u200B**'),
29
+ );
30
+
31
+ // 3. Restore preserved spans
32
+ processed = processed.replace(
33
+ /\x00P(\d+)\x00/g,
34
+ (_, i) => preserved[Number(i)],
35
+ );
36
+
37
+ return processed;
38
+ }
@@ -3,6 +3,7 @@
3
3
  // All libs loaded via CDN (defer), graceful fallback if unavailable
4
4
 
5
5
  import { t } from './features/i18n.js';
6
+ import { fixCjkPunctuationBoundary } from './cjk-fix.js';
6
7
 
7
8
  export function escapeHtml(str: string): string {
8
9
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
@@ -26,6 +27,8 @@ export function sanitizeHtml(html: string): string {
26
27
  .replace(/javascript\s*:/gi, 'about:blank');
27
28
  }
28
29
 
30
+
31
+
29
32
  // ── Orchestration JSON stripping ──
30
33
  function stripOrchestration(text: string): string {
31
34
  let cleaned = text.replace(/```json\n[\s\S]*?\n```/g, '');
@@ -195,7 +198,8 @@ export function renderMarkdown(text: string): string {
195
198
 
196
199
  let html: string;
197
200
  if (ensureMarked()) {
198
- html = marked.parse(cleaned) as string;
201
+ const fixed = fixCjkPunctuationBoundary(cleaned);
202
+ html = marked.parse(fixed) as string;
199
203
  // Wrap tables for horizontal scrolling
200
204
  html = html.replace(/<table/g, '<div class="table-wrapper"><table').replace(/<\/table>/g, '</table></div>');
201
205
  } else {