Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
39 lines
1.4 KiB
JavaScript
39 lines
1.4 KiB
JavaScript
// Module-supplied content is DATA, never markup.
|
|
//
|
|
// asText is the only way text reaches the DOM in this kit. It does not parse,
|
|
// sanitise or escape -- it refuses anything that is not a scalar, so "markup"
|
|
// is not a state the kit can be in. That is a stronger guarantee than escaping,
|
|
// which is a thing you can forget to do in one place.
|
|
|
|
const SCALAR = new Set(["string", "number", "boolean"]);
|
|
|
|
export function asText(value) {
|
|
if (value == null) return document.createTextNode("");
|
|
if (!SCALAR.has(typeof value)) {
|
|
throw new TypeError(
|
|
`Composer content must be a string, number or boolean; got ${describe(value)}. ` +
|
|
"Elements take data, not nodes or markup."
|
|
);
|
|
}
|
|
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
throw new TypeError(`Composer content must be a finite number; got ${value}.`);
|
|
}
|
|
return document.createTextNode(String(value));
|
|
}
|
|
|
|
/** Replace a node's content with `value`, rendered as text. */
|
|
export function setText(node, value) {
|
|
while (node.firstChild) node.removeChild(node.firstChild);
|
|
node.appendChild(asText(value));
|
|
return node;
|
|
}
|
|
|
|
function describe(value) {
|
|
if (typeof value === "object" && value !== null) {
|
|
if (typeof value.nodeType === "number") return `a DOM node (<${value.nodeName?.toLowerCase()}>)`;
|
|
if (Array.isArray(value)) return "an array";
|
|
return "an object";
|
|
}
|
|
return `a ${typeof value}`;
|
|
}
|