diff --git a/src/Transpiler.ts b/src/Transpiler.ts index 61df92b0e..e79f95474 100644 --- a/src/Transpiler.ts +++ b/src/Transpiler.ts @@ -691,6 +691,30 @@ export abstract class LuaTranspiler { } } + public escapeString(text: string): string { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String + const escapeSequences: Array<[RegExp, string]> = [ + [/[\\]/g, "\\\\"], + [/[\']/g, "\\\'"], + [/[\`]/g, "\\\`"], + [/[\"]/g, "\\\""], + [/[\n]/g, "\\n"], + [/[\r]/g, "\\r"], + [/[\v]/g, "\\v"], + [/[\t]/g, "\\t"], + [/[\b]/g, "\\b"], + [/[\f]/g, "\\f"], + [/[\0]/g, "\\0"], + ]; + + if (text.length > 0) { + for (const [regex, replacement] of escapeSequences) { + text = text.replace(regex, replacement); + } + } + return text; + } + public transpileExpression(node: ts.Node, brackets?: boolean): string { switch (node.kind) { case ts.SyntaxKind.BinaryExpression: @@ -714,7 +738,7 @@ export abstract class LuaTranspiler { return this.transpileIdentifier(node as ts.Identifier); case ts.SyntaxKind.StringLiteral: case ts.SyntaxKind.NoSubstitutionTemplateLiteral: - const text = (node as ts.StringLiteral).text; + const text = this.escapeString((node as ts.StringLiteral).text); return `"${text}"`; case ts.SyntaxKind.TemplateExpression: return this.transpileTemplateExpression(node as ts.TemplateExpression); @@ -889,13 +913,15 @@ export abstract class LuaTranspiler { } public transpileTemplateExpression(node: ts.TemplateExpression): string { - const parts = [`"${node.head.text}"`]; + const parts = [`"${this.escapeString(node.head.text)}"`]; node.templateSpans.forEach(span => { const expr = this.transpileExpression(span.expression, true); + const text = this.escapeString(span.literal.text); + if (ts.isTemplateTail(span.literal)) { - parts.push(`tostring(${expr}).."${span.literal.text}"`); + parts.push(`tostring(${expr}).."${text}"`); } else { - parts.push(`tostring(${expr}).."${span.literal.text}"`); + parts.push(`tostring(${expr}).."${text}"`); } }); return parts.join(".."); diff --git a/test/translation/lua/characterEscapeSequence.lua b/test/translation/lua/characterEscapeSequence.lua new file mode 100644 index 000000000..ddb2fa547 --- /dev/null +++ b/test/translation/lua/characterEscapeSequence.lua @@ -0,0 +1,18 @@ +local quoteInDoubleQuotes = "\' \' \'" + +local quoteInTemplateString = "\' \' \'" + +local doubleQuoteInQuotes = "\" \" \"" + +local doubleQuoteInDoubleQuotes = "\" \" \"" + +local doubleQuoteInTemplateString = "\" \" \"" + +local escapedCharsInQuotes = "\\ \0 \b \t \n \v \f \" \' \`" + +local escapedCharsInDoubleQUotes = "\\ \0 \b \t \n \v \f \" \' \`" + +local escapedCharsInTemplateString = "\\ \0 \b \t \n \v \f \" \' \`" + +local nonEmptyTemplateString = "Level 0: \n\t "..tostring("Level 1: \n\t\t "..tostring("Level 3: \n\t\t\t "..tostring("Last level \n --").." \n --").." \n --").." \n --" + diff --git a/test/translation/ts/characterEscapeSequence.ts b/test/translation/ts/characterEscapeSequence.ts new file mode 100644 index 000000000..f99683c32 --- /dev/null +++ b/test/translation/ts/characterEscapeSequence.ts @@ -0,0 +1,12 @@ +let quoteInDoubleQuotes = "' ' '"; +let quoteInTemplateString = `' ' '`; + +let doubleQuoteInQuotes = '" " "'; +let doubleQuoteInDoubleQuotes = "\" \" \""; +let doubleQuoteInTemplateString = `" " "`; + +let escapedCharsInQuotes = '\\ \0 \b \t \n \v \f \" \' \`'; +let escapedCharsInDoubleQUotes = "\\ \0 \b \t \n \v \f \" \' \`"; +let escapedCharsInTemplateString = `\\ \0 \b \t \n \v \f \" \' \``; + +let nonEmptyTemplateString = `Level 0: \n\t ${`Level 1: \n\t\t ${`Level 3: \n\t\t\t ${'Last level \n --'} \n --`} \n --`} \n --`;