Creating custom transforms

In the model transforms section, we've discussed some of the built in transforms that can be applied to a model. However, it's very easy to create your own transformations too. Let's build two simple transforms: one that renames interface types and one that excludes certain elements from code generation.

A custom InterfacePrefixerTransform

In this example, we are building a transform that prefixes the name of each Interface with a "I".

import * as elements from '@yellicode/elements';
import { RenamingTransform, RenameTargets } from '@yellicode/templating';

export class InterfacePrefixerTransform extends RenamingTransform {    
    constructor() {
        super(RenameTargets.interfaces);        
    }

    protected rename(name: string, target: elements.Element): string {
        return `I${name}`;
    }
}    

As you can see, our transform derives from the abstract RenamingTransform class and limits it's target elements to interfaces only. All we needed to do is to implement the rename function.

Note that this example is merely used as a starting point. We could have also used the built in PrefixingTransform directly instead of implementing a custom one.

A custom PublicClassesOnlyTransform

Say that we only wanted to generate code for classes with public visibility. We could filter out these classes in our template code, but we can also create a custom transform:

import * as elements from '@yellicode/elements';
import { PackagedElementTransform } from '@yellicode/templating';

export class PublicClassesOnlyTransform extends PackagedElementTransform {

    protected transformElement(element: elements.PackageableElement) {
        if (!elements.isPackage(element)) return;
        
        // The element is a Package (or the root Model, which is also Package).
        // Filter this package's packagedElements to include only public classes and nested packages.
        element.packagedElements = element.packagedElements
            .filter(pe => elements.isPackage(pe) || (elements.isClass(pe) && pe.visibility === elements.VisibilityKind.public));                
    }
}

This example derives from the abstract PackagedElementTransform class. The PackagedElementTransform invokes an abstract transformElement function for each element (such as a Class, Interface or other Package) that is owned by a package (including packages nested in other packages).