1 module nxt.sourced; 2 3 import nxt.path : Path, exists; 4 5 /++ JSON value with origin path. 6 7 TODO: generalize (templated) to any value. 8 TODO: generalize (templated) to any URL. 9 +/ 10 struct SourcedJSON { 11 import std.json : JSONValue, parseJSON; 12 Path path; ///< Path of `value` serialized to string. 13 JSONValue value; ///< JSON value. 14 bool outdated; ///< Is true if value needs has been changed since read from path. 15 16 /++ Uses parameter `Path` in ctor instead of `fromFile`. 17 See: https://docs.rs/from_file/latest/from_file/ 18 +/ 19 this(Path path, bool silentPassUponFailure = false) @safe { 20 import std.file : readText; 21 this.path = path; 22 this.value = silentPassUponFailure ? 23 (path.exists ? 24 readText(path.str).parseJSON : 25 JSONValue.emptyObject) : 26 readText(path.str).parseJSON; 27 } 28 29 ~this() const { 30 if (outdated) 31 writeBack(); 32 } 33 34 void writeBack(in bool pretty = true) const { 35 import std.stdio : File; 36 import std.json : JSONOptions; 37 if (pretty) { 38 static if (__traits(hasMember, JSONValue, "toPrettyString")) { 39 static if (is(typeof(value.toPrettyString(File(path, "w").lockingBinaryWriter, JSONOptions.doNotEscapeSlashes)))) { 40 value.toPrettyString(File(path, "w").lockingBinaryWriter, JSONOptions.doNotEscapeSlashes); 41 } else { 42 File(path.str, "w").write(value.toPrettyString(JSONOptions.doNotEscapeSlashes)); 43 } 44 } else { 45 static assert(0); 46 } 47 } else { 48 static if (__traits(hasMember, JSONValue, "toString")) { 49 File(path.str, "w").write(value.toString(JSONOptions.doNotEscapeSlashes)); 50 } else { 51 File(path.str, "w").write(value.to!string()); 52 } 53 } 54 } 55 } 56 57 /// 58 @safe unittest { 59 /+ TODO: const x = SourcedJSON(Path("")); +/ 60 }