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
This commit is contained in:
JoostK 2020-10-30 22:53:30 +01:00 committed by Joey Perrott
parent 2d79780384
commit 4eda87c86c
2 changed files with 49 additions and 1 deletions

View File

@ -122,6 +122,18 @@ export class AstObject<TExpression> {
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<T>(mapper: (value: AstValue<TExpression>) => T): Map<string, T> {
const result = new Map<string, T>();
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<TExpression> {
* access to the underlying value of the wrapped expression.
*/
export class AstValue<TExpression> {
constructor(private expression: TExpression, private host: AstHost<TExpression>) {}
constructor(readonly expression: TExpression, private host: AstHost<TExpression>) {}
/**
* 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?

View File

@ -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);