Mixing in custom code

Adding your own code to generated code is risky as when you re-generate the code, your changes will be overwritten. Therefore, Yellicode allows you to write you custom code in one or more separate files and merge designated regions from these files with the generated code.

Your target programming language might also have a way to blend code from different files. For C#, for example, you can generate partial classes and methods to split a class, struct or interface method over two or more sources. For TypeScript, there is a feature request for partial classes, which we hope will make it into a future release.

Merging regions from other files

Say we want to generate a TypeScript class named Person having a firstName and a lastName property. For simplicity, we will not create a model but hard-code the class as follows:

import { Generator, TextWriter } from '@yellicode/templating';

Generator.generate({ outputFile: './person.ts' },
    (writer: TextWriter) => {
        writer.writeLine('export class Person {');
        writer.increaseIndent();
        writer.writeLine('public firstName: string;')
        writer.writeLine('public lastName: string;')
        writer.decreaseIndent();
        writer.writeLine('}');
    }
);

But, what if we wanted to add a function that returns the person's full name? This is not the kind of code that you would typically generate, so let's create a separate file named custom-code.partial.template.ts for this:

export class Person {
    /// <person-functions>
    public getFullName() {
        return `${this.firstName} ${this.lastName}`;
    }
    /// </person-functions>
}

Note the region markers in the file. These markers let our template locate the regions to be pulled in. To do so, extend the template as follows, adding a single call to writeFileRegion:

import { Generator, TextWriter } from '@yellicode/templating';

Generator.generate({ outputFile: 'person.ts' },
    (writer: TextWriter) => {
        writer.writeLine('export class Person {');
        writer.increaseIndent();
        writer.writeLine('public firstName: string;')
        writer.writeLine('public lastName: string;')
        writer.writeFileRegion('person-functions', './custom-code.partial.template.ts');
        writer.decreaseIndent();
        writer.writeLine(`}`);
    }
);

If you haven't done so, start Yellicode and watch the resulting person.ts file.

Customizing the region marker format

The format of the region start- and end markers in the partial file might not work well with the programming language you are targeting. You can customize this format by creating your own implementation of the RegionMarkerFormatter interface. Say we want to use the marker format #start my-region-name ... code here ... #end my-region-name, the formatter implementation would look as follows:

import { RegionMarkerFormatter } from '@yellicode/templating';

export class CustomMarkerFormatter implements RegionMarkerFormatter {
    public getRegionStartMarker(regionName: string): string {
        return `#start ${regionName}`;
    }
    
    public getRegionEndMarker(regionName: string): string {
        return `#end ${regionName}`;
    }
}

Then, we would apply this formatter to the template as follows, assuming the custom formatter to be in a file named custom-marker-formatter.ts.

import { Generator, TextWriter } from '@yellicode/templating';
import { CustomMarkerFormatter } from './custom-marker-formatter';

Generator.generate({ outputFile: 'person.ts', regionMarkerFormatter: new CustomMarkerFormatter() },
    (writer: TextWriter) => {
        // code here stays the same
    }
);