All files / metadata controllerGenerator.ts

89.19% Statements 33/37
62.5% Branches 10/16
100% Functions 13/13
96.88% Lines 31/32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 621x   1x   1x     32x 32x     1x 32x     1x 1x 1x   1x   1x               1x 1x 2x 2x 2x 2x     1x 32x     1x 32x   1x 1x   1x 1x     1x 1x       1x 1x     1x  
import * as ts from 'typescript';
import { Controller } from './metadataGenerator';
import { MethodGenerator } from './methodGenerator';
 
export class ControllerGenerator {
    private readonly pathValue: string | undefined;
 
    constructor(private readonly node: ts.ClassDeclaration) {
        this.pathValue = this.getControllerRouteValue(node);
    }
 
    public IsValid() {
        return !!this.pathValue || this.pathValue === '';
    }
 
    public Generate(): Controller {
        Iif (!this.node.parent) { throw new Error('Controller node doesn\'t have a valid parent source file.'); }
        Iif (!this.node.name) { throw new Error('Controller node doesn\'t have a valid name.'); }
 
        const sourceFile = this.node.parent.getSourceFile();
 
        return {
            location: sourceFile.fileName,
            methods: this.buildMethods(),
            name: this.node.name.text,
            path: this.pathValue || ''
        };
    }
 
    private buildMethods() {
        return this.node.members
            .filter(m => m.kind === ts.SyntaxKind.MethodDeclaration)
            .map((m: ts.MethodDeclaration) => new MethodGenerator(m))
            .filter(generator => generator.IsValid())
            .map(generator => generator.Generate());
    }
 
    private getControllerRouteValue(node: ts.ClassDeclaration) {
        return this.getControllerDecoratorValue(node, 'Path', '');
    }
 
    private getControllerDecoratorValue(node: ts.ClassDeclaration, decoratorName: string, defaultValue: string) {
        if (!node.decorators) { return undefined; }
 
        const matchedAttributes = node.decorators
            .map(d => d.expression as ts.CallExpression)
            .filter(expression => {
                const subExpression = expression.expression as ts.Identifier;
                return subExpression.text === decoratorName;
            });
 
        Iif (!matchedAttributes.length) { return undefined; }
        Iif (matchedAttributes.length > 1) {
            throw new Error(`A controller can only have a single ${decoratorName} decorator in \`${(this.node.name as any).text}\` class.`);
        }
 
        const value = matchedAttributes[0].arguments[0] as ts.StringLiteral;
        return value ? value.text : defaultValue;
    }
 
}