refactor(compiler): wrap the jit evaluation in an injectable class (#28055)

When testing JIT code, it is useful to be able to access the
generated JIT source. Previously this is done by spying on the
global `Function` object, to capture the code when it is being
evaluated. This is problematic because you can only capture
the body of the function, and not the arguments, which messes
up line and column positions for source mapping for instance.

Now the code that generates and then evaluates JIT code is
wrapped in a `JitEvaluator` class, making it possible to provide
a mock implementation that can capture the generated source of
the function passed to `executeFunction(fn: Function, args: any[])`.

PR Close #28055
This commit is contained in:
Pete Bacon Darwin
2019-02-08 22:10:19 +00:00
committed by Misko Hevery
parent 8c3f1717a8
commit 54ca24b47d
6 changed files with 119 additions and 75 deletions

View File

@ -7,9 +7,7 @@
*/
import {CompileReflector} from '../compile_reflector';
import {ConstantPool} from '../constant_pool';
import * as o from '../output/output_ast';
import {jitStatements} from '../output/output_jit';
/**
* Implementation of `CompileReflector` which resolves references to @angular/core
@ -17,7 +15,7 @@ import {jitStatements} from '../output/output_jit';
*
* Only supports `resolveExternalReference`, all other methods throw.
*/
class R3JitReflector implements CompileReflector {
export class R3JitReflector implements CompileReflector {
constructor(private context: {[key: string]: any}) {}
resolveExternalReference(ref: o.ExternalReference): any {
@ -48,27 +46,3 @@ class R3JitReflector implements CompileReflector {
componentModuleUrl(type: any, cmpMetadata: any): string { throw new Error('Not implemented.'); }
}
/**
* JIT compiles an expression and returns the result of executing that expression.
*
* @param def the definition which will be compiled and executed to get the value to patch
* @param context an object map of @angular/core symbol names to symbols which will be available in
* the context of the compiled expression
* @param sourceUrl a URL to use for the source map of the compiled expression
* @param constantPool an optional `ConstantPool` which contains constants used in the expression
*/
export function jitExpression(
def: o.Expression, context: {[key: string]: any}, sourceUrl: string,
preStatements: o.Statement[]): any {
// The ConstantPool may contain Statements which declare variables used in the final expression.
// Therefore, its statements need to precede the actual JIT operation. The final statement is a
// declaration of $def which is set to the expression being compiled.
const statements: o.Statement[] = [
...preStatements,
new o.DeclareVarStmt('$def', def, undefined, [o.StmtModifier.Exported]),
];
const res = jitStatements(sourceUrl, statements, new R3JitReflector(context), false);
return res['$def'];
}