1 module elemi.internal; 2 3 import std.conv; 4 import std.string; 5 import std.algorithm; 6 7 pure @safe: 8 9 static if (__traits(compiles, { import core.interpolation; })) { 10 public import core.interpolation; 11 enum withInterpolation = true; 12 13 enum isInterpolation(size_t index, Ts...) 14 = is(Ts[index] == InterpolationHeader) 15 || is(Ts[index] == InterpolationFooter) 16 || is(Ts[index] == InterpolatedLiteral!text, string text) 17 || is(Ts[index] == InterpolatedExpression!text, string text) 18 || (index > 0 && is(Ts[index-1] == InterpolatedExpression!text, string text)); 19 20 } 21 else { 22 enum withInterpolation = false; 23 enum isInterpolation(size_t index, Ts...) = false; 24 } 25 26 /// Escape HTML elements. 27 /// 28 /// Package level: input sanitization is done automatically by the library. 29 package string escapeHTML(const string text) { 30 31 // substitute doesn't work in CTFE for some reason 32 if (__ctfe) { 33 34 return text 35 .map!(ch => ch.predSwitch( 36 '<', "<", 37 '>', ">", 38 '&', "&", 39 '"', """, 40 '\'', "'", 41 .text(ch), 42 )) 43 .join; 44 45 } 46 47 else return text.substitute!( 48 `<`, "<", 49 `>`, ">", 50 `&`, "&", 51 `"`, """, 52 `'`, "'", 53 ).to!string; 54 55 } 56 57 /// Serialize attributes 58 package string serializeAttributes(string[string] attributes) { 59 60 // Generate attribute text 61 string attrHTML; 62 foreach (key, value; attributes) { 63 64 attrHTML ~= format!` %s="%s"`(key, value.escapeHTML); 65 66 } 67 68 return attrHTML; 69 70 } 71 72 package string minifyAttributes(string attrHTML) { 73 74 const ret = attrHTML.splitter("\n") 75 .map!q{ a.strip } 76 .filter!q{ a.length } 77 .join(" "); 78 79 return ret.length 80 ? " " ~ ret 81 : null; 82 83 }