Skip to content

Instantly share code, notes, and snippets.

@bz0
Last active December 16, 2017 14:13
Show Gist options
  • Save bz0/fdebc5f1857b4a9a1b055963ec38546e to your computer and use it in GitHub Desktop.
Save bz0/fdebc5f1857b4a9a1b055963ec38546e to your computer and use it in GitHub Desktop.
typescriptで書くpukiwikiパーサ
class Inline {
private match = {
strong: /^''([\s\S]+?)''(?!')/,
em: /^'''((?:[^_]|__)+?)'''(?!')/,
br: /^~(?:\n|$)|^(&br;)/,
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
}
private out: string;
private renderer: Renderer;
constructor(){
this.renderer = new Renderer();
this.out = "";
}
public strong(src: string): string {
var cap: Array<string>;
if (cap = this.match.strong.exec(src)){
src = src.substring(cap[0].length);
this.out += this.renderer.strong(src);
}
return src;
}
public em(src: string): string {
var cap: Array<string>;
if (cap = this.match.em.exec(src)){
src = src.substring(cap[0].length);
this.out += this.renderer.em(src);
}
return src;
}
public text(src: string): string {
var cap: Array<string>;
if (cap = this.match.text.exec(src)){
this.out += src;
src = src.substring(cap[0].length);
}
return src;
}
public output(src: string): string {
while(src){
src = this.strong(src);
src = this.em(src);
src = this.text(src);
}
return this.out;
}
}
class Block {
private match = {
newline: /^\n+/,
heading: /^(\*{1,4})(.*?)(?:\n+|$)/,
text: /^[^\n]+/
}
private tokens: {type:string, depth: number, text: string}[];
constructor(){
this.tokens = [];
}
public newline(src: string): string {
var cap: Array<string>;
if (cap = this.match.newline.exec(src)){
src = src.substring(cap[0].length);
this.tokens.push({
type: 'newline',
text: cap[1],
depth: 0
});
}
return src;
}
public heading(src: string): string {
var cap: Array<string>;
if (cap = this.match.heading.exec(src)){
src = src.substring(cap[0].length);
console.log(this.tokens);
this.tokens.push({
type: 'heading',
text: cap[2],
depth: cap[1].length
});
}
return src;
}
public text(src: string): string {
var cap: Array<string>;
if (cap = this.match.text.exec(src)){
src = src.substring(cap[0].length);
this.tokens.push({
type: 'text',
text: cap[0],
depth: 0
});
}
return src;
}
public output(src: string): {type:string, depth: number, text: string}[] {
while(src){
src = this.newline(src);
src = this.heading(src);
src = this.text(src);
}
return this.tokens;
}
}
class Renderer {
public heading(text: string, depth: number): string{
return '<h' + depth + '>' + text + '<h' + depth + '>';
}
public strong(text: string): string {
return '<b>' + text + '</b>';
}
public em(text: string): string {
return '<em>' + text + '</em>';
}
public output(token: {type:string, depth: number, text: string}): string{
var src = "";
if (token.type==="heading"){
src = this.heading(token.text, token.depth);
}
return src;
}
}
class Parser{
private block:Block;
private inline:Inline;
private render:Renderer;
constructor(){
this.block = new Block();
this.inline = new Inline();
this.render = new Renderer();
}
public exec(input: string): string{
var tokens = this.block.output(input);
var output = "";
for(var i=0; i<tokens.length; i++){
tokens[i].text = this.inline.output(tokens[i].text);
output += this.render.output(tokens[i]);
}
return output;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment