From 4eda87c86c60497f67907885a2357373f8ad96b9 Mon Sep 17 00:00:00 2001 From: JoostK Date: Fri, 30 Oct 2020 22:53:30 +0100 Subject: [PATCH] refactor(compiler-cli): extend AST object and value helpers (#39518) This introduces `AstObject.toMap` as an alternative to `AstObject .toLiteral`, and adds `AstValue.getSymbolName` to query the symbol name of a value using the encapsulated AST host. PR Close #39518 --- .../compiler-cli/linker/src/ast/ast_value.ts | 22 ++++++++++++++- .../linker/test/ast/ast_value_spec.ts | 28 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/compiler-cli/linker/src/ast/ast_value.ts b/packages/compiler-cli/linker/src/ast/ast_value.ts index 2275c61aef..838e2ac637 100644 --- a/packages/compiler-cli/linker/src/ast/ast_value.ts +++ b/packages/compiler-cli/linker/src/ast/ast_value.ts @@ -122,6 +122,18 @@ export class AstObject { return result; } + /** + * Converts the AstObject to a JavaScript Map, mapping each property value (as an + * `AstValue`) to the generic type (`T`) via the `mapper` function. + */ + toMap(mapper: (value: AstValue) => T): Map { + const result = new Map(); + for (const [key, expression] of this.obj) { + result.set(key, mapper(new AstValue(expression, this.host))); + } + return result; + } + private getRequiredProperty(propertyName: string): TExpression { if (!this.obj.has(propertyName)) { throw new FatalLinkerError( @@ -136,7 +148,15 @@ export class AstObject { * access to the underlying value of the wrapped expression. */ export class AstValue { - constructor(private expression: TExpression, private host: AstHost) {} + constructor(readonly expression: TExpression, private host: AstHost) {} + + /** + * Get the name of the symbol represented by the given expression node, or `null` if it is not a + * symbol. + */ + getSymbolName(): string|null { + return this.host.getSymbolName(this.expression); + } /** * Is this value a number? diff --git a/packages/compiler-cli/linker/test/ast/ast_value_spec.ts b/packages/compiler-cli/linker/test/ast/ast_value_spec.ts index 711b996cfc..cdc61f1cd8 100644 --- a/packages/compiler-cli/linker/test/ast/ast_value_spec.ts +++ b/packages/compiler-cli/linker/test/ast/ast_value_spec.ts @@ -141,9 +141,37 @@ describe('AstObject', () => { }); }); }); + + describe('toMap()', () => { + it('should convert the AstObject to a Map with each property mapped', () => { + expect(obj.toMap(value => value.getOpaque())).toEqual(new Map([ + ['a', obj.getOpaque('a')], + ['b', obj.getOpaque('b')], + ['c', obj.getOpaque('c')], + ['d', obj.getOpaque('d')], + ['e', obj.getOpaque('e')], + ])); + }); + }); }); describe('AstValue', () => { + describe('getSymbolName', () => { + it('should return the name of an identifier', () => { + expect(new AstValue(factory.createIdentifier('Foo'), host).getSymbolName()).toEqual('Foo'); + }); + + it('should return the name of a property access', () => { + const propertyAccess = factory.createPropertyAccess( + factory.createIdentifier('Foo'), factory.createIdentifier('Bar')); + expect(new AstValue(propertyAccess, host).getSymbolName()).toEqual('Bar'); + }); + + it('should return null if no symbol name is available', () => { + expect(new AstValue(factory.createLiteral('a'), host).getSymbolName()).toBeNull(); + }); + }); + describe('isNumber', () => { it('should return true if the value is a number', () => { expect(new AstValue(factory.createLiteral(42), host).isNumber()).toEqual(true);