(name: string, value: string | null)
| 108 | ]); |
| 109 | |
| 110 | function validateSetAttribute(name: string, value: string | null): void { |
| 111 | const lower = name.toLowerCase(); |
| 112 | if (RESERVED_ATTRS.has(lower)) { |
| 113 | throw new Error( |
| 114 | `setAttribute: "${name}" is a reserved composition attribute and cannot be reassigned. ` + |
| 115 | `Use the appropriate typed method (setTiming, setHold, etc.) instead.`, |
| 116 | ); |
| 117 | } |
| 118 | if (lower.startsWith("on")) { |
| 119 | throw new Error( |
| 120 | `setAttribute: event-handler attributes ("${name}") are not permitted — ` + |
| 121 | `they produce executable HTML that cannot be safely serialized.`, |
| 122 | ); |
| 123 | } |
| 124 | if (value !== null && URI_BEARING_ATTRS.has(lower)) { |
| 125 | const trimmed = value.trim(); |
| 126 | if (DANGEROUS_URI_SCHEMES.test(trimmed) || DANGEROUS_DATA_URI.test(trimmed)) { |
| 127 | throw new Error(`setAttribute: unsafe URI value for "${name}".`); |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | export class UnsupportedOpError extends Error { |
| 133 | // Stable error code — part of the public API contract (F7); hosts switch on |
no outgoing calls
no test coverage detected