()
| 741 | } |
| 742 | |
| 743 | function readQuotedValue(): string { |
| 744 | const quoteCode = input.charCodeAt(pos); |
| 745 | if (quoteCode !== CC_DQUOTE && quoteCode !== CC_SQUOTE) { |
| 746 | error("Expected quote to start attribute value"); |
| 747 | } |
| 748 | const quoteChar = input[pos]!; |
| 749 | const start = pos + 1; |
| 750 | |
| 751 | const closeIdx = input.indexOf(quoteChar, start); |
| 752 | if (closeIdx === -1) { |
| 753 | pos = len; |
| 754 | error("Unterminated attribute value"); |
| 755 | } |
| 756 | |
| 757 | const raw = input.slice(start, closeIdx); |
| 758 | |
| 759 | // Validate: '<' not allowed in attribute values (XML 1.0 §3.1) |
| 760 | if (raw.includes("<")) { |
| 761 | // Find exact position for error reporting |
| 762 | pos = start + raw.indexOf("<"); |
| 763 | error("Cannot use '<' in attribute value"); |
| 764 | } |
| 765 | |
| 766 | pos = closeIdx + 1; |
| 767 | |
| 768 | // Normalize whitespace (§3.3.3) and decode entities |
| 769 | return decodeEntities(raw.replace(/[\t\n]/g, " "), xml11); |
| 770 | } |
| 771 | |
| 772 | function readText(): string { |
| 773 | const start = pos; |
no test coverage detected