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:
parent
9ae3742565
commit
f3f4c3d835
|
@ -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 {
|
||||||
|
|
|
@ -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} = {
|
||||||
|
|
Loading…
Reference in New Issue