fix(ivy): i18n - support "\", "`" and "${" sequences in i18n messages (#33820)

Since i18n messages are mapped to `$localize` tagged template strings,
the "raw" version must be properly escaped. Otherwise TS will throw an
error such as:

```
Error: Debug Failure. False expression: Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.
```

This commit ensures that we properly escape these raw strings before creating
TS AST nodes from them.

PR Close #33820
This commit is contained in:
Pete Bacon Darwin
2019-11-15 16:25:59 +00:00
committed by Alex Rickabaugh
parent 62f7d0fe5c
commit a6247aafa1
7 changed files with 156 additions and 104 deletions

View File

@ -8,7 +8,6 @@
import {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinType, BuiltinTypeName, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, Type, TypeVisitor, TypeofExpr, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler';
import {LocalizedString} from '@angular/compiler/src/output/output_ast';
import {serializeI18nHead, serializeI18nTemplatePart} from '@angular/compiler/src/render3/view/i18n/meta';
import * as ts from 'typescript';
import {DefaultImportRecorder, ImportRewriter, NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports';
@ -547,7 +546,7 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor {
*/
function visitLocalizedString(ast: LocalizedString, context: Context, visitor: ExpressionVisitor) {
let template: ts.TemplateLiteral;
const metaBlock = serializeI18nHead(ast.metaBlock, ast.messageParts[0]);
const metaBlock = ast.serializeI18nHead();
if (ast.messageParts.length === 1) {
template = ts.createNoSubstitutionTemplateLiteral(metaBlock.cooked, metaBlock.raw);
} else {
@ -555,9 +554,8 @@ function visitLocalizedString(ast: LocalizedString, context: Context, visitor: E
const spans: ts.TemplateSpan[] = [];
for (let i = 1; i < ast.messageParts.length; i++) {
const resolvedExpression = ast.expressions[i - 1].visitExpression(visitor, context);
const templatePart =
serializeI18nTemplatePart(ast.placeHolderNames[i - 1], ast.messageParts[i]);
const templateMiddle = ts.createTemplateMiddle(templatePart);
const templatePart = ast.serializeI18nTemplatePart(i);
const templateMiddle = ts.createTemplateMiddle(templatePart.cooked, templatePart.raw);
spans.push(ts.createTemplateSpan(resolvedExpression, templateMiddle));
}
if (spans.length > 0) {