Files
cjk-autospace/test/participation-boundaries.test.mjs
T

248 lines
9.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import { test } from "node:test";
import { setupDom } from "./helpers.mjs";
import { createJuzhen } from "../dist/juzhen.mjs";
test("pill:塊本身與其後代塊的內部不進入 standalone pass", () =>
{
for (const html of [
'<main><div class="pill"><p>甲ABC乙,丙。</p></div><p>正常ABC,文字。</p></main>',
'<main><p class="pill">甲ABC乙,丙。</p><p>正常ABC,文字。</p></main>',
])
{
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const pill = document.querySelector(".pill");
const before = pill.innerHTML;
const jz = createJuzhen({ pillSelector: ".pill" });
try
{
jz.render(document.body);
assert.equal(pill.innerHTML, before, "pill 內部保持原樣");
assert.ok(document.querySelector("main > p:not(.pill) jz-hws"), "正常兄弟塊仍處理");
jz.revert(document.body);
assert.equal(pill.innerHTML, before);
}
finally { jz.disconnect(); dom.window.close(); }
}
});
const exclusions = [
[ "avoid", "data-jz-skip" ],
[ "text", 'data-jz-level="text"' ],
[ "off", 'data-juzhen-off="orphan jinze"' ],
[ "predicate", 'class="skip-text"' ],
];
const skippedText = (node) => node.nodeType === 3
&& node.parentElement?.classList.contains("skip-text");
test("jinze:排除或關閉段落功能的兩側不建立禁斷綁定", () =>
{
for (const [ label, attr ] of exclusions)
{
for (const side of [ "before-close", "after-open" ])
{
const protectedHtml = '<span ' + attr + '>自管</span>';
const html = side === "before-close"
? '<p>' + protectedHtml + ',正常文字。</p>'
: '<p>正常文字(' + protectedHtml + '</p>';
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const protectedEl = document.querySelector("span");
const jz = createJuzhen({ spacing: false, orphan: false, longWord: false,
isSkipped: skippedText });
try
{
jz.render(document.body);
assert.equal(protectedEl.closest("jz-jinze"), null, label + "/" + side);
assert.equal(protectedEl.innerHTML, "自管");
jz.revert(document.body);
assert.equal(document.body.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
}
}
});
test("jinze:透明元素內的排除內容不可被整元素退化綁定帶入", () =>
{
const html = '<p><a href="#">甲<span data-jz-skip>自管</span>乙</a>,正常。</p>';
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const protectedEl = document.querySelector("[data-jz-skip]");
const jz = createJuzhen({ spacing: false, orphan: false, longWord: false });
try
{
jz.render(document.body);
assert.equal(protectedEl.closest("jz-jinze"), null);
jz.revert(document.body);
assert.equal(document.body.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
});
test("jinze:註解與空 Text 不阻斷禁則,回退保留註解身份和次序", () =>
{
const html = '<p>甲<!--anchor-->,乙。</p>';
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const p = document.querySelector("p");
const anchor = p.childNodes[1];
const empty = document.createTextNode("");
p.insertBefore(empty, anchor);
const jz = createJuzhen({ spacing: false, orphan: false, longWord: false });
try
{
jz.render(p);
const group = p.querySelector("jz-jinze");
assert.equal(group.textContent, "甲,");
assert.ok(group.contains(anchor));
assert.ok(group.contains(empty));
jz.revert(p);
assert.equal(p.childNodes[1], anchor);
assert.equal(anchor.previousSibling.textContent, "甲");
assert.equal(anchor.nextSibling.textContent, ",乙。");
assert.equal(document.body.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
});
test("jinze:行內 render 根不把外部兄弟搬入生成群組", () =>
{
const html = '<p>甲<strong id="root">,乙。</strong>後文</p>';
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const root = document.getElementById("root");
const parent = root.parentNode;
const before = root.previousSibling;
const after = root.nextSibling;
const jz = createJuzhen({ spacing: false, orphan: false, longWord: false });
try
{
jz.render(root);
assert.equal(root.parentNode, parent);
assert.equal(root.previousSibling, before);
assert.equal(root.nextSibling, after);
assert.equal(parent.querySelectorAll(":scope > jz-jinze").length, 0);
jz.revert(root);
assert.equal(document.body.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
});
test("orphan:排除/text/off 的尾部內容不計數,也不包裹", () =>
{
for (const [ label, attr ] of exclusions)
{
const html = '<p>正常文字<span ' + attr + '>自管文字</span></p>';
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const jz = createJuzhen({ spacing: false, jiya: false, jinze: false, longWord: false,
isSkipped: skippedText });
try
{
jz.render(document.body);
assert.equal(document.querySelector("jz-orphan"), null, label + " 尾部是綁定邊界");
jz.revert(document.body);
assert.equal(document.body.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
}
});
test("orphan:只綁最後排除邊界之後的合資格末尾", () =>
{
for (const [ label, attr ] of exclusions)
{
for (const tail of [ "末", "最後" ])
{
const html = '<p>前文<span ' + attr + '>自管文字</span>' + tail + '</p>';
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const jz = createJuzhen({ spacing: false, jiya: false, jinze: false, longWord: false,
isSkipped: skippedText });
try
{
jz.render(document.body);
const orphan = document.querySelector("jz-orphan");
assert.equal(orphan?.textContent ?? null, tail === "末" ? null : tail, label + "/" + tail);
assert.equal(document.querySelector("span").closest("jz-orphan"), null);
jz.revert(document.body);
assert.equal(document.body.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
}
}
});
test("orphan:不可切容器不以整綁繞過排除邊界,可切容器只切合資格末尾", () =>
{
for (const tag of [ 'span', 'a href="#"' ])
{
const closeTag = tag.split(" ")[0];
const html = '<p>前文<' + tag + '><span data-jz-skip>自管</span>最後</' + closeTag + '></p>';
const { dom, document } = setupDom(html);
const original = document.body.innerHTML;
const protectedEl = document.querySelector("[data-jz-skip]");
const jz = createJuzhen({ spacing: false, jiya: false, jinze: false, longWord: false });
try
{
jz.render(document.body);
assert.equal(protectedEl.closest("jz-orphan"), null);
assert.equal(document.querySelector("jz-orphan")?.textContent ?? null,
closeTag === "span" ? "最後" : null);
jz.revert(document.body);
assert.equal(document.body.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
}
});
test("jinze:完整跨節點 base/VS/surrogate 原子一起綁到閉標點", () =>
{
for (const parts of [ [ "𠀀", "\u{E0100}" ], [ "\uD840", "\uDC00", "\uDB40", "\uDD00" ] ])
{
const { dom, document } = setupDom("<p></p>");
const p = document.querySelector("p");
p.append("前文");
const authors = parts.map((part) =>
{
const span = document.createElement("span");
span.textContent = part;
p.appendChild(span);
return span;
});
p.append(",");
const original = p.innerHTML;
const jz = createJuzhen({ spacing: false, orphan: false, longWord: false });
try
{
jz.render(p);
assert.equal(p.querySelector("jz-jinze").textContent, "𠀀\u{E0100},");
const rendered = p.innerHTML;
jz.render(p);
assert.equal(p.innerHTML, rendered);
jz.revert(p);
assert.equal(p.innerHTML, original);
assert.deepEqual(Array.from(p.querySelectorAll("span")), authors);
}
finally { jz.disconnect(); dom.window.close(); }
}
});
test("orphan:split surrogate 的補充平面字計為一個實義字", () =>
{
const { dom, document } = setupDom('<p>前文<strong>\uD840</strong><em>\uDC00</em>末</p>');
const p = document.querySelector("p");
const original = p.innerHTML;
const jz = createJuzhen({ spacing: false, jiya: false, jinze: false, longWord: false });
try
{
jz.render(p);
assert.equal(p.querySelector("jz-orphan").textContent, "𠀀末");
jz.revert(p);
assert.equal(p.innerHTML, original);
}
finally { jz.disconnect(); dom.window.close(); }
});