in src/scanner.ts [858:960]
private scanStringLiteral(): RawToken {
const start = this.index;
let quote = this.source[start];
assert((quote === '\'' || quote === '"'),
'String literal must starts with a quote');
++this.index;
let octal = false;
let str = '';
while (!this.eof()) {
let ch = this.source[this.index++];
if (ch === quote) {
quote = '';
break;
} else if (ch === '\\') {
ch = this.source[this.index++];
if (!ch || !Character.isLineTerminator(ch.charCodeAt(0))) {
switch (ch) {
case 'u':
if (this.source[this.index] === '{') {
++this.index;
str += this.scanUnicodeCodePointEscape();
} else {
const unescapedChar = this.scanHexEscape(ch);
if (unescapedChar === null) {
this.throwUnexpectedToken();
}
str += unescapedChar;
}
break;
case 'x':
const unescaped = this.scanHexEscape(ch);
if (unescaped === null) {
this.throwUnexpectedToken(Messages.InvalidHexEscapeSequence);
}
str += unescaped;
break;
case 'n':
str += '\n';
break;
case 'r':
str += '\r';
break;
case 't':
str += '\t';
break;
case 'b':
str += '\b';
break;
case 'f':
str += '\f';
break;
case 'v':
str += '\x0B';
break;
case '8':
case '9':
str += ch;
this.tolerateUnexpectedToken();
break;
default:
if (ch && Character.isOctalDigit(ch.charCodeAt(0))) {
const octToDec = this.octalToDecimal(ch);
octal = octToDec.octal || octal;
str += String.fromCharCode(octToDec.code);
} else {
str += ch;
}
break;
}
} else {
++this.lineNumber;
if (ch === '\r' && this.source[this.index] === '\n') {
++this.index;
}
this.lineStart = this.index;
}
} else if (Character.isLineTerminator(ch.charCodeAt(0))) {
break;
} else {
str += ch;
}
}
if (quote !== '') {
this.index = start;
this.throwUnexpectedToken();
}
return {
type: Token.StringLiteral,
value: str,
octal: octal,
lineNumber: this.lineNumber,
lineStart: this.lineStart,
start: start,
end: this.index
};
}