2016-06-23 12:47:54 -04:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2018-04-24 17:22:55 -04:00
|
|
|
import {AST, AstVisitor, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead} from '../../../src/expression_parser/ast';
|
|
|
|
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../src/ml_parser/interpolation_config';
|
2015-06-06 05:15:14 -04:00
|
|
|
|
2016-07-06 17:06:47 -04:00
|
|
|
class Unparser implements AstVisitor {
|
2015-06-23 06:46:38 -04:00
|
|
|
private static _quoteRegExp = /"/g;
|
2015-06-06 05:15:14 -04:00
|
|
|
private _expression: string;
|
2016-06-20 12:52:41 -04:00
|
|
|
private _interpolationConfig: InterpolationConfig;
|
2015-06-06 05:15:14 -04:00
|
|
|
|
2016-07-06 17:06:47 -04:00
|
|
|
unparse(ast: AST, interpolationConfig: InterpolationConfig) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._expression = '';
|
2016-06-20 12:52:41 -04:00
|
|
|
this._interpolationConfig = interpolationConfig;
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast);
|
|
|
|
return this._expression;
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitPropertyRead(ast: PropertyRead, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.receiver);
|
|
|
|
this._expression += ast.receiver instanceof ImplicitReceiver ? `${ast.name}` : `.${ast.name}`;
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitPropertyWrite(ast: PropertyWrite, context: any) {
|
2015-08-12 19:26:21 -04:00
|
|
|
this._visit(ast.receiver);
|
|
|
|
this._expression +=
|
|
|
|
ast.receiver instanceof ImplicitReceiver ? `${ast.name} = ` : `.${ast.name} = `;
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.value);
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitBinary(ast: Binary, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.left);
|
|
|
|
this._expression += ` ${ast.operation} `;
|
|
|
|
this._visit(ast.right);
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitChain(ast: Chain, context: any) {
|
2016-11-12 08:08:58 -05:00
|
|
|
const len = ast.expressions.length;
|
2015-06-10 05:11:01 -04:00
|
|
|
for (let i = 0; i < len; i++) {
|
|
|
|
this._visit(ast.expressions[i]);
|
|
|
|
this._expression += i == len - 1 ? ';' : '; ';
|
|
|
|
}
|
2015-06-06 05:15:14 -04:00
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitConditional(ast: Conditional, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.condition);
|
|
|
|
this._expression += ' ? ';
|
|
|
|
this._visit(ast.trueExp);
|
|
|
|
this._expression += ' : ';
|
|
|
|
this._visit(ast.falseExp);
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitPipe(ast: BindingPipe, context: any) {
|
2015-06-04 13:06:09 -04:00
|
|
|
this._expression += '(';
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.exp);
|
|
|
|
this._expression += ` | ${ast.name}`;
|
|
|
|
ast.args.forEach(arg => {
|
|
|
|
this._expression += ':';
|
|
|
|
this._visit(arg);
|
2015-06-04 13:06:09 -04:00
|
|
|
});
|
|
|
|
this._expression += ')';
|
2015-06-06 05:15:14 -04:00
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitFunctionCall(ast: FunctionCall, context: any) {
|
2017-03-24 12:59:58 -04:00
|
|
|
this._visit(ast.target !);
|
2015-06-06 05:15:14 -04:00
|
|
|
this._expression += '(';
|
2016-11-12 08:08:58 -05:00
|
|
|
let isFirst = true;
|
2015-06-06 05:15:14 -04:00
|
|
|
ast.args.forEach(arg => {
|
|
|
|
if (!isFirst) this._expression += ', ';
|
|
|
|
isFirst = false;
|
|
|
|
this._visit(arg);
|
|
|
|
});
|
|
|
|
this._expression += ')';
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitImplicitReceiver(ast: ImplicitReceiver, context: any) {}
|
2015-06-06 05:15:14 -04:00
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitInterpolation(ast: Interpolation, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
for (let i = 0; i < ast.strings.length; i++) {
|
|
|
|
this._expression += ast.strings[i];
|
|
|
|
if (i < ast.expressions.length) {
|
2016-06-20 12:52:41 -04:00
|
|
|
this._expression += `${this._interpolationConfig.start} `;
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.expressions[i]);
|
2016-06-20 12:52:41 -04:00
|
|
|
this._expression += ` ${this._interpolationConfig.end}`;
|
2015-06-06 05:15:14 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitKeyedRead(ast: KeyedRead, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.obj);
|
|
|
|
this._expression += '[';
|
|
|
|
this._visit(ast.key);
|
|
|
|
this._expression += ']';
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitKeyedWrite(ast: KeyedWrite, context: any) {
|
2015-08-12 19:26:21 -04:00
|
|
|
this._visit(ast.obj);
|
|
|
|
this._expression += '[';
|
|
|
|
this._visit(ast.key);
|
|
|
|
this._expression += '] = ';
|
|
|
|
this._visit(ast.value);
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitLiteralArray(ast: LiteralArray, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._expression += '[';
|
2016-11-12 08:08:58 -05:00
|
|
|
let isFirst = true;
|
2015-06-06 05:15:14 -04:00
|
|
|
ast.expressions.forEach(expression => {
|
|
|
|
if (!isFirst) this._expression += ', ';
|
|
|
|
isFirst = false;
|
|
|
|
this._visit(expression);
|
|
|
|
});
|
|
|
|
|
|
|
|
this._expression += ']';
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitLiteralMap(ast: LiteralMap, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._expression += '{';
|
2016-11-12 08:08:58 -05:00
|
|
|
let isFirst = true;
|
2015-06-06 05:15:14 -04:00
|
|
|
for (let i = 0; i < ast.keys.length; i++) {
|
|
|
|
if (!isFirst) this._expression += ', ';
|
|
|
|
isFirst = false;
|
2017-07-05 13:54:05 -04:00
|
|
|
const key = ast.keys[i];
|
|
|
|
this._expression += key.quoted ? JSON.stringify(key.key) : key.key;
|
|
|
|
this._expression += ': ';
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.values[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._expression += '}';
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitLiteralPrimitive(ast: LiteralPrimitive, context: any) {
|
2016-10-19 16:42:39 -04:00
|
|
|
if (typeof ast.value === 'string') {
|
2016-10-06 18:10:27 -04:00
|
|
|
this._expression += `"${ast.value.replace( Unparser._quoteRegExp, '\"')}"`;
|
2015-06-06 05:15:14 -04:00
|
|
|
} else {
|
|
|
|
this._expression += `${ast.value}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitMethodCall(ast: MethodCall, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.receiver);
|
2015-07-10 05:29:41 -04:00
|
|
|
this._expression += ast.receiver instanceof ImplicitReceiver ? `${ast.name}(` : `.${ast.name}(`;
|
2016-11-12 08:08:58 -05:00
|
|
|
let isFirst = true;
|
2015-06-06 05:15:14 -04:00
|
|
|
ast.args.forEach(arg => {
|
|
|
|
if (!isFirst) this._expression += ', ';
|
|
|
|
isFirst = false;
|
|
|
|
this._visit(arg);
|
|
|
|
});
|
|
|
|
this._expression += ')';
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitPrefixNot(ast: PrefixNot, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._expression += '!';
|
|
|
|
this._visit(ast.expression);
|
|
|
|
}
|
|
|
|
|
2017-05-11 13:15:54 -04:00
|
|
|
visitNonNullAssert(ast: NonNullAssert, context: any) {
|
|
|
|
this._visit(ast.expression);
|
|
|
|
this._expression += '!';
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitSafePropertyRead(ast: SafePropertyRead, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.receiver);
|
|
|
|
this._expression += `?.${ast.name}`;
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitSafeMethodCall(ast: SafeMethodCall, context: any) {
|
2015-06-06 05:15:14 -04:00
|
|
|
this._visit(ast.receiver);
|
|
|
|
this._expression += `?.${ast.name}(`;
|
2016-11-12 08:08:58 -05:00
|
|
|
let isFirst = true;
|
2015-06-06 05:15:14 -04:00
|
|
|
ast.args.forEach(arg => {
|
|
|
|
if (!isFirst) this._expression += ', ';
|
|
|
|
isFirst = false;
|
|
|
|
this._visit(arg);
|
|
|
|
});
|
|
|
|
this._expression += ')';
|
|
|
|
}
|
|
|
|
|
2016-01-06 17:13:44 -05:00
|
|
|
visitQuote(ast: Quote, context: any) {
|
|
|
|
this._expression += `${ast.prefix}:${ast.uninterpretedExpression}`;
|
|
|
|
}
|
2015-11-23 20:58:12 -05:00
|
|
|
|
2015-06-06 05:15:14 -04:00
|
|
|
private _visit(ast: AST) { ast.visit(this); }
|
|
|
|
}
|
2016-07-06 17:06:47 -04:00
|
|
|
|
|
|
|
const sharedUnparser = new Unparser();
|
|
|
|
|
|
|
|
export function unparse(
|
|
|
|
ast: AST, interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): string {
|
|
|
|
return sharedUnparser.unparse(ast, interpolationConfig);
|
|
|
|
}
|