fix(compiler): disallow references for select and index evaluation

Also fixes an issue where enum values of 0 or '``' where not treated
correctly.

Fixes: #18170
This commit is contained in:
Chuck Jazdzewski 2017-09-29 11:51:08 -07:00 committed by Alex Rickabaugh
parent 9ae3742565
commit f3f4c3d835
2 changed files with 152 additions and 4 deletions

View File

@ -444,7 +444,7 @@ export class StaticReflector implements CompileReflector {
} else { } else {
const staticSymbol = expression; const staticSymbol = expression;
const declarationValue = resolveReferenceValue(staticSymbol); const declarationValue = resolveReferenceValue(staticSymbol);
if (declarationValue) { if (declarationValue != null) {
return simplifyInContext(staticSymbol, declarationValue, depth + 1, references); return simplifyInContext(staticSymbol, declarationValue, depth + 1, references);
} else { } else {
return staticSymbol; return staticSymbol;
@ -522,8 +522,8 @@ export class StaticReflector implements CompileReflector {
} }
return null; return null;
case 'index': case 'index':
let indexTarget = simplify(expression['expression']); let indexTarget = simplifyInContext(context, expression['expression'], depth, 0);
let index = simplify(expression['index']); let index = simplifyInContext(context, expression['index'], depth, 0);
if (indexTarget && isPrimitive(index)) return indexTarget[index]; if (indexTarget && isPrimitive(index)) return indexTarget[index];
return null; return null;
case 'select': case 'select':
@ -535,7 +535,7 @@ export class StaticReflector implements CompileReflector {
selectContext = selectContext =
self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members); self.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
const declarationValue = resolveReferenceValue(selectContext); const declarationValue = resolveReferenceValue(selectContext);
if (declarationValue) { if (declarationValue != null) {
return simplifyInContext( return simplifyInContext(
selectContext, declarationValue, depth + 1, references); selectContext, declarationValue, depth + 1, references);
} else { } else {

View File

@ -914,6 +914,154 @@ describe('StaticReflector', () => {
.toEqual([{data: {c: [3]}}]); .toEqual([{data: {c: [3]}}]);
}); });
// Regression #18170
it('should evaluate enums and statics that are 0', () => {
const data = Object.create(DEFAULT_TEST_DATA);
const file = '/tmp/src/my_component.ts';
data[file] = `
import {Component} from '@angular/core';
import {provideRoutes} from './macro';
import {MyEnum, MyClass} from './consts';
@Component({
template: '<div></div>',
providers: [provideRoutes({
path: 'foo',
data: {
e: MyEnum.Value
}
})]
})
export class MyComponent { }
`;
data['/tmp/src/macro.ts'] = `
import {ANALYZE_FOR_ENTRY_COMPONENTS, ROUTES} from '@angular/core';
export interface Route {
path?: string;
data?: any;
}
export type Routes = Route[];
export function provideRoutes(routes: Routes): any {
return [
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: routes},
{provide: ROUTES, multi: true, useValue: routes},
];
}
`;
data['/tmp/src/consts.ts'] = `
export enum MyEnum {
Value = 0,
}
`;
init(data);
expect(reflector.annotations(reflector.getStaticSymbol(file, 'MyComponent'))[0]
.providers[0][0]
.useValue)
.toEqual({path: 'foo', data: {e: 0}});
});
// Regression #18170
it('should agressively evaluate enums selects', () => {
const data = Object.create(DEFAULT_TEST_DATA);
const file = '/tmp/src/my_component.ts';
data[file] = `
import {Component} from '@angular/core';
import {provideRoutes} from './macro';
import {E} from './indirect';
@Component({
template: '<div></div>',
providers: [provideRoutes({
path: 'foo',
data: {
e: E.Value,
}
})]
})
export class MyComponent { }
`;
data['/tmp/src/macro.ts'] = `
import {ANALYZE_FOR_ENTRY_COMPONENTS, ROUTES} from '@angular/core';
export interface Route {
path?: string;
data?: any;
}
export type Routes = Route[];
export function provideRoutes(routes: Routes): any {
return [
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: routes},
{provide: ROUTES, multi: true, useValue: routes},
];
}
`;
data['/tmp/src/indirect.ts'] = `
import {MyEnum} from './consts';
export const E = MyEnum;
`,
data['/tmp/src/consts.ts'] = `
export enum MyEnum {
Value = 1,
}
`;
init(data);
expect(reflector.annotations(reflector.getStaticSymbol(file, 'MyComponent'))[0]
.providers[0][0]
.useValue)
.toEqual({path: 'foo', data: {e: 1}});
});
// Regression #18170
it('should agressively evaluate array indexes', () => {
const data = Object.create(DEFAULT_TEST_DATA);
const file = '/tmp/src/my_component.ts';
data[file] = `
import {Component} from '@angular/core';
import {provideRoutes} from './macro';
import {E} from './indirect';
@Component({
template: '<div></div>',
providers: [provideRoutes({
path: 'foo',
data: {
e: E[E[E[1]]],
}
})]
})
export class MyComponent { }
`;
data['/tmp/src/macro.ts'] = `
import {ANALYZE_FOR_ENTRY_COMPONENTS, ROUTES} from '@angular/core';
export interface Route {
path?: string;
data?: any;
}
export type Routes = Route[];
export function provideRoutes(routes: Routes): any {
return [
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: routes},
{provide: ROUTES, multi: true, useValue: routes},
];
}
`;
data['/tmp/src/indirect.ts'] = `
import {A} from './consts';
export const E = A;
`,
data['/tmp/src/consts.ts'] = `
export const A = [0, 1];
`;
init(data);
expect(reflector.annotations(reflector.getStaticSymbol(file, 'MyComponent'))[0]
.providers[0][0]
.useValue)
.toEqual({path: 'foo', data: {e: 1}});
});
}); });
const DEFAULT_TEST_DATA: {[key: string]: any} = { const DEFAULT_TEST_DATA: {[key: string]: any} = {