e3296104a6
承階段一之下游審計。核心貫穿問題:「透明穿越」判定實有兩套口徑散落各處,抵觸 finder 檔頭「所有遍歷共用同一判定」之聲明。用戶抉擇:**嚴格白名單**(未知行內標籤=邊界, 透明須顯式登記 styleInlines)。 透明判定單一真相源(2a): ・transparentInline 提升為公開 isTransparent,作邏輯文本流之單一透明判定。 ・collectRuns 改由 isTransparent 判定——未在 styleInlines 之未知行內標籤(如 <button>/自訂 元素)當隔離式邊界(斷 run、內部自成脈絡);isolate 與未知行內併為同一分支。 ・jiyaAdjacency 同改用 finder.isTransparent;adjacentLogicalChar 沿用(僅隨改名)。 ・分層澄清(承 #4 教訓,不強行一統):邏輯文本流統一為 isTransparent;另兩層各有正當之 不同邊界、刻意不併入——結構切分安全(split canSplit:更窄白名單,<a>/ABBR 不可切)與 物理版面(lineedge:getClientRects 物理相鄰,須跨 isolate 找真實鄰接)。檔頭改分層表述。 跨透明元素邊界避頭尾綁定(2b,修下游審計 #3): ・避頭類標點若落於透明元素邊緣(「你好<strong>。世界</strong>」之 。位於 strong 首位、與 「好」不同 DOM parent),舊版 forbiddenBreak 僅認直接 jz-char、render 僅處理 jz-char 之直接 父(strong),外層 p 之「好↔strong」綁定從不被評估 → 。漏綁、可誤置行首。 ・偵測:edgeCharEl 經 finder.isTransparent 穿越透明元素定位邊緣 jz-char。 ・父級處理:render 沿透明元素邊緣上攀納入外層 parent,父集深者先處理。綁定端沿用 isolateBoundaryToken(可切則最小綁定;邊界字為已 charify 之 jz-char 無法越過時退化整綁, 安全、與 <a> 同型)。 avoid 排除機制歸一(2c): ・isAvoided 改單一組合入口(自身即邊界 或 祖先鏈任一邊界),免除「avoidsSelf ‖ isAvoided」 易漏一半之誤用(階段一 #2 即此類);avoidsSelf 保留供遍歷原語逐元素下探自判(免 O(n²))。 ・processPills/orphan/spacing root 收斂為 isAvoided(x);doc 補齊七種 avoid 來源與優先序。 一致性小項(2e):scope.include 型別去多餘 `| null`;PASSES 陣列補註(執行序由 pass.order 分群排序決定);gapTrim 補 featureEnabledFor("spacing"),與 lineEdge relayout 逐節點閘對稱。 評估後不做(2d):五處幂等判斷(jiya 祖先/longword 父/spacing 父/orphan 子/jinze 父)檢查 不同位置關係、無單一 isJz 形狀可全覆蓋;真正缺陷(jinze 二次 render 巢狀)已於階段一以 isJz 修復,其餘各自正確,強行歸一徒增風險(承 #4 教訓:正當差異不硬併)。 新增契約/回歸測試(button 嚴格白名單、跨透明邊界避頭);121 測試全綠、構建乾淨。
110 lines
6.8 KiB
TypeScript
110 lines
6.8 KiB
TypeScript
import type { FeatureLevel, ResolvedOptions } from "../types.js";
|
||
/** 邏輯 run 中之單一字元來源位置。 */
|
||
export interface CharPos {
|
||
textNode: Text;
|
||
offset: number;
|
||
}
|
||
/** 一段邏輯文本:剝離樣式後之連續字元,及其逐字回映射。 */
|
||
export interface LogicalRun {
|
||
text: string;
|
||
map: CharPos[];
|
||
}
|
||
/** pill 鄰接之邏輯鄰字。 */
|
||
export interface AdjacentChar {
|
||
textNode: Text;
|
||
offset: number;
|
||
ch: string;
|
||
}
|
||
export declare class Finder {
|
||
private readonly opts;
|
||
private readonly styleSet;
|
||
private readonly blockSet;
|
||
private readonly skipSet;
|
||
private readonly pillSelector;
|
||
private readonly isolateSelector;
|
||
private readonly avoidSelector;
|
||
private readonly includeSelector;
|
||
private readonly skipAttr;
|
||
private readonly userIsSkipped;
|
||
private readonly levelTextSelector;
|
||
private readonly featureCache;
|
||
private readonly levelCache;
|
||
constructor(opts: ResolvedOptions);
|
||
/** 該元素是否匹配 pill 選擇器(三分類之「整體」:code/kbd/行內公式等)。 */
|
||
pillMatches(el: Element): boolean;
|
||
/** 該元素是否匹配 isolate 選擇器(三分類之「隔離」:帶盒樣式之行內,如背景色
|
||
* <mark>)。邊界口徑同 pill(斷 run/斷相鄰/不可切分/兩端補隙),內部照常處理。 */
|
||
isolateMatches(el: Element): boolean;
|
||
/** 節點是否位於 pill **內部**(僅查祖先,不含自身)。pill 為整體元素:內部對
|
||
* 一切 pass 不可見——不 charify、不收 run、不切分、不於其內插間隙(下游問題六:
|
||
* .katex 內部曾被 jiya/spacing 直接變更)。 */
|
||
insidePill(node: Node): boolean;
|
||
/** 邏輯文本應**透明穿越**之行內元素:樣式行內標籤,以及聚珍自身之 wrap 類
|
||
* jz-*(jz-hws 間隙、jz-jinze 禁則群組、jz-char/jz-inner 標點原子)。穿越這些
|
||
* 才能正確找到跨包裝之邏輯鄰字(如 jinze 已把 pill 納入 jz-jinze 後,pill 之左
|
||
* 鄰字仍須可達;I7)。
|
||
* ⚠ 以**元素**而非標籤名判定:pill/isolate/avoid 縱使標籤名在樣式集亦為邊界、
|
||
* 不可穿越(下游問題六:KaTeX 全樹皆 SPAN,名字判定令整棵公式被當透明下潛而
|
||
* 肢解;scope.avoid/skipAttribute 命中自身者同理)。
|
||
* ⚠ jz-char/jz-inner 必須透明:否則 adjacentLogicalChar 之 descend 遇標點原子既
|
||
* 不進入亦不終止、而是**跳過**它續找更前之兄弟(下游 Bug:`汉字。<code>` 經 jinze
|
||
* 綁定為 `汉<jz-jinze>字<jz-char>。</jz-char></jz-jinze><code>`,pill 之左鄰字應
|
||
* 為「。」、不補間隙;舊邏輯卻越過 jz-char 取到「字」→ 誤包 jz-hws 於「字。」之間)。
|
||
* jz-char 僅含標點(jiya 只 charify biaodian),標點非 pillNeighbor,故透明後 descend
|
||
* 回傳標點 → 不補隙,與 collectRuns 之既有透明遞迴一致。jz-inner 亦須列入,否則
|
||
* descend 進入 jz-char 後因 jz-inner 不透明而跳過其內標點。 */
|
||
isTransparent(el: Element): boolean;
|
||
/** 該元素**自身**是否為 avoid 邊界。avoid 之七種來源,依序短路判定、任一命中即是:
|
||
* ① isSkipped 謂詞(消費端函數) ② skipTags 標籤名單(PRE/SAMP/SCRIPT…,可覆寫)
|
||
* ③ SVG 命名空間 ④ contentEditable
|
||
* ⑤ data-jz-skip 屬性(內建) ⑥ skipAttribute(消費端指定屬性名)
|
||
* ⑦ scope.avoid 選擇器
|
||
* **此為自身判定**,供遍歷原語(collectRuns/jiyaAdjacency/canSplit/isTransparent)於
|
||
* 下探時逐元素自判(祖先由遞迴涵蓋)。**一次性**問「某節點是否被 avoid(自身或祖先)」
|
||
* 請改用 isAvoided(單一組合入口),勿只用本方法而漏判祖先、或只用 isAvoided 而漏判自身
|
||
* (下游問題六/階段一 #2:漏一半致 avoid 對自身形同虛設)。 */
|
||
avoidsSelf(el: Element): boolean;
|
||
/** 某節點是否被 avoid——**自身即邊界**(元素經 avoidsSelf 之七源;非元素節點僅判
|
||
* isSkipped)**或**祖先鏈上任一為 avoid 邊界。此為「是否 avoid」之**單一組合入口(安全
|
||
* 預設)**:一次性檢查用此,免除「avoidsSelf ‖ isAvoided」易漏一半之誤用。遍歷原語逐
|
||
* 元素下探時則用 avoidsSelf(僅自身,祖先由遞迴涵蓋)。 */
|
||
isAvoided(node: Node): boolean;
|
||
/** scope.include 啟用判定:未設則恆 true;設則須有命中祖先(opt-in)。 */
|
||
inScope(node: Node): boolean;
|
||
/** 走訪 root 下所有「可處理」文本節點(已過濾 avoid / pill 內部 / 非作用域)。 */
|
||
eachTextNode(root: Element, cb: (node: Text) => void): void;
|
||
/** 走訪 root 下所有 block 元素(含 root 本身若為 block)。 */
|
||
eachBlock(root: Element, cb: (block: Element) => void): void;
|
||
/**
|
||
* 收集 block 之邏輯文本 run(架構 §4.1,I7):透明行內(isTransparent:styleInlines
|
||
* + wrap 類 jz-*)穿越、run 延續;block/pill/avoid 中斷 run;isolate 與**未知行內
|
||
* 標籤**(嚴格白名單)中斷 run 且內部自成獨立 run。回傳 text.length >= 2 之 run。
|
||
*/
|
||
collectRuns(block: Element): LogicalRun[];
|
||
/**
|
||
* pill 之邏輯鄰字(架構 §4.1):經樣式鏈遞迴,遇 pill/block/avoid/間隙
|
||
* marker 即止。direction = -1 取前鄰字,+1 取後鄰字。
|
||
*/
|
||
adjacentLogicalChar(el: Element, direction: -1 | 1): AdjacentChar | null;
|
||
/**
|
||
* 節點之功能級別(§6.5.0a)。自 node 向上找**最近**之顯式信號:元素屬性
|
||
* `data-jz-level="text|paragraph"`(最優先),或命中 `level.text` 選擇器(→ text);
|
||
* 皆無則預設 paragraph(全功能)。結果以解析後之元素為鍵快取。
|
||
*/
|
||
levelFor(node: Node): FeatureLevel;
|
||
/**
|
||
* 某級別之 pass 是否可作用於該節點(§6.5.0a gate)。文本級 pass 不受限(恆 true);
|
||
* 段落級 pass 僅作用於段落級元素(text-level 子樹跳過)。與 featureEnabledFor 疊加:
|
||
* level 為粗粒度語義組(先判),blocks/屬性為細粒度逐功能(後調)。
|
||
*/
|
||
levelAllows(node: Node, passLevel: FeatureLevel): boolean;
|
||
/**
|
||
* 解析節點對某功能之有效啟用狀態(§3.6,per-node 閘)。向上找最近帶
|
||
* 功能指令之祖先(data-juzhen 白名單 / data-juzhen-off 黑名單 / 命中
|
||
* blocks 選擇器),無則回退全域 features。結果以元素為鍵快取。
|
||
*/
|
||
featureEnabledFor(node: Node, name: string): boolean;
|
||
private globalFeature;
|
||
private resolveFeature;
|
||
}
|