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 }