1 /** 2 * D implementation of Jinja2 templates 3 * 4 * Copyright: 5 * Copyright (c) 2018, Maxim Tyapkin. 6 * Authors: 7 * Maxim Tyapkin 8 * License: 9 * This software is licensed under the terms of the BSD 3-clause license. 10 * The full terms of the license can be found in the LICENSE.md file. 11 */ 12 13 module djinja.djinja; 14 15 private 16 { 17 import std.meta; 18 import std.traits; 19 20 import djinja.render; 21 import djinja.lexer; 22 import djinja.parser; 23 import djinja.uninode; 24 import djinja.ast; 25 } 26 27 28 29 struct JinjaConfig 30 { 31 string exprOpBegin = "{{"; 32 string exprOpEnd = "}}"; 33 string stmtOpBegin = "{%"; 34 string stmtOpEnd = "%}"; 35 string cmntOpBegin = "{#"; 36 string cmntOpEnd = "#}"; 37 string cmntOpInline = "##"; 38 string stmtOpInline = "#"; 39 } 40 41 42 43 TemplateNode loadData(JinjaConfig config = defaultConfig)(string tmpl) 44 { 45 alias JinjaLexer = Lexer!( 46 config.exprOpBegin, 47 config.exprOpEnd, 48 config.stmtOpBegin, 49 config.stmtOpEnd, 50 config.cmntOpBegin, 51 config.cmntOpEnd, 52 config.stmtOpInline, 53 config.cmntOpInline 54 ); 55 56 Parser!JinjaLexer parser; 57 return parser.parseTree(tmpl); 58 } 59 60 61 62 TemplateNode loadFile(JinjaConfig config = defaultConfig)(string path) 63 { 64 alias JinjaLexer = Lexer!( 65 config.exprOpBegin, 66 config.exprOpEnd, 67 config.stmtOpBegin, 68 config.stmtOpEnd, 69 config.cmntOpBegin, 70 config.cmntOpEnd, 71 config.stmtOpInline, 72 config.cmntOpInline 73 ); 74 75 Parser!JinjaLexer parser; 76 return parser.parseTreeFromFile(path); 77 } 78 79 80 81 string render(T...)(TemplateNode tree) 82 { 83 alias Args = AliasSeq!T; 84 alias Idents = staticMap!(Ident, T); 85 86 auto render = new Render(tree); 87 88 auto data = UniNode.emptyObject(); 89 90 foreach (i, arg; Args) 91 { 92 static if (isSomeFunction!arg) 93 render.registerFunction!arg(Idents[i]); 94 else 95 data[Idents[i]] = arg.serialize; 96 } 97 98 return render.render(data.serialize); 99 } 100 101 102 103 string renderData(T...)(string tmpl) 104 { 105 static if (T.length > 0 && is(typeof(T[0]) == JinjaConfig)) 106 return render!(T[1 .. $])(loadData!(T[0])(tmpl)); 107 else 108 return render!(T)(loadData!defaultConfig(tmpl)); 109 } 110 111 112 113 string renderFile(T...)(string path) 114 { 115 static if (T.length > 0 && is(typeof(T[0]) == JinjaConfig)) 116 return render!(T[1 .. $])(loadFile!(T[0])(path)); 117 else 118 return render!(T)(loadFile!defaultConfig(path)); 119 } 120 121 122 123 void print(TemplateNode tree) 124 { 125 auto printer = new Printer; 126 tree.accept(printer); 127 } 128 129 130 131 private: 132 133 134 135 enum defaultConfig = JinjaConfig.init; 136 137 138 139 template Ident(alias A) 140 { 141 enum Ident = __traits(identifier, A); 142 }