Representing our converted markdown using a markdown document
While we are parsing our content, we need a mechanism to actually store the text that we are creating during the parsing process. We could just use a global string and update it directly, but that would become problematic if we decided to asynchronously add to it later on. The main reason for not using a string is down to Single Responsibility Principle again. If we were using a simple string, then each piece of code that we add to the text would end up having to write to the string in the correct way, which means that they would be mixing reading the markdown with writing to the HTML output. When we discuss it like that, it becomes apparent that we need to have a separate means of writing the HTML content out.
What this means for us is that we are going to want code that can accept a number of strings to form the content (these could include our HTML tags, so we don't want to just accept a single string). We also want a means of getting our document when we have finished building it up. We are going to start by defining an interface, which will act as the contract that consuming code will implement. Of particular interest here is that we are going to allow our code to accept any number of items in our Add method, so we will be using a REST parameter here:
interface IMarkdownDocument {
Add(...content : string[]) : void;
Get() : string;
}
Given this interface, we can create our MarkdownDocument class as follows:
class MarkdownDocument implements IMarkdownDocument {
private content : string = "";
Add(...content: string[]): void {
content.forEach(element => {
this.content += element;
});
}
Get(): string {
return this.content;
}
}
This class is incredibly straightforward. For each piece of content passed in to our Add method, we add it to a member variable called content. As this is declared as private, our Get method returns the same variable. This is why I like having classes with a single responsibility—in this case, they are just updating the content; they tend to be a lot cleaner and easier to understand than convoluted classes that do many different things. The main thing is that we can do whatever we like to keep our content updated internally, as we have hidden how we maintain the document from the consuming code.
As we are going to be parsing our document one line at a time, we are going to use a class to represent the current line that we are processing:
class ParseElement {
CurrentLine : string = "";
}
Our class is very simple. Again, we have decided not to go with a simple string to pass around our code base because this class makes our intent clear—we want to parse the current line. If we had just used a string to represent the line, it would be too easy to pass the wrong thing when we wanted to use the line.