c00fb3e482
下游需求:非段落/特定範圍元素用半角式(banjiao),段落用全角/開明。原標點樣式僅由 lang
決定(lang.policy/lang.style),無逐元素覆寫。新增與 data-jz-level/level.text 同構之逐元素樣式
機制(banjiao 渲染早已就緒,此為純路由、無新壓縮邏輯、無新 CSS)。
設置格式(供下游):
・HTML 屬性:data-jz-style="banjiao|kaiming|quanjiao"——標於元素或其祖先,該子樹用此樣式。
・選項:lang: { stylePolicy: [{ selector, style }] }——如
[{ selector: "h1,h2,button,.ui", style: "banjiao" }]。
・優先序:逐元素覆寫(近祖先勝、同層屬性優先於選擇器)> lang.policy > lang.style > 內建。
實作:resolveStyle 先查 resolveStyleOverride(自身及祖先鏈掃 data-jz-style 屬性/stylePolicy
選擇器命中),無則回退 lang。屬性值非法(拼錯)則忽略、續回退。types.ts 補 lang.stylePolicy
+導出 StyleRule;index.ts 正規化(stylePolicy 預設 [])。
冒烟三例通過(屬性 banjiao/選擇器 banjiao/屬性覆蓋選擇器);既有 121 測試無回歸(stylePolicy
預設空、行為不變)。回歸測試+文檔隨後補(e2e 階段)。
184 lines
8.0 KiB
TypeScript
184 lines
8.0 KiB
TypeScript
import type { Finder } from "./core/finder.js";
|
||
import type { LangClass, LocaleConfig, PunctStyle, StyleRule } from "./core/locale.js";
|
||
import type { Bias, BiasTable, BdSubclass, CharClassOverride, Ruleset } from "./core/unicode.js";
|
||
export type { LangClass, PunctStyle, StyleRule, Bias, BiasTable, BdSubclass, CharClassOverride, Ruleset };
|
||
/** 長英文詞包裝設定。 */
|
||
export interface LongWordOptions {
|
||
minLength?: number;
|
||
lang?: string;
|
||
}
|
||
/** 垂懸字避免設定(§6.5.1)。布林 true 等同 { chars: 2 }。 */
|
||
export interface OrphanOptions {
|
||
/** 段末行至少保留之 CJK 實義字數(標點/符號不計;預設 2)。 */
|
||
chars?: number;
|
||
}
|
||
/** 標點擠壓設定(架構 §6.3)。布林 true 等同 { halfWidth: "halt" }。 */
|
||
export interface JiyaOptions {
|
||
/** 半形渲染機制:
|
||
* - "halt"(預設)— 用字型 OpenType `halt`,由字型按字形正確定位,需字型支援;
|
||
* - "margin" — 負 margin 後備模式,供缺 halt 之字型,依字形偏側表收半形。 */
|
||
halfWidth?: "halt" | "margin";
|
||
/** margin 後備模式之字形偏側覆寫表(逐 lang 逐字),覆寫內建參考預設。
|
||
* halt 模式不讀此欄。 */
|
||
bias?: BiasTable;
|
||
}
|
||
/** 分塊功能選擇:選擇器 → 該塊內生效之功能集(覆寫全域)。 */
|
||
export interface BlockRule {
|
||
selector: string;
|
||
features: string[];
|
||
}
|
||
/** createJuzhen 之公開選項。所有欄位皆可選;預設見 normalizeOptions。 */
|
||
export interface JuzhenOptions {
|
||
/** 語言與全角/開明政策。 */
|
||
lang?: {
|
||
/** 無 lang 祖先時之預設語言標籤(預設 "zh-Hant")。 */
|
||
default?: string;
|
||
/** 全域標點擠壓預設:quanjiao(全角式)|kaiming(開明式)|
|
||
* banjiao(半角式)。覆寫內建逐語言預設,可被 policy 逐 lang/stylePolicy 逐元素覆寫。 */
|
||
style?: PunctStyle;
|
||
/** 逐 lang 覆寫。 */
|
||
policy?: Partial<Record<LangClass, PunctStyle>>;
|
||
/** **逐元素**覆寫標點樣式(優先於 lang/policy/style):選擇器命中之元素及其子樹
|
||
* 用指定樣式,如非段落/UI 元素用半角式 `[{ selector: "h1,h2,button,.ui", style: "banjiao" }]`。
|
||
* 與 HTML 屬性 `data-jz-style="banjiao|kaiming|quanjiao"` 同一機制;近祖先勝、屬性優先於選擇器。 */
|
||
stylePolicy?: StyleRule[];
|
||
};
|
||
/** 自定義字符分類(擴充內置規則集)。把未分類字符或新符號歸入中文/西文/
|
||
* 全寬標點各子類,以覆寫 spacing/jiya 等規則之分類判定(追加語義)。 */
|
||
charClass?: CharClassOverride;
|
||
/** 功能分級標記(§6.5.0a)。段落級功能(禁則/行端/懸掛/垂懸字/長詞斷字)
|
||
* 僅作用於段落級元素;文本級功能(中西間隙/標點擠壓)任意文本皆適用。
|
||
* - `text`:選擇器,命中之子樹**僅文本級**(標題/按鈕/UI 文字典型);亦可
|
||
* 經元素屬性 `data-jz-level="text"`/`"paragraph"` 標記(屬性優先、最近祖先勝)。
|
||
* 預設:塊級元素(blockTags)→ 段落級(全功能)。 */
|
||
level?: {
|
||
text?: string;
|
||
};
|
||
/** justify 原子化:jz-char/jz-jinze 是否以 inline-block 作對齊單一原子
|
||
* (預設 true)。設 false 改 display:inline——用於分頁器(如 Paged.js)之
|
||
* 對齊引擎會把每個 inline-block 邊界當伸縮點、與 CJK inter-ideograph 疊加
|
||
* 致窄欄散架之情形(halt 半形與 jinze nowrap 仍保留)。 */
|
||
justifyAtoms?: boolean;
|
||
/** 作用域限定(§3.6)。 */
|
||
scope?: {
|
||
root?: Element | string;
|
||
include?: string;
|
||
avoid?: string;
|
||
};
|
||
spacing?: boolean;
|
||
longWord?: boolean | LongWordOptions;
|
||
jiya?: boolean | JiyaOptions;
|
||
jinze?: boolean;
|
||
orphan?: boolean | OrphanOptions;
|
||
/** @deprecated 標點懸掛**已移除**(§6.5.6):純負 margin 機制經實測為機制級死路(寬度
|
||
* 守恆矛盾,CSS 接觸不到斷行器),原生 hanging-punctuation 為唯一正解但僅 Safari 支援、
|
||
* 且與本庫 inline-block 原子互斥。此選項仍被接受以保 API 相容,但**無任何效果**。 */
|
||
hanging?: boolean;
|
||
/** @reserved 標點修正(簡/繁正規化)——架構已預留(切片 #7),**當前無任何效果**。
|
||
* 注意:此為功能開關,與 `charClass.biaodian`(標點子類擴充表,語義完全不同)同名,勿混。 */
|
||
biaodian?: boolean;
|
||
/** @reserved 著重號/裝飾——架構已預留(切片 #8),**當前無任何效果**。 */
|
||
emphasis?: boolean;
|
||
/** @reserved Ruby/注音——架構已預留(切片 #8),**當前無任何效果**。 */
|
||
ruby?: boolean;
|
||
/** 分塊功能選擇(§3.6)。 */
|
||
blocks?: BlockRule[];
|
||
styleInlines?: string[];
|
||
blockTags?: string[];
|
||
skipTags?: string[];
|
||
/** 整體(pill)元素選擇器(預設 "code, kbd")。pill 之邊界口徑與 isolate 完全
|
||
* 相同(行為覆蓋),差異僅在內部不可見;同元素雙選擇器命中時 pill 勝出。 */
|
||
pillSelector?: string;
|
||
/** 內外隔離元素選擇器(預設 "mark")。傳 "" 停用(mark 回歸透明)。 */
|
||
isolateSelector?: string;
|
||
skipAttribute?: string;
|
||
isSkipped?: (node: Node) => boolean;
|
||
}
|
||
/** 正規化後之內部選項。 */
|
||
export interface ResolvedOptions {
|
||
locale: LocaleConfig;
|
||
/** 最終字符分類規則集(內置默認 + charClass 覆寫)。 */
|
||
ruleset: Ruleset;
|
||
justifyAtoms: boolean;
|
||
/** 功能分級之 text-level 選擇器(§6.5.0a);null 表示未設。 */
|
||
levelText: string | null;
|
||
scope: {
|
||
root: Element | string | null;
|
||
include: string | null;
|
||
avoid: string | null;
|
||
};
|
||
features: {
|
||
spacing: boolean;
|
||
longWord: boolean;
|
||
jiya: boolean;
|
||
jinze: boolean;
|
||
orphan: boolean;
|
||
biaodian: boolean;
|
||
emphasis: boolean;
|
||
ruby: boolean;
|
||
};
|
||
longWord: {
|
||
minLength: number;
|
||
lang: string;
|
||
};
|
||
/** 垂懸字避免設定(解析後)。 */
|
||
orphan: {
|
||
chars: number;
|
||
};
|
||
/** 擠壓半形渲染設定(halt 預設/margin 後備)。 */
|
||
jiyaConfig: {
|
||
halfWidth: "halt" | "margin";
|
||
bias: BiasTable;
|
||
};
|
||
blocks: BlockRule[];
|
||
finder: {
|
||
styleInlines: Set<string>;
|
||
blockTags: Set<string>;
|
||
skipTags: Set<string>;
|
||
pillSelector: string;
|
||
isolateSelector: string;
|
||
skipAttribute: string | null;
|
||
isSkipped: ((node: Node) => boolean) | null;
|
||
};
|
||
}
|
||
/** render/revert 之統一上下文(§3.3)。 */
|
||
export interface RenderContext {
|
||
root: Element;
|
||
options: ResolvedOptions;
|
||
finder: Finder;
|
||
}
|
||
/**
|
||
* charify 階段之包裝請求:把 node.data[start, end) 包進 build() 造出之元素。
|
||
* 同階段各 pass 之請求須互不重疊(標點/字母段天然不交集)。
|
||
*/
|
||
export interface WrapRequest {
|
||
start: number;
|
||
end: number;
|
||
build: (text: string) => HTMLElement;
|
||
pass: string;
|
||
}
|
||
/** pass 種類。 */
|
||
export type PassKind = "charify" | "standalone";
|
||
/** 功能分級(§6.5.0a):text=任意文本片段皆適用;paragraph=需行/段布局。 */
|
||
export type FeatureLevel = "text" | "paragraph";
|
||
interface BasePass {
|
||
name: string;
|
||
order: number;
|
||
kind: PassKind;
|
||
/** 功能分級(§6.5.0a)。paragraph 級 pass 對 text-level 元素自動跳過。 */
|
||
level: FeatureLevel;
|
||
enabled: (options: ResolvedOptions) => boolean;
|
||
revert: (ctx: RenderContext) => void;
|
||
}
|
||
/** 共享 P1 走訪之字元包裝 pass。 */
|
||
export interface CharifyPass extends BasePass {
|
||
kind: "charify";
|
||
collect: (node: Text, ctx: RenderContext) => WrapRequest[];
|
||
}
|
||
/** 自跑走訪/版面後處理之 pass。 */
|
||
export interface StandalonePass extends BasePass {
|
||
kind: "standalone";
|
||
render: (ctx: RenderContext) => void;
|
||
}
|
||
export type Pass = CharifyPass | StandalonePass;
|