From da917757763628238577ad669cea19a90cbb4d01 Mon Sep 17 00:00:00 2001 From: Miroslav Oujesky Date: Tue, 3 Nov 2015 17:05:17 +0100 Subject: [PATCH] Fixed handling of literal text blocks enclosed in {literal} command. --- .../phpsrc/internal/GenPhpExprsVisitor.java | 2 +- .../soy/phpsrc/restricted/PhpExprUtils.java | 37 +++++++++++++++++++ .../internal/GenPhpCodeVisitorTest.java | 14 +++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/java/src/com/google/template/soy/phpsrc/internal/GenPhpExprsVisitor.java b/java/src/com/google/template/soy/phpsrc/internal/GenPhpExprsVisitor.java index 0f7353dc6..fea496640 100644 --- a/java/src/com/google/template/soy/phpsrc/internal/GenPhpExprsVisitor.java +++ b/java/src/com/google/template/soy/phpsrc/internal/GenPhpExprsVisitor.java @@ -134,7 +134,7 @@ List execOnChildren(ParentSoyNode node) { */ @Override protected void visitRawTextNode(RawTextNode node) { // Escape special characters in the text before writing as a string. - String exprText = BaseUtils.escapeToSoyString(node.getRawText(), false); + String exprText = PhpExprUtils.escapeLiteralString(node.getRawText()); phpExprs.add(new PhpStringExpr(exprText)); } diff --git a/java/src/com/google/template/soy/phpsrc/restricted/PhpExprUtils.java b/java/src/com/google/template/soy/phpsrc/restricted/PhpExprUtils.java index d65b077cc..ad7140149 100644 --- a/java/src/com/google/template/soy/phpsrc/restricted/PhpExprUtils.java +++ b/java/src/com/google/template/soy/phpsrc/restricted/PhpExprUtils.java @@ -242,4 +242,41 @@ public static String escapePhpMethodName(String phpMethodName) { return phpMethodName; } + + /** + * Escapes raw literal string to PHP string + * + * Based on BaseUtil.escapeSoyString(), but adjusted to work with PHP apostrophe enclosed strings + * + * Line breaks are transformed as PHP_EOL constants, backslashes and apostrohpes are escaped, + * other characters are left in their literal form + * + * @param value + * @return Prepared PHP string + */ + public static String escapeLiteralString(String value) { + + int len = value.length(); + StringBuilder out = new StringBuilder(len * 9 / 8); + out.append('\''); + + int codePoint; + for (int i = 0; i < len; i += Character.charCount(codePoint)) { + codePoint = value.codePointAt(i); + + switch (codePoint) { + case '\n': out.append("'.PHP_EOL.'"); break; + // remove \r completely, line breaks are handled on \n + case '\r': out.append(""); break; + case '\\': out.append("\\\\"); break; + case '\'': out.append("\\'"); break; + default: + out.appendCodePoint(codePoint); + break; + } + } + + out.append('\''); + return out.toString(); + } } diff --git a/java/tests/com/google/template/soy/phpsrc/internal/GenPhpCodeVisitorTest.java b/java/tests/com/google/template/soy/phpsrc/internal/GenPhpCodeVisitorTest.java index e8a4139a0..9de2d0ebc 100644 --- a/java/tests/com/google/template/soy/phpsrc/internal/GenPhpCodeVisitorTest.java +++ b/java/tests/com/google/template/soy/phpsrc/internal/GenPhpCodeVisitorTest.java @@ -343,4 +343,18 @@ public void testCallReturnsString() { assertThatSoyCode(soyCode).compilesTo(expectedPhpCode); } + + public void testLiteral() { + String soyCode = "{literal}\n" + + " /* some\n" + + " multiline\n" + + " string */\n" + + " {$a}\n" + + "\t'\"test&\n" + + "{/literal}"; + + String expectedPhpCode = "$output .= ''.PHP_EOL.' /* some'.PHP_EOL.' multiline'.PHP_EOL.' string */'.PHP_EOL.' {$a}'.PHP_EOL.'\t\\'\"test&'.PHP_EOL.'';\n"; + + assertThatSoyCode(soyCode).compilesTo(expectedPhpCode); + } }