'use strict'; // adapted from https://github.com/jridgewell/string-dedent var getBuiltIn = require('../internals/get-built-in'); var uncurryThis = require('../internals/function-uncurry-this'); var fromCharCode = String.fromCharCode; var fromCodePoint = getBuiltIn('String', 'fromCodePoint'); var charAt = uncurryThis(''.charAt); var charCodeAt = uncurryThis(''.charCodeAt); var stringIndexOf = uncurryThis(''.indexOf); var stringSlice = uncurryThis(''.slice); var ZERO_CODE = 48; var NINE_CODE = 57; var LOWER_A_CODE = 97; var LOWER_F_CODE = 102; var UPPER_A_CODE = 65; var UPPER_F_CODE = 70; var isDigit = function (str, index) { var c = charCodeAt(str, index); return c >= ZERO_CODE && c <= NINE_CODE; }; var parseHex = function (str, index, end) { if (end >= str.length) return -1; var n = 0; for (; index < end; index++) { var c = hexToInt(charCodeAt(str, index)); if (c === -1) return -1; n = n * 16 + c; } return n; }; var hexToInt = function (c) { if (c >= ZERO_CODE && c <= NINE_CODE) return c - ZERO_CODE; if (c >= LOWER_A_CODE && c <= LOWER_F_CODE) return c - LOWER_A_CODE + 10; if (c >= UPPER_A_CODE && c <= UPPER_F_CODE) return c - UPPER_A_CODE + 10; return -1; }; module.exports = function (raw) { var out = ''; var start = 0; // We need to find every backslash escape sequence, and cook the escape into a real char. var i = 0; var n; while ((i = stringIndexOf(raw, '\\', i)) > -1) { out += stringSlice(raw, start, i); // If the backslash is the last char of the string, then it was an invalid sequence. // This can't actually happen in a tagged template literal, but could happen if you manually // invoked the tag with an array. if (++i === raw.length) return; var next = charAt(raw, i++); switch (next) { // Escaped control codes need to be individually processed. case 'b': out += '\b'; break; case 't': out += '\t'; break; case 'n': out += '\n'; break; case 'v': out += '\v'; break; case 'f': out += '\f'; break; case 'r': out += '\r'; break; // Escaped line terminators just skip the char. case '\r': // Treat `\r\n` as a single terminator. if (i < raw.length && charAt(raw, i) === '\n') ++i; // break omitted case '\n': case '\u2028': case '\u2029': break; // `\0` is a null control char, but `\0` followed by another digit is an illegal octal escape. case '0': if (isDigit(raw, i)) return; out += '\0'; break; // Hex escapes must contain 2 hex chars. case 'x': n = parseHex(raw, i, i + 2); if (n === -1) return; i += 2; out += fromCharCode(n); break; // Unicode escapes contain either 4 chars, or an unlimited number between `{` and `}`. // The hex value must not overflow 0x10FFFF. case 'u': if (i < raw.length && charAt(raw, i) === '{') { var end = stringIndexOf(raw, '}', ++i); if (end === -1) return; n = parseHex(raw, i, end); i = end + 1; } else { n = parseHex(raw, i, i + 4); i += 4; } if (n === -1 || n > 0x10FFFF) return; out += fromCodePoint(n); break; default: if (isDigit(next, 0)) return; out += next; } start = i; } return out + stringSlice(raw, start); };