refactor(ivy): implement `NgccReflectionHost.findDecoratedFiles` (#26082)
PR Close #26082
This commit is contained in:
parent
d17602f31d
commit
7f03528dbc
|
@ -12,9 +12,9 @@ import * as ts from 'typescript';
|
||||||
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from '../../ngtsc/annotations';
|
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ResourceLoader, SelectorScopeRegistry} from '../../ngtsc/annotations';
|
||||||
import {CompileResult, DecoratorHandler} from '../../ngtsc/transform';
|
import {CompileResult, DecoratorHandler} from '../../ngtsc/transform';
|
||||||
|
|
||||||
import {NgccReflectionHost} from './host/ngcc_host';
|
|
||||||
import {DecoratedClass} from './host/decorated_class';
|
import {DecoratedClass} from './host/decorated_class';
|
||||||
import {DecoratedFile} from './host/decorated_file';
|
import {DecoratedFile} from './host/decorated_file';
|
||||||
|
import {NgccReflectionHost} from './host/ngcc_host';
|
||||||
import {isDefined} from './utils';
|
import {isDefined} from './utils';
|
||||||
|
|
||||||
export interface AnalyzedClass<A = any, M = any> extends DecoratedClass {
|
export interface AnalyzedClass<A = any, M = any> extends DecoratedClass {
|
||||||
|
|
|
@ -7,9 +7,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter} from '../../../ngtsc/host';
|
import {ClassMember, ClassMemberKind, Decorator, FunctionDefinition, Parameter} from '../../../ngtsc/host';
|
||||||
import {reflectObjectLiteral} from '../../../ngtsc/metadata';
|
import {reflectObjectLiteral} from '../../../ngtsc/metadata';
|
||||||
import {getNameText} from '../utils';
|
import {getNameText, getOriginalSymbol, isDefined} from '../utils';
|
||||||
|
|
||||||
|
import {DecoratedClass} from './decorated_class';
|
||||||
|
import {DecoratedFile} from './decorated_file';
|
||||||
import {Fesm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './fesm2015_host';
|
import {Fesm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignmentStatement} from './fesm2015_host';
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,6 +125,42 @@ export class Esm5ReflectionHost extends Fesm2015ReflectionHost {
|
||||||
return {node, body: statements || null, parameters};
|
return {node, body: statements || null, parameters};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all the files accessible via an entry-point, that contain decorated classes.
|
||||||
|
* @param entryPoint The starting point file for finding files that contain decorated classes.
|
||||||
|
* @returns A collection of files objects that hold info about the decorated classes and import
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
|
findDecoratedFiles(entryPoint: ts.SourceFile): DecoratedFile[] {
|
||||||
|
const moduleSymbol = this.checker.getSymbolAtLocation(entryPoint);
|
||||||
|
const map = new Map<ts.SourceFile, DecoratedFile>();
|
||||||
|
const getParsedClass = (declaration: ts.VariableDeclaration) => {
|
||||||
|
const decorators = this.getDecoratorsOfDeclaration(declaration);
|
||||||
|
if (decorators) {
|
||||||
|
return new DecoratedClass(getNameText(declaration.name), declaration, decorators);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (moduleSymbol) {
|
||||||
|
const classDeclarations = this.checker.getExportsOfModule(moduleSymbol)
|
||||||
|
.map(getOriginalSymbol(this.checker))
|
||||||
|
.map(exportSymbol => exportSymbol.valueDeclaration)
|
||||||
|
.filter(isDefined)
|
||||||
|
.filter(ts.isVariableDeclaration);
|
||||||
|
|
||||||
|
const decoratedClasses = classDeclarations.map(getParsedClass).filter(isDefined);
|
||||||
|
|
||||||
|
decoratedClasses.forEach(clazz => {
|
||||||
|
const file = clazz.declaration.getSourceFile();
|
||||||
|
if (!map.has(file)) {
|
||||||
|
map.set(file, new DecoratedFile(file));
|
||||||
|
}
|
||||||
|
map.get(file) !.decoratedClasses.push(clazz);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Array.from(map.values());
|
||||||
|
}
|
||||||
|
|
||||||
///////////// Protected Helpers /////////////
|
///////////// Protected Helpers /////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,8 +11,10 @@ import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host';
|
import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host';
|
||||||
import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata';
|
import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata';
|
||||||
import {findAll, getNameText, isDefined} from '../utils';
|
import {findAll, getNameText, getOriginalSymbol, isDefined} from '../utils';
|
||||||
|
|
||||||
|
import {DecoratedClass} from './decorated_class';
|
||||||
|
import {DecoratedFile} from './decorated_file';
|
||||||
import {NgccReflectionHost, PRE_NGCC_MARKER, SwitchableVariableDeclaration, isSwitchableVariableDeclaration} from './ngcc_host';
|
import {NgccReflectionHost, PRE_NGCC_MARKER, SwitchableVariableDeclaration, isSwitchableVariableDeclaration} from './ngcc_host';
|
||||||
|
|
||||||
export const DECORATORS = 'decorators' as ts.__String;
|
export const DECORATORS = 'decorators' as ts.__String;
|
||||||
|
@ -294,6 +296,48 @@ export class Fesm2015ReflectionHost extends TypeScriptReflectionHost implements
|
||||||
return super.getImportOfIdentifier(id) || this.getImportOfNamespacedIdentifier(id);
|
return super.getImportOfIdentifier(id) || this.getImportOfNamespacedIdentifier(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find all the files accessible via an entry-point, that contain decorated classes.
|
||||||
|
* @param entryPoint The starting point file for finding files that contain decorated classes.
|
||||||
|
* @returns A collection of files objects that hold info about the decorated classes and import
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
|
findDecoratedFiles(entryPoint: ts.SourceFile): DecoratedFile[] {
|
||||||
|
const moduleSymbol = this.checker.getSymbolAtLocation(entryPoint);
|
||||||
|
const map = new Map<ts.SourceFile, DecoratedFile>();
|
||||||
|
if (moduleSymbol) {
|
||||||
|
const exportedSymbols =
|
||||||
|
this.checker.getExportsOfModule(moduleSymbol).map(getOriginalSymbol(this.checker));
|
||||||
|
const exportedDeclarations =
|
||||||
|
exportedSymbols.map(exportSymbol => exportSymbol.valueDeclaration).filter(isDefined);
|
||||||
|
|
||||||
|
const decoratedClasses =
|
||||||
|
exportedDeclarations
|
||||||
|
.map(declaration => {
|
||||||
|
if (ts.isClassDeclaration(declaration) || ts.isVariableDeclaration(declaration)) {
|
||||||
|
const name = declaration.name && ts.isIdentifier(declaration.name) ?
|
||||||
|
declaration.name.text :
|
||||||
|
undefined;
|
||||||
|
const decorators = this.getDecoratorsOfDeclaration(declaration);
|
||||||
|
return decorators && isDefined(name) ?
|
||||||
|
new DecoratedClass(name, declaration, decorators) :
|
||||||
|
undefined;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
})
|
||||||
|
.filter(isDefined);
|
||||||
|
|
||||||
|
decoratedClasses.forEach(clazz => {
|
||||||
|
const file = clazz.declaration.getSourceFile();
|
||||||
|
if (!map.has(file)) {
|
||||||
|
map.set(file, new DecoratedFile(file));
|
||||||
|
}
|
||||||
|
map.get(file) !.decoratedClasses.push(clazz);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Array.from(map.values());
|
||||||
|
}
|
||||||
|
|
||||||
///////////// Protected Helpers /////////////
|
///////////// Protected Helpers /////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import {ReflectionHost} from '../../../ngtsc/host';
|
import {ReflectionHost} from '../../../ngtsc/host';
|
||||||
|
import {DecoratedFile} from './decorated_file';
|
||||||
|
|
||||||
export const PRE_NGCC_MARKER = '__PRE_NGCC__';
|
export const PRE_NGCC_MARKER = '__PRE_NGCC__';
|
||||||
export const POST_NGCC_MARKER = '__POST_NGCC__';
|
export const POST_NGCC_MARKER = '__POST_NGCC__';
|
||||||
|
@ -37,4 +38,12 @@ export interface NgccReflectionHost extends ReflectionHost {
|
||||||
* @returns An array of variable declarations that match.
|
* @returns An array of variable declarations that match.
|
||||||
*/
|
*/
|
||||||
getSwitchableDeclarations(module: ts.Node): SwitchableVariableDeclaration[];
|
getSwitchableDeclarations(module: ts.Node): SwitchableVariableDeclaration[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all the files accessible via an entry-point, that contain decorated classes.
|
||||||
|
* @param entryPoint The starting point file for finding files that contain decorated classes.
|
||||||
|
* @returns A collection of files objects that hold info about the decorated classes and import
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
|
findDecoratedFiles(entryPoint: ts.SourceFile): DecoratedFile[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
|
||||||
import {DecoratedClass} from '../host/decorated_class';
|
import {DecoratedClass} from '../host/decorated_class';
|
||||||
import {DecoratedFile} from '../host/decorated_file';
|
import {DecoratedFile} from '../host/decorated_file';
|
||||||
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {getOriginalSymbol, isDefined} from '../utils';
|
import {getOriginalSymbol, isDefined} from '../utils';
|
||||||
|
|
||||||
import {FileParser} from './file_parser';
|
import {FileParser} from './file_parser';
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {NgccReflectionHost} from '../host/ngcc_host';
|
|
||||||
import {DecoratedClass} from '../host/decorated_class';
|
import {DecoratedClass} from '../host/decorated_class';
|
||||||
import {DecoratedFile} from '../host/decorated_file';
|
import {DecoratedFile} from '../host/decorated_file';
|
||||||
|
import {NgccReflectionHost} from '../host/ngcc_host';
|
||||||
import {getNameText, getOriginalSymbol, isDefined} from '../utils';
|
import {getNameText, getOriginalSymbol, isDefined} from '../utils';
|
||||||
|
|
||||||
import {FileParser} from './file_parser';
|
import {FileParser} from './file_parser';
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {Decorator} from '../../ngtsc/host';
|
import {Decorator} from '../../ngtsc/host';
|
||||||
import {DecoratorHandler} from '../../ngtsc/transform';
|
import {DecoratorHandler} from '../../ngtsc/transform';
|
||||||
import {AnalyzedFile, Analyzer} from '../src/analyzer';
|
import {AnalyzedFile, Analyzer} from '../src/analyzer';
|
||||||
import {Fesm2015ReflectionHost} from '../src/host/fesm2015_host';
|
|
||||||
import {DecoratedClass} from '../src/host/decorated_class';
|
import {DecoratedClass} from '../src/host/decorated_class';
|
||||||
import {DecoratedFile} from '../src/host/decorated_file';
|
import {DecoratedFile} from '../src/host/decorated_file';
|
||||||
|
import {Fesm2015ReflectionHost} from '../src/host/fesm2015_host';
|
||||||
|
|
||||||
import {getDeclaration, makeProgram} from './helpers/utils';
|
import {getDeclaration, makeProgram} from './helpers/utils';
|
||||||
|
|
||||||
const TEST_PROGRAM = {
|
const TEST_PROGRAM = {
|
||||||
|
|
|
@ -50,6 +50,39 @@ const MARKER_FILE = {
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DECORATED_FILES = [
|
||||||
|
{
|
||||||
|
name: '/primary.js',
|
||||||
|
contents: `
|
||||||
|
import {Directive} from '@angular/core';
|
||||||
|
class A {}
|
||||||
|
A.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[a]' }] }
|
||||||
|
];
|
||||||
|
function x() {}
|
||||||
|
function y() {}
|
||||||
|
class B {}
|
||||||
|
B.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[b]' }] }
|
||||||
|
];
|
||||||
|
class C {}
|
||||||
|
export { A, x, C };
|
||||||
|
export { D } from '/secondary';
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '/secondary.js',
|
||||||
|
contents: `
|
||||||
|
import {Directive} from '@angular/core';
|
||||||
|
class D {}
|
||||||
|
D.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[d]' }] }
|
||||||
|
];
|
||||||
|
export { D };
|
||||||
|
`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
describe('Esm2015ReflectionHost', () => {
|
describe('Esm2015ReflectionHost', () => {
|
||||||
describe('getGenericArityOfClass()', () => {
|
describe('getGenericArityOfClass()', () => {
|
||||||
it('should properly count type parameters', () => {
|
it('should properly count type parameters', () => {
|
||||||
|
@ -84,4 +117,28 @@ describe('Esm2015ReflectionHost', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('findDecoratedFiles()', () => {
|
||||||
|
it('should return an array of objects for each file that has exported and decorated classes',
|
||||||
|
() => {
|
||||||
|
const program = makeProgram(...DECORATED_FILES);
|
||||||
|
const dtsMapper = new DtsMapper('/src', '/typings');
|
||||||
|
const host = new Esm2015ReflectionHost(false, program.getTypeChecker(), dtsMapper);
|
||||||
|
const decoratedFiles =
|
||||||
|
host.findDecoratedFiles(program.getSourceFile(DECORATED_FILES[0].name) !);
|
||||||
|
expect(decoratedFiles.length).toEqual(2);
|
||||||
|
const primary = decoratedFiles[0];
|
||||||
|
expect(primary.decoratedClasses.length).toEqual(1);
|
||||||
|
const classA = primary.decoratedClasses.find(c => c.name === 'A') !;
|
||||||
|
expect(classA.name).toEqual('A');
|
||||||
|
expect(ts.isClassDeclaration(classA.declaration)).toBeTruthy();
|
||||||
|
expect(classA.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
|
||||||
|
const secondary = decoratedFiles[1];
|
||||||
|
expect(secondary.decoratedClasses.length).toEqual(1);
|
||||||
|
const classD = secondary.decoratedClasses.find(c => c.name === 'D') !;
|
||||||
|
expect(classD.name).toEqual('D');
|
||||||
|
expect(ts.isClassDeclaration(classD.declaration)).toBeTruthy();
|
||||||
|
expect(classD.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -427,6 +427,51 @@ const FUNCTION_BODY_FILE = {
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DECORATED_FILES = [
|
||||||
|
{
|
||||||
|
name: '/primary.js',
|
||||||
|
contents: `
|
||||||
|
import {Directive} from '@angular/core';
|
||||||
|
var A = (function() {
|
||||||
|
function A() {}
|
||||||
|
A.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[a]' }] }
|
||||||
|
];
|
||||||
|
return A;
|
||||||
|
}());
|
||||||
|
var B = (function() {
|
||||||
|
function B() {}
|
||||||
|
B.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[b]' }] }
|
||||||
|
];
|
||||||
|
return B;
|
||||||
|
}());
|
||||||
|
function x() {}
|
||||||
|
function y() {}
|
||||||
|
var C = (function() {
|
||||||
|
function C() {}
|
||||||
|
return C;
|
||||||
|
});
|
||||||
|
export { A, x, C };
|
||||||
|
export { D } from '/secondary';
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '/secondary.js',
|
||||||
|
contents: `
|
||||||
|
import {Directive} from '@angular/core';
|
||||||
|
var D = (function() {
|
||||||
|
function D() {}
|
||||||
|
D.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[d]' }] }
|
||||||
|
];
|
||||||
|
return D;
|
||||||
|
}());
|
||||||
|
export { D };
|
||||||
|
`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
describe('Esm5ReflectionHost', () => {
|
describe('Esm5ReflectionHost', () => {
|
||||||
|
|
||||||
describe('getDecoratorsOfDeclaration()', () => {
|
describe('getDecoratorsOfDeclaration()', () => {
|
||||||
|
@ -1206,4 +1251,25 @@ describe('Esm5ReflectionHost', () => {
|
||||||
expect(getClassSymbolSpy).toHaveBeenCalledWith(mockNode);
|
expect(getClassSymbolSpy).toHaveBeenCalledWith(mockNode);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('fileDecoratedFiles()', () => {
|
||||||
|
it('should return an array of objects for each file that has exported and decorated classes',
|
||||||
|
() => {
|
||||||
|
const program = makeProgram(...DECORATED_FILES);
|
||||||
|
const host = new Esm5ReflectionHost(false, program.getTypeChecker());
|
||||||
|
const decoratedFiles =
|
||||||
|
host.findDecoratedFiles(program.getSourceFile(DECORATED_FILES[0].name) !);
|
||||||
|
expect(decoratedFiles.length).toEqual(2);
|
||||||
|
const primary = decoratedFiles[0];
|
||||||
|
expect(primary.decoratedClasses.length).toEqual(1);
|
||||||
|
const classA = primary.decoratedClasses[0];
|
||||||
|
expect(classA.name).toEqual('A');
|
||||||
|
expect(classA.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
|
||||||
|
const secondary = decoratedFiles[1];
|
||||||
|
expect(secondary.decoratedClasses.length).toEqual(1);
|
||||||
|
const classD = secondary.decoratedClasses[0];
|
||||||
|
expect(classD.name).toEqual('D');
|
||||||
|
expect(classD.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -392,6 +392,37 @@ const MARKER_FILE = {
|
||||||
`
|
`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DECORATED_FILE = {
|
||||||
|
name: '/primary.js',
|
||||||
|
contents: `
|
||||||
|
import {Directive} from '@angular/core';
|
||||||
|
class A {}
|
||||||
|
A.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[a]' }] }
|
||||||
|
];
|
||||||
|
|
||||||
|
class B {}
|
||||||
|
B.decorators = [
|
||||||
|
{ type: Directive, args: [{ selector: '[b]' }] }
|
||||||
|
];
|
||||||
|
|
||||||
|
function x() {}
|
||||||
|
|
||||||
|
function y() {}
|
||||||
|
|
||||||
|
class C {}
|
||||||
|
|
||||||
|
let D = class D {}
|
||||||
|
D = tslib_1.__decorate([
|
||||||
|
Directive({ selector: '[d]' }),
|
||||||
|
OtherD()
|
||||||
|
], D);
|
||||||
|
export {D};
|
||||||
|
|
||||||
|
export { A, x, C };
|
||||||
|
`
|
||||||
|
};
|
||||||
|
|
||||||
describe('Fesm2015ReflectionHost', () => {
|
describe('Fesm2015ReflectionHost', () => {
|
||||||
|
|
||||||
describe('getDecoratorsOfDeclaration()', () => {
|
describe('getDecoratorsOfDeclaration()', () => {
|
||||||
|
@ -1152,4 +1183,29 @@ describe('Fesm2015ReflectionHost', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('findDecoratedFiles()', () => {
|
||||||
|
it('should return an array of objects for each file that has exported and decorated classes',
|
||||||
|
() => {
|
||||||
|
const program = makeProgram(DECORATED_FILE);
|
||||||
|
const host = new Fesm2015ReflectionHost(false, program.getTypeChecker());
|
||||||
|
const decoratedFiles =
|
||||||
|
host.findDecoratedFiles(program.getSourceFile(DECORATED_FILE.name) !);
|
||||||
|
expect(decoratedFiles.length).toEqual(1);
|
||||||
|
const decoratedClasses = decoratedFiles[0].decoratedClasses;
|
||||||
|
expect(decoratedClasses.length).toEqual(2);
|
||||||
|
|
||||||
|
const decoratedClassA = decoratedClasses.find(c => c.name === 'A') !;
|
||||||
|
expect(decoratedClassA.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
|
||||||
|
expect(decoratedClassA.decorators.map(
|
||||||
|
decorator => decorator.args && decorator.args.map(arg => arg.getText())))
|
||||||
|
.toEqual([[`{ selector: '[a]' }`]]);
|
||||||
|
|
||||||
|
const decoratedClassD = decoratedClasses.find(c => c.name === 'D') !;
|
||||||
|
expect(decoratedClassD.decorators.map(decorator => decorator.name)).toEqual(['Directive']);
|
||||||
|
expect(decoratedClassD.decorators.map(
|
||||||
|
decorator => decorator.args && decorator.args.map(arg => arg.getText())))
|
||||||
|
.toEqual([[`{ selector: '[d]' }`]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue