admin a5faec5abf feat: 補 ESM export { createCjkAutospace }
下游 Vite / Rollup / TypeScript 靜態 ESM 解析需要真正之 `export`
關鍵字;原 UMD-ish(module.exports + globalThis)對 ESM 消費端
仍須走副作用導入 + globalThis 取值之 workaround。

於檔尾既有 CJS / globalThis 兩塊後再加 `export { createCjkAutospace };
順序刻意如此,讓串接端(IIFE 函式體內不能有 module-level export)
只需以 `sed '/^export {/d'` 剝最後一行即安全。

four-form export 同時支援:ESM named import / CommonJS require /
globalThis / IIFE 串接(後者需剝 export 行)。README 同步補上。
2026-05-26 17:25:34 +08:00

cjk-autospace

CJK ↔ Latin / 數字 / 標點 / 引號 / 括號 / 運算子等邊界之自動間距 shim。Pangu.js v7.2.1 規則之 ES5 端口,加上「跨樣式標籤透明 + 行內塊邊界」兩 pass 架構,再加 Pass C 長英文段 <span lang> 包裝(讓瀏覽器原生連字斷詞)。工廠模式,由消費端注入配置。

詳細文檔 + Changelog 位於 docs 分支:架構解析、雙 pass 流程、整合範例見 index.html;變更記錄見 CHANGELOG.html。本機並列檢出:git worktree add ../cjk-autospace-docs docs

API

const autospace = createCjkAutospace({
    pillSelector: "code, kbd, .your-pill-class",
});
autospace.apply(document.body);

回傳 { apply(root?) }。冪等:在已注入 marker 之 DOM 上重跑會跳過既有 .cjk-autospace。完整選項見 cjk-autospace.d.ts

CSS 需求

.cjk-autospace {
    -webkit-user-select: none;
    user-select: none;
    /* 視覺寬度由消費端決定,例如 0.25em via inline-block + width */
}

user-select: none 讓選取與剪貼板跳過 markermarker 內含真實 ASCII spacelayout 視為 whitespace:行末 collapse、容許換行、justify 可拉伸)。

標籤三分類

  • STYLE_INLINES<strong> / <em> / <a> / <b> / <i> / <u> / <s> / <mark> / <ins> / <del> / <sub> / <sup> / <small> / <abbr> / <cite> / <dfn> / <q> / <span> / <var> / <samp> / <time> / <bdo> / <bdi> / <ruby> / <rb> / <rt> / <rp> / <wbr>)— shim 透明走過。跨樣式之 Pangu 邊界(如 <strong>是</strong> Neovim)由 Pass A 在剝離後識別。
  • PILL(由 pillSelector 指定,預設 code, kbd)— 行內塊。邊界由 Pass B 處理,與內容鄰接(CJK / 字母數字)即插 marker。
  • BLOCK<p> / <div> / <h1><h6> / <li> / <pre> / <table> / <br> / <hr> / …)— 段落級。Pass A 把它們當作 run 邊界,子 block 各自一次。

三 pass

  • Pass A — per-block Pangu on tag-stripped text:對每個 BLOCK 走 DFS 收集邏輯文本(STYLE 透明、PILL 與子 BLOCK 中斷 run、既有 marker 也中斷),整段套 panguSpace,把 MARK 反映射回 textNode/offset。MARK 對應原文若是單 ASCII space 則 strip 後插 marker,否則純插。actions 倒序執行確保前面偏移不被後面動作影響。

  • Pass B — pill boundary:對每個 PILL 透過 STYLE 鏈遞迴找邏輯鄰字(adjacentLogicalChar),鄰字若是 CJK / 字母數字直接插 marker;若是 1 個 ASCII space 且另一側為內容字則 strip 後插 marker;其餘(標點 / 多空格 / 換行 / 既有 marker)跳過。

  • Pass C — long English word wrap預設啟用longWordWrap: false 顯式關閉):將文本節點內所有 [A-Za-z]{N,}(預設 N=6)之長英文段包進 <span lang="en">。冪等:parent 已為 <span lang> 直接跳過。連字符不在 DOM,由瀏覽器 hyphens: auto 在斷行時純視覺渲染 → 選取 / 複製返回原文無污染。需消費端加 CSS:

    [lang|="en"] {
        hyphens: auto;
        -webkit-hyphens: auto;
        hyphenate-limit-chars: 6 3 3;  /* 詞長 / 斷點前 / 斷點後最少字符 */
    }
    

    不加 CSS 則 span 為惰性(DOM 變更但無視覺效果)。

配置選項

選項 預設 說明
pillSelector "code, kbd" 行內塊 CSS 選擇器
styleInlines 預設樣式標籤集 tagName 大寫之陣列
blockTags 預設段落標籤集 tagName 大寫之陣列
skipTags mono / form / script / style tagName 大寫之陣列;整 subtree skip
autospaceClass "cjk-autospace" marker span class 名
skipAttribute "data-md-key" 任一祖先帶此屬性即整 subtree skip
isSkipped (無) 自訂 skip callback;先於內建判定檢查
longWordWrap true(預設啟用) Pass C 開關。傳 false 顯式關閉;{minLength, lang} 自訂;true / 省略等同 {minLength: 6, lang: "en"}

模組形式

四種消費場景並存:

  • ES module / TypeScriptimport { createCjkAutospace } from "./cjk-autospace.js"(檔尾 export { createCjkAutospace },配 cjk-autospace.d.ts

  • CommonJS / Noderequire("./cjk-autospace.js").createCjkAutospace(檔尾 module.exports

  • Browser global:載入後可 globalThis.createCjkAutospace

  • IIFE 串接:把本檔內容 cat 進單一閉包(如 Claude 模板 build.sh / Nvim peek build hook)— export {…} 為 ESM module-level 語法,串入函式體內會語法錯誤,串接端須剝掉那行:

    sed '/^export[[:space:]]*{/d' cjk-autospace.js
    

    其餘 module.exports / globalThis 兩塊在閉包內安全(typeof 檢查不會 throw、globalThis 賦值無副作用)。

授權

基於 Pangu.js v7.2.1 的規則表 port原始項目 MIT)。

S
Description
No description provided
Readme 16 MiB
Languages
TypeScript 55.6%
JavaScript 37.4%
CSS 4.8%
Python 1.2%
HTML 1%