fix(8223): Preserve Provider expressions
Preserves constructor calls in addition to function calls. Introduced a special case for forwardRef() similar to CONST_EXPR.
This commit is contained in:
parent
30de2db349
commit
7c0d4976b1
|
@ -180,6 +180,7 @@ export class Evaluator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can fold a call to CONST_EXPR
|
||||
if (isCallOf(callExpression, "CONST_EXPR") && callExpression.arguments.length === 1)
|
||||
return this.isFoldableWorker(callExpression.arguments[0], folding);
|
||||
|
@ -286,18 +287,35 @@ export class Evaluator {
|
|||
if (isCallOf(callExpression, "CONST_EXPR") && callExpression.arguments.length === 1) {
|
||||
return args[0];
|
||||
}
|
||||
if (isCallOf(callExpression, 'forwardRef') && callExpression.arguments.length === 1) {
|
||||
const firstArgument = callExpression.arguments[0];
|
||||
if (firstArgument.kind == ts.SyntaxKind.ArrowFunction) {
|
||||
const arrowFunction = <ts.ArrowFunction>firstArgument;
|
||||
return this.evaluateNode(arrowFunction.body);
|
||||
}
|
||||
}
|
||||
const expression = this.evaluateNode(callExpression.expression);
|
||||
if (isDefined(expression) && args.every(isDefined)) {
|
||||
const result: MetadataSymbolicCallExpression = {
|
||||
__symbolic: "call",
|
||||
expression: this.evaluateNode(callExpression.expression)
|
||||
};
|
||||
const result:
|
||||
MetadataSymbolicCallExpression = {__symbolic: "call", expression: expression};
|
||||
if (args && args.length) {
|
||||
result.arguments = args;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case ts.SyntaxKind.NewExpression:
|
||||
const newExpression = <ts.NewExpression>node;
|
||||
const newArgs = newExpression.arguments.map(arg => this.evaluateNode(arg));
|
||||
const newTarget = this.evaluateNode(newExpression.expression);
|
||||
if (isDefined(newTarget) && newArgs.every(isDefined)) {
|
||||
const result: MetadataSymbolicCallExpression = {__symbolic: "new", expression: newTarget};
|
||||
if (newArgs.length) {
|
||||
result.arguments = newArgs;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case ts.SyntaxKind.PropertyAccessExpression: {
|
||||
const propertyAccessExpression = <ts.PropertyAccessExpression>node;
|
||||
const expression = this.evaluateNode(propertyAccessExpression.expression);
|
||||
|
|
|
@ -57,7 +57,7 @@ export interface MetadataObject { [name: string]: MetadataValue; }
|
|||
export interface MetadataArray { [name: number]: MetadataValue; }
|
||||
|
||||
export interface MetadataSymbolicExpression {
|
||||
__symbolic: "binary" | "call" | "index" | "pre" | "reference" | "select"
|
||||
__symbolic: "binary" | "call" | "index" | "new" | "pre" | "reference" | "select"
|
||||
}
|
||||
export function isMetadataSymbolicExpression(value: any): value is MetadataSymbolicExpression {
|
||||
if (value) {
|
||||
|
@ -65,6 +65,7 @@ export function isMetadataSymbolicExpression(value: any): value is MetadataSymbo
|
|||
case "binary":
|
||||
case "call":
|
||||
case "index":
|
||||
case "new":
|
||||
case "pre":
|
||||
case "reference":
|
||||
case "select":
|
||||
|
@ -97,13 +98,13 @@ export function isMetadataSymbolicIndexExpression(
|
|||
}
|
||||
|
||||
export interface MetadataSymbolicCallExpression extends MetadataSymbolicExpression {
|
||||
__symbolic: "call";
|
||||
__symbolic: "call" | "new";
|
||||
expression: MetadataValue;
|
||||
arguments?: MetadataValue[];
|
||||
}
|
||||
export function isMetadataSymbolicCallExpression(
|
||||
value: any): value is MetadataSymbolicCallExpression {
|
||||
return value && value.__symbolic === "call";
|
||||
return value && (value.__symbolic === "call" || value.__symbolic === "new");
|
||||
}
|
||||
|
||||
export interface MetadataSymbolicPrefixExpression extends MetadataSymbolicExpression {
|
||||
|
|
|
@ -13,7 +13,9 @@ describe('Evaluator', () => {
|
|||
let evaluator: Evaluator;
|
||||
|
||||
beforeEach(() => {
|
||||
host = new Host(FILES, ['expressions.ts']);
|
||||
host = new Host(
|
||||
FILES,
|
||||
['expressions.ts', 'const_expr.ts', 'forwardRef.ts', 'classes.ts', 'newExpression.ts']);
|
||||
service = ts.createLanguageService(host);
|
||||
program = service.getProgram();
|
||||
typeChecker = program.getTypeChecker();
|
||||
|
@ -25,6 +27,7 @@ describe('Evaluator', () => {
|
|||
expectNoDiagnostics(service.getCompilerOptionsDiagnostics());
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
expectNoDiagnostics(service.getSyntacticDiagnostics(sourceFile.fileName));
|
||||
expectNoDiagnostics(service.getSemanticDiagnostics(sourceFile.fileName));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -101,6 +104,34 @@ describe('Evaluator', () => {
|
|||
expect(evaluator.evaluateNode(findVar(expressions, 'recursiveB').initializer))
|
||||
.toEqual({__symbolic: "reference", name: "recursiveA", module: undefined});
|
||||
});
|
||||
|
||||
it('should correctly handle special cases for CONST_EXPR', () => {
|
||||
var const_expr = program.getSourceFile('const_expr.ts');
|
||||
expect(evaluator.evaluateNode(findVar(const_expr, 'bTrue').initializer)).toEqual(true);
|
||||
expect(evaluator.evaluateNode(findVar(const_expr, 'bFalse').initializer)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should resolve a forwardRef', () => {
|
||||
var forwardRef = program.getSourceFile('forwardRef.ts');
|
||||
expect(evaluator.evaluateNode(findVar(forwardRef, 'bTrue').initializer)).toEqual(true);
|
||||
expect(evaluator.evaluateNode(findVar(forwardRef, 'bFalse').initializer)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return new expressions', () => {
|
||||
var newExpression = program.getSourceFile('newExpression.ts');
|
||||
expect(evaluator.evaluateNode(findVar(newExpression, 'someValue').initializer))
|
||||
.toEqual({
|
||||
__symbolic: "new",
|
||||
expression: {__symbolic: "reference", name: "Value", module: "classes.ts"},
|
||||
arguments: ["name", 12]
|
||||
});
|
||||
expect(evaluator.evaluateNode(findVar(newExpression, 'complex').initializer))
|
||||
.toEqual({
|
||||
__symbolic: "new",
|
||||
expression: {__symbolic: "reference", name: "Value", module: "classes.ts"},
|
||||
arguments: ["name", 12]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const FILES: Directory = {
|
||||
|
@ -109,6 +140,11 @@ const FILES: Directory = {
|
|||
return function(fn: Function) { }
|
||||
}
|
||||
`,
|
||||
'classes.ts': `
|
||||
export class Value {
|
||||
constructor(public name: string, public value: any) {}
|
||||
}
|
||||
`,
|
||||
'consts.ts': `
|
||||
export var someName = 'some-name';
|
||||
export var someBool = true;
|
||||
|
@ -159,5 +195,22 @@ const FILES: Directory = {
|
|||
import {someName, someBool} from './consts';
|
||||
|
||||
@Pipe({name: someName, pure: someBool})
|
||||
export class B {}`
|
||||
export class B {}`,
|
||||
'const_expr.ts': `
|
||||
function CONST_EXPR(value: any) { return value; }
|
||||
export var bTrue = CONST_EXPR(true);
|
||||
export var bFalse = CONST_EXPR(false);
|
||||
`,
|
||||
'forwardRef.ts': `
|
||||
function forwardRef(value: any) { return value; }
|
||||
export var bTrue = forwardRef(() => true);
|
||||
export var bFalse = forwardRef(() => false);
|
||||
`,
|
||||
'newExpression.ts': `
|
||||
import {Value} from './classes';
|
||||
function CONST_EXPR(value: any) { return value; }
|
||||
function forwardRef(value: any) { return value; }
|
||||
export const someValue = new Value("name", 12);
|
||||
export const complex = CONST_EXPR(new Value("name", forwardRef(() => 12)));
|
||||
`
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue