(str)
| 955 | * @throws {Error} on a malformed escape sequence, like the JS parser would |
| 956 | */ |
| 957 | const parseString = (str) => { |
| 958 | const q = str[0]; |
| 959 | |
| 960 | if (q !== '"' && q !== "'" && q !== "`") { |
| 961 | return null; |
| 962 | } |
| 963 | |
| 964 | const template = q === "`"; |
| 965 | const inner = str.slice(1, -1); |
| 966 | const len = inner.length; |
| 967 | let result = ""; |
| 968 | let i = 0; |
| 969 | |
| 970 | while (i < len) { |
| 971 | const ch = inner[i]; |
| 972 | if (ch !== "\\") { |
| 973 | // Template value normalizes raw <CR> and <CRLF> to <LF> |
| 974 | if (template && ch === "\r") { |
| 975 | result += "\n"; |
| 976 | i += inner[i + 1] === "\n" ? 2 : 1; |
| 977 | } else { |
| 978 | result += ch; |
| 979 | i++; |
| 980 | } |
| 981 | continue; |
| 982 | } |
| 983 | |
| 984 | i++; |
| 985 | if (i >= len) throw new Error("Unterminated escape sequence"); |
| 986 | const esc = inner[i]; |
| 987 | |
| 988 | if (esc === "x") { |
| 989 | const hex = inner.slice(i + 1, i + 3); |
| 990 | if (!/^[0-9a-fA-F]{2}$/.test(hex)) { |
| 991 | throw new Error("Invalid hexadecimal escape sequence"); |
| 992 | } |
| 993 | result += String.fromCharCode(Number.parseInt(hex, 16)); |
| 994 | i += 3; |
| 995 | } else if (esc === "u") { |
| 996 | if (inner[i + 1] === "{") { |
| 997 | // \u{N...} |
| 998 | const closeIdx = inner.indexOf("}", i + 2); |
| 999 | const codeStr = closeIdx === -1 ? "" : inner.slice(i + 2, closeIdx); |
| 1000 | const code = Number.parseInt(codeStr, 16); |
| 1001 | if (!/^[0-9a-fA-F]+$/.test(codeStr) || code > 0x10ffff) { |
| 1002 | throw new Error("Invalid Unicode escape sequence"); |
| 1003 | } |
| 1004 | result += String.fromCodePoint(code); |
| 1005 | i = closeIdx + 1; |
| 1006 | } else { |
| 1007 | // \uNNNN |
| 1008 | const hex = inner.slice(i + 1, i + 5); |
| 1009 | if (!/^[0-9a-fA-F]{4}$/.test(hex)) { |
| 1010 | throw new Error("Invalid Unicode escape sequence"); |
| 1011 | } |
| 1012 | result += String.fromCharCode(Number.parseInt(hex, 16)); |
| 1013 | i += 5; |
| 1014 | } |
no test coverage detected