- Getting started
- Tutorial - Model driven basics
- Tutorial - Full stack Angular application
- Fundamentals
- How-to
- Modeler
- Reference
Generating code from a model
In this part, you will learn how to turn your Yellicode model into actual C# code. We are going to modify the default template (csharp-tutorial.template.ts
) from part I so that it generates the C# classes and enumerations that we need.
Sharpen the code generation template
Open up csharp-tutorial.template.ts
and start by adding a new import
line that adds the C# extension that you installed in the previous step.
import { CSharpWriter } from '@yellicode/csharp';
Then change the name of the output file to ./output/Domain.cs
and replace the contents of the generateFromModel
function so that the generator function looks as follows:
Generator.generateFromModel({ outputFile: './output/Domain.cs' }, (writer: TextWriter, model: elements.Model) => { const csharp = new CSharpWriter(writer); csharp.writeUsingDirectives('System'); csharp.writeLine(); csharp.writeNamespaceBlock({name: 'CSharpTutorial.Domain'},() => { model.getAllClasses().forEach((eachClass) => { csharp.writeClassBlock(eachClass, () => { // some work to be done here }); csharp.writeLine(); }) }) });
Generate the first domain model
Let's see what the first output looks like. Run Yellicode (in watch
mode so that you only need to run this command once):
yellicode --watch
When you see the message 'Code generation done', find the output file ./output/Domain.cs
and observe the first version of our domain model.
The template enumerated all classes in your model (using the Meta Model API) and wrote an empty class declaration - including comments - for each one of them. Except that one comment is empty, because the Task
class is undocumented. Let's quickly fix this!
Go back to Yellicode Modeler, find the Task
class and enter a description (hint: A task is a discrete piece of work required to complete a story). Now save the model (make sure to unfocus out of the description input first), go back to the output file and notice your new comments.
Completing the generated code
Now let's complete the generated C# code by adding auto-properties and enumerations. First, update the writeClassBlock
call as follows:
csharp.writeClassBlock(eachClass, () => { eachClass.ownedAttributes.forEach(p => { csharp.writeAutoProperty(p); csharp.writeLine(); }) });
Save the template, observe the terminal output and wait for the 'Code generation done.' message. Now we're really getting somewhere, you should see that a property is generated for each attribute (that's the UML term for a property) in your model.
Side note: the ownedAttributes
property returns all attributes that are defined on a class, excluding inherited properties. The Class element also has a getAllAttributes()
function that includes all inherited properties (which we obviously don't need here).
The current output would not compile because we are still missing enumerations that some of the classes depend on. This is a simple four-liner to be added to your template:
model.getAllEnumerations().forEach((eachEnum) => { csharp.writeEnumeration(eachEnum); csharp.writeLine(); })
The final template
Your final template should now look as follows:
import { TextWriter } from '@yellicode/core'; import { Generator } from '@yellicode/templating'; import * as elements from '@yellicode/elements'; import { CSharpWriter } from '@yellicode/csharp'; Generator.generateFromModel({ outputFile: './output/Domain.cs' }, (writer: TextWriter, model: elements.Model) => { const csharp = new CSharpWriter(writer); csharp.writeUsingDirectives('System'); csharp.writeLine(); csharp.writeNamespaceBlock({ name: 'CSharpTutorial.Domain' }, () => { // Generate enumerations model.getAllEnumerations().forEach((eachEnum) => { csharp.writeEnumeration(eachEnum); csharp.writeLine(); }) // Generate classes model.getAllClasses().forEach((eachClass) => { csharp.writeClassBlock(eachClass, () => { eachClass.ownedAttributes.forEach(p => { csharp.writeAutoProperty(p); csharp.writeLine(); }) }); csharp.writeLine(); }) }) });
If you haven't done so, save the template again and wait for the enumerations to appear.
Note that the generated enumerations have an explicit integer value. Obviously, this is not mandatory (but you might prefer them). You can see where the values come from when you open the enumeration in Yellicode Modeler and observe the Enumeration Literals section.
Generating each class in its own file
You might prefer to generate each class in its own .cs file. This is outside the scope of this tutorial, but is a pretty simple change to the structure of your template. We will leave that as an exercise for the reader.
This completes the second part of this tutorial. In the next part, you will see how we can bring .NET types into the mix.
Continue to Part II - Using framework-specific types »