1 | 'use strict';
|
---|
2 | // adapted from https://github.com/jridgewell/string-dedent
|
---|
3 | var getBuiltIn = require('../internals/get-built-in');
|
---|
4 | var uncurryThis = require('../internals/function-uncurry-this');
|
---|
5 |
|
---|
6 | var fromCharCode = String.fromCharCode;
|
---|
7 | var fromCodePoint = getBuiltIn('String', 'fromCodePoint');
|
---|
8 | var charAt = uncurryThis(''.charAt);
|
---|
9 | var charCodeAt = uncurryThis(''.charCodeAt);
|
---|
10 | var stringIndexOf = uncurryThis(''.indexOf);
|
---|
11 | var stringSlice = uncurryThis(''.slice);
|
---|
12 |
|
---|
13 | var ZERO_CODE = 48;
|
---|
14 | var NINE_CODE = 57;
|
---|
15 | var LOWER_A_CODE = 97;
|
---|
16 | var LOWER_F_CODE = 102;
|
---|
17 | var UPPER_A_CODE = 65;
|
---|
18 | var UPPER_F_CODE = 70;
|
---|
19 |
|
---|
20 | var isDigit = function (str, index) {
|
---|
21 | var c = charCodeAt(str, index);
|
---|
22 | return c >= ZERO_CODE && c <= NINE_CODE;
|
---|
23 | };
|
---|
24 |
|
---|
25 | var parseHex = function (str, index, end) {
|
---|
26 | if (end >= str.length) return -1;
|
---|
27 | var n = 0;
|
---|
28 | for (; index < end; index++) {
|
---|
29 | var c = hexToInt(charCodeAt(str, index));
|
---|
30 | if (c === -1) return -1;
|
---|
31 | n = n * 16 + c;
|
---|
32 | }
|
---|
33 | return n;
|
---|
34 | };
|
---|
35 |
|
---|
36 | var hexToInt = function (c) {
|
---|
37 | if (c >= ZERO_CODE && c <= NINE_CODE) return c - ZERO_CODE;
|
---|
38 | if (c >= LOWER_A_CODE && c <= LOWER_F_CODE) return c - LOWER_A_CODE + 10;
|
---|
39 | if (c >= UPPER_A_CODE && c <= UPPER_F_CODE) return c - UPPER_A_CODE + 10;
|
---|
40 | return -1;
|
---|
41 | };
|
---|
42 |
|
---|
43 | module.exports = function (raw) {
|
---|
44 | var out = '';
|
---|
45 | var start = 0;
|
---|
46 | // We need to find every backslash escape sequence, and cook the escape into a real char.
|
---|
47 | var i = 0;
|
---|
48 | var n;
|
---|
49 | while ((i = stringIndexOf(raw, '\\', i)) > -1) {
|
---|
50 | out += stringSlice(raw, start, i);
|
---|
51 | // If the backslash is the last char of the string, then it was an invalid sequence.
|
---|
52 | // This can't actually happen in a tagged template literal, but could happen if you manually
|
---|
53 | // invoked the tag with an array.
|
---|
54 | if (++i === raw.length) return;
|
---|
55 | var next = charAt(raw, i++);
|
---|
56 | switch (next) {
|
---|
57 | // Escaped control codes need to be individually processed.
|
---|
58 | case 'b':
|
---|
59 | out += '\b';
|
---|
60 | break;
|
---|
61 | case 't':
|
---|
62 | out += '\t';
|
---|
63 | break;
|
---|
64 | case 'n':
|
---|
65 | out += '\n';
|
---|
66 | break;
|
---|
67 | case 'v':
|
---|
68 | out += '\v';
|
---|
69 | break;
|
---|
70 | case 'f':
|
---|
71 | out += '\f';
|
---|
72 | break;
|
---|
73 | case 'r':
|
---|
74 | out += '\r';
|
---|
75 | break;
|
---|
76 | // Escaped line terminators just skip the char.
|
---|
77 | case '\r':
|
---|
78 | // Treat `\r\n` as a single terminator.
|
---|
79 | if (i < raw.length && charAt(raw, i) === '\n') ++i;
|
---|
80 | // break omitted
|
---|
81 | case '\n':
|
---|
82 | case '\u2028':
|
---|
83 | case '\u2029':
|
---|
84 | break;
|
---|
85 | // `\0` is a null control char, but `\0` followed by another digit is an illegal octal escape.
|
---|
86 | case '0':
|
---|
87 | if (isDigit(raw, i)) return;
|
---|
88 | out += '\0';
|
---|
89 | break;
|
---|
90 | // Hex escapes must contain 2 hex chars.
|
---|
91 | case 'x':
|
---|
92 | n = parseHex(raw, i, i + 2);
|
---|
93 | if (n === -1) return;
|
---|
94 | i += 2;
|
---|
95 | out += fromCharCode(n);
|
---|
96 | break;
|
---|
97 | // Unicode escapes contain either 4 chars, or an unlimited number between `{` and `}`.
|
---|
98 | // The hex value must not overflow 0x10FFFF.
|
---|
99 | case 'u':
|
---|
100 | if (i < raw.length && charAt(raw, i) === '{') {
|
---|
101 | var end = stringIndexOf(raw, '}', ++i);
|
---|
102 | if (end === -1) return;
|
---|
103 | n = parseHex(raw, i, end);
|
---|
104 | i = end + 1;
|
---|
105 | } else {
|
---|
106 | n = parseHex(raw, i, i + 4);
|
---|
107 | i += 4;
|
---|
108 | }
|
---|
109 | if (n === -1 || n > 0x10FFFF) return;
|
---|
110 | out += fromCodePoint(n);
|
---|
111 | break;
|
---|
112 | default:
|
---|
113 | if (isDigit(next, 0)) return;
|
---|
114 | out += next;
|
---|
115 | }
|
---|
116 | start = i;
|
---|
117 | }
|
---|
118 | return out + stringSlice(raw, start);
|
---|
119 | };
|
---|