1 module dhtags.utils.html; 2 3 string escape(string str) { 4 import std.array : join; 5 import std.conv : to; 6 7 string[] result; 8 foreach (c; str) { 9 switch (c) { 10 case '"': result ~= """; break; 11 case '&': result ~= "&"; break; 12 case '>': result ~= ">"; break; 13 case '<': result ~= "<"; break; 14 default: result ~= c.to!string; 15 } 16 } 17 return result.join; 18 } 19 20 /** Strip the left margin for a multi-line string and remove newlines */ 21 string stripMargin(string s) { 22 import std..string : splitLines, stripLeft; 23 import std.algorithm : map; 24 import std.array : join; 25 return s.splitLines.map!(line => line.stripLeft).join; 26 } 27 28 /** 29 * Convert a value of any type to a string. 30 * We need to handle floating point values separately because the 'to' function can't convert these to a string at compile-time. 31 */ 32 string asString(alias value)() { 33 import std.math : floor; 34 import std.conv : to; 35 36 string doubleToString(double d)() { 37 return d.stringof; 38 } 39 40 alias TVal = typeof(cast(const) value); 41 42 if (__ctfe) { 43 static if (is(TVal == const(float)) || is(TVal == const(double))) { 44 enum double val = value; 45 return doubleToString!(val)(); 46 } else { 47 return value.to!string; 48 } 49 } else { 50 return value.to!string; 51 } 52 } 53 54 /** 55 * Convert a lower camelcase string to snake case. 56 * We can't use regex to match at compile-time so we'll iterate through the string and convert it manually. 57 */ 58 pure string camelCaseToHyphens(string s) { 59 import std.array : join; 60 import std.range : enumerate; 61 import std.algorithm : map; 62 import std.ascii : isUpper, isLower; 63 import std..string : toLower; 64 import std.conv : to; 65 66 return s.enumerate.map!((t) { 67 if (isUpper(t.value)) { 68 if (t.index > 0 && (isLower(s[t.index - 1]) || (t.index < s.length - 1 && isLower(s[t.index + 1])))) { 69 return "-" ~ t.value.toLower.to!string; 70 } else { 71 return t.value.toLower.to!string; 72 } 73 } else { 74 return t.value.to!string; 75 } 76 }).join; 77 } 78 79 /** 80 * Convert a hyphen-separated string to a lower camelcase string. 81 */ 82 pure string hyphenToCamelCase(string s) { 83 import std.array : join; 84 import std.ascii : toUpper; 85 import std.algorithm : map; 86 import std.range : enumerate; 87 import std.conv : to; 88 89 return s.enumerate.map!((t) { 90 if (t.value == '-') { 91 return ""; 92 } else { 93 return (t.index > 0 && (s[t.index - 1] == '-')) ? t.value.toUpper.to!string : t.value.to!string; 94 } 95 }).join; 96 } 97 98 /** 99 * Replace hyphens with underscores so it can be used in mixin as a symbol. 100 */ 101 pure string hyphenToUnderscores(string s) { 102 import std..string : replace; 103 return s.replace("-", "_"); 104 } 105 106 /** 107 * Replace underscores with hyphens to get the actual attribute name 108 */ 109 pure string underscoreToHyphens(string s) { 110 import std..string : replace; 111 return s.replace("_", "-"); 112 } 113 114 string mixinTempls(List...)() { 115 import std..string : format; 116 static if (List.length) { 117 return format("mixin %s;", List[0].stringof) ~ mixinTempls!(List[1 .. $]); 118 } else { return ""; } 119 }