Last active
March 28, 2020 06:23
-
-
Save masterashu/56841a48fa132e59ba003a68e3a1e7f2 to your computer and use it in GitHub Desktop.
Mini YAML Writer utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
getObjects() sync* { | |
var obj = Map<String, dynamic>(); | |
obj['Hello'] = 'World'; | |
obj['Users'] = [ | |
'192.168.13.25', | |
'192.168.1.3', | |
<String>['192.168.13.25', '192.168.1.3', '192.168.1.3'] | |
]; | |
obj['Home'] = <String>['localhost', '127.0.0.1']; | |
yield obj; | |
var obj2 = Map<String, dynamic>(); | |
obj2['Hello'] = 'World'; | |
obj2['Users'] = [ | |
'192.168.13.25', | |
'192.168.1.3', | |
Map<String, dynamic>.fromIterables(["ABCD", "EFGH"], [132, 3353.3]), | |
]; | |
obj2['Home'] = <String>['localhost', '127.0.0.1']; | |
yield obj2; | |
var obj3 = Map<dynamic, dynamic>(); | |
obj3[<String>['localhost', '127.0.0.1']] = 'World'; | |
obj3[<String>['192.168.13.25', '192.168.1.3', '192.168.1.3']] = [ | |
<String>['192.168.13.25', '192.168.1.3', '192.168.1.3'], | |
]; | |
obj3[Map<dynamic, dynamic>.fromIterables([ | |
["ABCD", "EFGH"] | |
], [ | |
[132, 3353.3] | |
])] = ['localhost', '127.0.0.1', 1324, 4636343]; | |
yield obj3; | |
} | |
class YamlWriter { | |
static bool isScalar(node) => (node is String || node is num || node is bool); | |
/// Maximum no. of columns before line break occurs | |
final int maxColumns; | |
/// Maximum length of colums when scalar is printed in folding | |
final int foldingColumnLength; | |
/// Output File stream where to write | |
StringBuffer outputStream; | |
/// List of indentations | |
var _indents = <int>[0]; | |
/// current starting indentation | |
int get indent => _indents.last; | |
/// Increases the indentation of the writer | |
void addIndent() => _indents.add(indent + 2); | |
/// Decreses the indentation of the writer | |
void popIndent() => _indents.removeLast(); | |
/// Resets the indentation to Zero | |
void resetIndent() => _indents.removeWhere((n) => n > 0); | |
/// Position of current writing column | |
var column = 0; | |
/// write an Object to the output stream | |
void writeDocument(Object document) { | |
resetIndent(); | |
writeDocumentStart(); | |
if (document is String || document is num || document is bool) { | |
writeScalar(document); | |
} else { | |
writeNode(document); | |
} | |
resetIndent(); | |
writeDocumentEnd(); | |
} | |
void writeMap(Map map) { | |
for (var key in map.keys) { | |
bool complexKey = false; | |
writeIndent(); | |
if (isScalar(key)) { | |
writeScalar(key); | |
} else if (key is Map) { | |
writeKeyEntry(); | |
writeMap(key); | |
complexKey = true; | |
} else if (key is List) { | |
writeKeyEntry(); | |
writeList(key); | |
complexKey = true; | |
} else { | |
print('Unknown type of object'); | |
} | |
if (complexKey) popIndent(); | |
writeValueEntry(complexKey); | |
var value = map[key]; | |
if (isScalar(value)) { | |
writeScalar(value); | |
} else if (value is Map) { | |
writeNewLine(); | |
writeMap(value); | |
} else if (value is List) { | |
writeNewLine(); | |
writeList(value); | |
} else { | |
print('Unknown type of object'); | |
} | |
popIndent(); | |
if (column != 0) writeNewLine(); | |
} | |
} | |
void writeList(List list) { | |
for (var node in list) { | |
writeIndent(); | |
writeListEntry(); | |
if (isScalar(node)) { | |
writeScalar(node); | |
} else if (node is Map) { | |
addIndent(); | |
writeNewLine(); | |
writeMap(node); | |
popIndent(); | |
} else if (node is List) { | |
addIndent(); | |
writeNewLine(); | |
writeList(node); | |
popIndent(); | |
} else { | |
print('Unknown type of object'); | |
} | |
if (column != 0) writeNewLine(); | |
} | |
} | |
void writeNode(Object node) { | |
if (node is Map) { | |
writeMap(node); | |
} else if (node is List) { | |
writeList(node); | |
} else { | |
writeScalar(node); | |
} | |
} | |
void writeScalar(Object scalar) { | |
var value = scalar.toString(); | |
if (value.length > foldingColumnLength) { | |
return writeBlockScalar(scalar); | |
} | |
if (value.contains(RegExp(r'(\r)|(\n)|(\r\n)'))) { | |
if (value.length <= foldingColumnLength) { | |
return writeQuotedScalar(scalar); | |
} else { | |
return writeBlockScalar(scalar); | |
} | |
} | |
outputStream.write('$value'); | |
column += value.length; | |
} | |
void writeBlockScalar(Object scalar, [bool folded = true]) { | |
outputStream.write('${folded ? '>' : '|'}'); | |
writeNewLine(); | |
writeIndent(); | |
bool lastCR = false; | |
var buffer = StringBuffer(); | |
for (var ch in scalar.toString().codeUnits) { | |
if (lastCR) { | |
lastCR = false; | |
continue; | |
} | |
switch (ch) { | |
case CharCode.CR: | |
lastCR = true; | |
continue; | |
case CharCode.LF: | |
if (lastCR) break; | |
var word = buffer.toString(); | |
buffer.clear(); | |
if (folded) { | |
if (column - indent + word.length > foldingColumnLength) { | |
writeNewLine(); | |
writeIndent(); | |
} | |
outputStream.write(word); | |
writeNewLine(); | |
writeIndent(); | |
outputStream.write(' '); | |
} else { | |
outputStream.write(word); | |
writeNewLine(); | |
writeIndent(); | |
} | |
break; | |
case CharCode.SP: | |
var word = buffer.toString(); | |
buffer.clear(); | |
if (folded && (column - indent + word.length > foldingColumnLength)) { | |
writeNewLine(); | |
writeIndent(); | |
} | |
outputStream.write(word + ' '); | |
break; | |
default: | |
buffer.write(String.fromCharCode(ch)); | |
} | |
column++; | |
} | |
if (buffer.isNotEmpty) outputStream.write(buffer.toString()); | |
} | |
writeQuotedScalar(Object scalar, [bool single = false]) { | |
bool lastCR = false; | |
outputStream.write('${single ? "'" : '"'}'); | |
for (var ch in scalar.toString().codeUnits) { | |
if (lastCR) { | |
lastCR = false; | |
continue; | |
} | |
switch (ch) { | |
case CharCode.CR: | |
lastCR = true; | |
continue; | |
case CharCode.LF: | |
outputStream.write('\\n'); | |
break; | |
case CharCode.TAB: | |
outputStream.write('\\t'); | |
break; | |
case CharCode.SINGLE_QUOTE: | |
outputStream.write('${single ? "''" : "'"}'); | |
break; | |
case CharCode.DOUBLE_QUOTE: | |
outputStream.write('${single ? '"' : '\"'}'); | |
break; | |
default: | |
outputStream.write(String.fromCharCode(ch)); | |
} | |
column++; | |
} | |
outputStream.write('${single ? "'" : '"'}'); | |
} | |
void writeIndent() { | |
outputStream.write(' ' * indent); | |
column += indent; | |
} | |
void writeListEntry() { | |
outputStream.write('- '); | |
column += 2; | |
} | |
void writeKeyEntry() { | |
outputStream.write('? '); | |
addIndent(); | |
writeNewLine(); | |
} | |
void writeValueEntry([bool complexKey = false]) { | |
if (complexKey) writeIndent(); | |
outputStream.write(': '); | |
column += 2; | |
addIndent(); | |
} | |
void writeNewLine() { | |
outputStream.write('\n'); | |
column = 0; | |
} | |
void writeDocumentStart() { | |
outputStream.write('---'); | |
writeNewLine(); | |
} | |
void writeDocumentEnd() { | |
outputStream.write('---'); | |
writeNewLine(); | |
} | |
YamlWriter({ | |
this.outputStream, | |
this.maxColumns = 80, | |
this.foldingColumnLength = 40, | |
}) { | |
assert(outputStream != null); | |
} | |
} | |
class CharCode { | |
static const TAB = 0x9; | |
static const LF = 0xA; | |
static const CR = 0xD; | |
static const SP = 0x20; | |
static const DOLLAR = 0x24; | |
static const LEFT_PAREN = 0x28; | |
static const RIGHT_PAREN = 0x29; | |
static const PLUS = 0x2B; | |
static const COMMA = 0x2C; | |
static const HYPHEN = 0x2D; | |
static const PERIOD = 0x2E; | |
static const QUESTION = 0x3F; | |
static const COLON = 0x3A; | |
static const SEMICOLON = 0x3B; | |
static const EQUALS = 0x3D; | |
static const LEFT_SQUARE = 0x5B; | |
static const RIGHT_SQUARE = 0x5D; | |
static const LEFT_CURLY = 0x7B; | |
static const RIGHT_CURLY = 0x7D; | |
static const HASH = 0x23; | |
static const AMPERSAND = 0x26; | |
static const ASTERISK = 0x2A; | |
static const EXCLAMATION = 0x21; | |
static const VERTICAL_BAR = 0x7C; | |
static const LEFT_ANGLE = 0x3C; | |
static const RIGHT_ANGLE = 0x3E; | |
static const SINGLE_QUOTE = 0x27; | |
static const DOUBLE_QUOTE = 0x22; | |
static const PERCENT = 0x25; | |
static const AT = 0x40; | |
static const GRAVE_ACCENT = 0x60; | |
static const TILDE = 0x7E; | |
static const NULL = 0x0; | |
static const BELL = 0x7; | |
static const BACKSPACE = 0x8; | |
static const VERTICAL_TAB = 0xB; | |
static const FORM_FEED = 0xC; | |
static const ESCAPE = 0x1B; | |
static const SLASH = 0x2F; | |
static const BACKSLASH = 0x5C; | |
static const UNDERSCORE = 0x5F; | |
static const NEL = 0x85; | |
static const NBSP = 0xA0; | |
static const LINE_SEPARATOR = 0x2028; | |
static const PARAGRAPH_SEPARATOR = 0x2029; | |
static const BOM = 0xFEFF; | |
static const NUMBER_0 = 0x30; | |
static const NUMBER_9 = 0x39; | |
static const LETTER_A = 0x61; | |
static const LETTER_B = 0x62; | |
static const LETTER_E = 0x65; | |
static const LETTER_F = 0x66; | |
static const LETTER_N = 0x6E; | |
static const LETTER_R = 0x72; | |
static const LETTER_T = 0x74; | |
static const LETTER_U = 0x75; | |
static const LETTER_V = 0x76; | |
static const LETTER_X = 0x78; | |
static const LETTER_Z = 0x7A; | |
static const LETTER_CAP_A = 0x41; | |
static const LETTER_CAP_F = 0x46; | |
static const LETTER_CAP_L = 0x4C; | |
static const LETTER_CAP_N = 0x4E; | |
static const LETTER_CAP_P = 0x50; | |
static const LETTER_CAP_U = 0x55; | |
static const LETTER_CAP_X = 0x58; | |
static const LETTER_CAP_Z = 0x5A; | |
} | |
main(List<String> args) { | |
var buffer = StringBuffer(); | |
var yamlWriter = YamlWriter(outputStream: buffer); | |
for (var object in getObjects()) { | |
yamlWriter.writeDocument(object); | |
} | |
print(buffer.toString()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment