feat(core): support metadata reflection for native class types (#22356)
closes #21731 PR Close #22356
This commit is contained in:
parent
3e6a86fb0a
commit
5c89d6bffa
|
@ -15,9 +15,12 @@ import {GetterFn, MethodFn, SetterFn} from './types';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attention: This regex has to hold even if the code is minified!
|
* Attention: These regex has to hold even if the code is minified!
|
||||||
*/
|
*/
|
||||||
export const DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
|
export const DELEGATE_CTOR = /^function\s+\S+\(\)\s*{[\s\S]+\.apply\(this,\s*arguments\)/;
|
||||||
|
export const INHERITED_CLASS = /^class\s+[A-Za-z\d$_]*\s*extends\s+[A-Za-z\d$_]+\s*{/;
|
||||||
|
export const INHERITED_CLASS_WITH_CTOR =
|
||||||
|
/^class\s+[A-Za-z\d$_]*\s*extends\s+[A-Za-z\d$_]+\s*{[\s\S]*constructor\s*\(/;
|
||||||
|
|
||||||
export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
private _reflect: any;
|
private _reflect: any;
|
||||||
|
@ -57,6 +60,7 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _ownParameters(type: Type<any>, parentCtor: any): any[][]|null {
|
private _ownParameters(type: Type<any>, parentCtor: any): any[][]|null {
|
||||||
|
const typeStr = type.toString();
|
||||||
// If we have no decorators, we only have function.length as metadata.
|
// If we have no decorators, we only have function.length as metadata.
|
||||||
// In that case, to detect whether a child class declared an own constructor or not,
|
// In that case, to detect whether a child class declared an own constructor or not,
|
||||||
// we need to look inside of that constructor to check whether it is
|
// we need to look inside of that constructor to check whether it is
|
||||||
|
@ -64,7 +68,8 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities {
|
||||||
// This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
|
// This also helps to work around for https://github.com/Microsoft/TypeScript/issues/12439
|
||||||
// that sets 'design:paramtypes' to []
|
// that sets 'design:paramtypes' to []
|
||||||
// if a class inherits from another class but has no ctor declared itself.
|
// if a class inherits from another class but has no ctor declared itself.
|
||||||
if (DELEGATE_CTOR.exec(type.toString())) {
|
if (DELEGATE_CTOR.exec(typeStr) ||
|
||||||
|
(INHERITED_CLASS.exec(typeStr) && !INHERITED_CLASS_WITH_CTOR.exec(typeStr))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Reflector} from '@angular/core/src/reflection/reflection';
|
import {Reflector} from '@angular/core/src/reflection/reflection';
|
||||||
import {DELEGATE_CTOR, ReflectionCapabilities} from '@angular/core/src/reflection/reflection_capabilities';
|
import {DELEGATE_CTOR, INHERITED_CLASS, INHERITED_CLASS_WITH_CTOR, ReflectionCapabilities} from '@angular/core/src/reflection/reflection_capabilities';
|
||||||
import {global} from '@angular/core/src/util';
|
import {global} from '@angular/core/src/util';
|
||||||
import {makeDecorator, makeParamDecorator, makePropDecorator} from '@angular/core/src/util/decorators';
|
import {makeDecorator, makeParamDecorator, makePropDecorator} from '@angular/core/src/util/decorators';
|
||||||
|
|
||||||
|
@ -188,6 +188,41 @@ class TestObj {
|
||||||
Object.defineProperty(dummyArrowFn, 'prototype', {value: undefined});
|
Object.defineProperty(dummyArrowFn, 'prototype', {value: undefined});
|
||||||
expect(() => reflector.annotations(dummyArrowFn as any)).not.toThrow();
|
expect(() => reflector.annotations(dummyArrowFn as any)).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support native class', () => {
|
||||||
|
const ChildNoCtor = `class ChildNoCtor extends Parent {}\n`;
|
||||||
|
const ChildWithCtor = `class ChildWithCtor extends Parent {\n` +
|
||||||
|
` constructor() { super(); }` +
|
||||||
|
`}\n`;
|
||||||
|
const ChildNoCtorPrivateProps = `class ChildNoCtorPrivateProps extends Parent {\n` +
|
||||||
|
` private x = 10;\n` +
|
||||||
|
`}\n`;
|
||||||
|
|
||||||
|
const checkNoOwnMetadata = (str: string) =>
|
||||||
|
INHERITED_CLASS.exec(str) && !INHERITED_CLASS_WITH_CTOR.exec(str);
|
||||||
|
|
||||||
|
expect(checkNoOwnMetadata(ChildNoCtor)).toBeTruthy();
|
||||||
|
expect(checkNoOwnMetadata(ChildNoCtorPrivateProps)).toBeTruthy();
|
||||||
|
expect(checkNoOwnMetadata(ChildWithCtor)).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should properly handle all class forms', () => {
|
||||||
|
const ctor = (str: string) => expect(INHERITED_CLASS.exec(str)).toBeTruthy() &&
|
||||||
|
expect(INHERITED_CLASS_WITH_CTOR.exec(str)).toBeTruthy();
|
||||||
|
const noCtor = (str: string) => expect(INHERITED_CLASS.exec(str)).toBeTruthy() &&
|
||||||
|
expect(INHERITED_CLASS_WITH_CTOR.exec(str)).toBeFalsy();
|
||||||
|
|
||||||
|
ctor(`class Bar extends Foo {constructor(){}}`);
|
||||||
|
ctor(`class Bar extends Foo { constructor ( ) {} }`);
|
||||||
|
ctor(`class Bar extends Foo { other(){}; constructor(){} }`);
|
||||||
|
|
||||||
|
noCtor(`class extends Foo{}`);
|
||||||
|
noCtor(`class extends Foo {}`);
|
||||||
|
noCtor(`class Bar extends Foo {}`);
|
||||||
|
noCtor(`class $Bar1_ extends $Fo0_ {}`);
|
||||||
|
noCtor(`class Bar extends Foo { other(){} }`);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('inheritance with decorators', () => {
|
describe('inheritance with decorators', () => {
|
||||||
|
|
Loading…
Reference in New Issue