/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/compiler/src/expression_parser/serializer.ts
210 строк
6 KB
Kristiyan Kostadinov
refactor(compiler): add AST nodes for arrow functions
09 янв 2026, 21:35
09 янв 2026, 21:35
ab536f8
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC 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.dev/license */ import * as expr from './ast'; /** Serializes the given AST into a normalized string format. */ export function serialize(expression: expr.ASTWithSource): string { return expression.visit(new SerializeExpressionVisitor()); } class SerializeExpressionVisitor implements expr.AstVisitor { visitUnary(ast: expr.Unary, context: any): string { return `${ast.operator}${ast.expr.visit(this, context)}`; } visitBinary(ast: expr.Binary, context: any): string { return `${ast.left.visit(this, context)} ${ast.operation} ${ast.right.visit(this, context)}`; } visitChain(ast: expr.Chain, context: any): string { return ast.expressions.map((e) => e.visit(this, context)).join('; '); } visitConditional(ast: expr.Conditional, context: any): string { return `${ast.condition.visit(this, context)} ? ${ast.trueExp.visit( this, context, )} : ${ast.falseExp.visit(this, context)}`; } visitThisReceiver(): string { return 'this'; } visitImplicitReceiver(): string { return ''; } visitInterpolation(ast: expr.Interpolation, context: any): string { return interleave( ast.strings, ast.expressions.map((e) => e.visit(this, context)), ).join(''); } visitKeyedRead(ast: expr.KeyedRead, context: any): string { return `${ast.receiver.visit(this, context)}[${ast.key.visit(this, context)}]`; } visitLiteralArray(ast: expr.LiteralArray, context: any): string { return `[${ast.expressions.map((e) => e.visit(this, context)).join(', ')}]`; } visitLiteralMap(ast: expr.LiteralMap, context: any): string { return `{${zip( ast.keys.map((literal) => { if (literal.kind === 'spread') { return '...'; } return literal.quoted ? `'${literal.key}'` : literal.key; }), ast.values.map((value) => value.visit(this, context)), ) .map(([key, value]) => `${key}: ${value}`) .join(', ')}}`; } visitLiteralPrimitive(ast: expr.LiteralPrimitive): string { if (ast.value === null) return 'null'; switch (typeof ast.value) { case 'number': case 'boolean': return ast.value.toString(); case 'undefined': return 'undefined'; case 'string': return `'${ast.value.replace(/'/g, `\\'`)}'`; default: throw new Error(`Unsupported primitive type: ${ast.value}`); } } visitPipe(ast: expr.BindingPipe, context: any): string { return `${ast.exp.visit(this, context)} | ${ast.name}`; } visitPrefixNot(ast: expr.PrefixNot, context: any): string { return `!${ast.expression.visit(this, context)}`; } visitNonNullAssert(ast: expr.NonNullAssert, context: any): string { return `${ast.expression.visit(this, context)}!`; } visitPropertyRead(ast: expr.PropertyRead, context: any): string { if ( ast.receiver instanceof expr.ImplicitReceiver || ast.receiver instanceof expr.ThisReceiver ) { return ast.name; } else { return `${ast.receiver.visit(this, context)}.${ast.name}`; } } visitSafePropertyRead(ast: expr.SafePropertyRead, context: any): string { return `${ast.receiver.visit(this, context)}?.${ast.name}`; } visitSafeKeyedRead(ast: expr.SafeKeyedRead, context: any): string { return `${ast.receiver.visit(this, context)}?.[${ast.key.visit(this, context)}]`; } visitCall(ast: expr.Call, context: any): string { return `${ast.receiver.visit(this, context)}(${ast.args .map((e) => e.visit(this, context)) .join(', ')})`; } visitSafeCall(ast: expr.SafeCall, context: any): string { return `${ast.receiver.visit(this, context)}?.(${ast.args .map((e) => e.visit(this, context)) .join(', ')})`; } visitTypeofExpression(ast: expr.TypeofExpression, context: any) { return `typeof ${ast.expression.visit(this, context)}`; } visitVoidExpression(ast: expr.VoidExpression, context: any) { return `void ${ast.expression.visit(this, context)}`; } visitRegularExpressionLiteral(ast: expr.RegularExpressionLiteral, context: any) { return `/${ast.body}/${ast.flags || ''}`; } visitArrowFunction(ast: expr.ArrowFunction, context: any) { let params: string; if (ast.parameters.length === 1) { params = ast.parameters[0].name; } else { params = `(${ast.parameters.map((e) => e.name).join(', ')})`; } return `${params} => ${ast.body.visit(this, context)}`; } visitASTWithSource(ast: expr.ASTWithSource, context: any): string { return ast.ast.visit(this, context); } visitTemplateLiteral(ast: expr.TemplateLiteral, context: any) { let result = ''; for (let i = 0; i < ast.elements.length; i++) { result += ast.elements[i].visit(this, context); const expression = i < ast.expressions.length ? ast.expressions[i] : null; if (expression !== null) { result += '${' + expression.visit(this, context) + '}'; } } return '`' + result + '`'; } visitTemplateLiteralElement(ast: expr.TemplateLiteralElement, context: any) { return ast.text; } visitTaggedTemplateLiteral(ast: expr.TaggedTemplateLiteral, context: any) { return ast.tag.visit(this, context) + ast.template.visit(this, context); } visitSpreadElement(ast: expr.SpreadElement, context: any) { return `...${ast.expression.visit(this, context)}`; } visitParenthesizedExpression(ast: expr.ParenthesizedExpression, context: any) { return '(' + ast.expression.visit(this, context) + ')'; } } /** Zips the two input arrays into a single array of pairs of elements at the same index. */ function zip<Left, Right>(left: Left[], right: Right[]): Array<[Left, Right]> { if (left.length !== right.length) throw new Error('Array lengths must match'); return left.map((l, i) => [l, right[i]]); } /** * Interleaves the two arrays, starting with the first item on the left, then the first item * on the right, second item from the left, and so on. When the first array's items are exhausted, * the remaining items from the other array are included with no interleaving. */ function interleave<Left, Right>(left: Left[], right: Right[]): Array<Left | Right> { const result: Array<Left | Right> = []; for (let index = 0; index < Math.max(left.length, right.length); index++) { if (index < left.length) result.push(left[index]); if (index < right.length) result.push(right[index]); } return result; }