Permalink
Browse files

Implement the dumper at minimal level.

  • Loading branch information...
1 parent 2f23b19 commit a6054682f7d5fd802c65731c51f453d8efee8d91 @dervus dervus committed Feb 7, 2013
View
@@ -22,6 +22,7 @@ module.exports.loadAll = loader.loadAll;
module.exports.safeLoad = loader.safeLoad;
module.exports.safeLoadAll = loader.safeLoadAll;
module.exports.dump = dumper.dump;
+module.exports.safeDump = dumper.safeDump;
module.exports.YAMLException = require('./js-yaml/exception');
module.exports.scan = deprecated('scan');
module.exports.parse = deprecated('parse');
View
@@ -1,12 +1,347 @@
'use strict';
-var YAMLException = require('./exception');
+var common = require('./common');
+var NIL = common.NIL;
+var YAMLException = require('./exception');
+var DEFAULT_SCHEMA = require('./schema/default');
+var SAFE_SCHEMA = require('./schema/safe');
-function dump(object, settings) {
- throw new YAMLException('the dumper is not implemented yet');
+var _hasOwnProperty = Object.prototype.hasOwnProperty;
+
+
+var ESCAPE_SEQUENCES = {};
+
+ESCAPE_SEQUENCES[0x00] = '\\0';
+ESCAPE_SEQUENCES[0x07] = '\\a';
+ESCAPE_SEQUENCES[0x08] = '\\b';
+ESCAPE_SEQUENCES[0x09] = '\\t';
+ESCAPE_SEQUENCES[0x0A] = '\\n';
+ESCAPE_SEQUENCES[0x0B] = '\\v';
+ESCAPE_SEQUENCES[0x0C] = '\\f';
+ESCAPE_SEQUENCES[0x0D] = '\\r';
+ESCAPE_SEQUENCES[0x1B] = '\\e';
+ESCAPE_SEQUENCES[0x22] = '\\"';
+ESCAPE_SEQUENCES[0x5C] = '\\\\';
+ESCAPE_SEQUENCES[0x85] = '\\N';
+ESCAPE_SEQUENCES[0xA0] = '\\_';
+ESCAPE_SEQUENCES[0x2028] = '\\L';
+ESCAPE_SEQUENCES[0x2029] = '\\P';
+
+
+function kindOf(object) {
+ var kind = typeof object;
+
+ if (null === object) {
+ return 'null';
+ } else if ('number' === kind) {
+ return 0 === object % 1 ? 'integer' : 'float';
+ } else if ('object' === kind && Array.isArray(object)) {
+ return 'array';
+ } else {
+ return kind;
+ }
+}
+
+
+function compileStyleMap(map) {
+ var result, keys, index, length, tagName, tagPrefix, fullTagName;
+
+ if (null === map) {
+ return {};
+ }
+
+ result = {};
+ keys = Object.keys(map);
+
+ for (index = 0, length = keys.length; index < length; index += 1) {
+ tagName = keys[index];
+ tagPrefix = tagName.slice(0, 2);
+
+ if ('!!' === tagPrefix) {
+ fullTagName = 'tag:yaml.org,2002:' + tagName.slice(2);
+ result[fullTagName] = map[tagName];
+ } else {
+ result[tagName] = map[tagName];
+ }
+ }
+
+ return result;
+}
+
+
+function encodeHex(character) {
+ var string, handle, length;
+
+ string = character.toString(16).toUpperCase();
+
+ if (character <= 0xFF) {
+ handle = 'x';
+ length = 2;
+ } else if (character <= 0xFFFF) {
+ handle = 'u';
+ length = 4;
+ } else if (character <= 0xFFFFFFFF) {
+ handle = 'U';
+ length = 8;
+ } else {
+ throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF');
+ }
+
+ return '\\' + handle + common.repeat('0', length - string.length) + string;
+}
+
+
+function dump(input, settings) {
+ var schema = common.getOption(settings, 'schema', DEFAULT_SCHEMA),
+ indent = Math.max(1, common.getOption(settings, 'indent', 2)),
+ flowLevel = common.getOption(settings, 'flowLevel', -1),
+ styleMap = compileStyleMap(common.getOption(settings, 'styles', null)),
+
+ implicitTypes = schema.compiledImplicit,
+ explicitTypes = schema.compiledExplicit,
+
+ kind,
+ tag,
+ result;
+
+ function generateNextLine(level) {
+ return '\n' + common.repeat(' ', indent * level);
+ }
+
+ function writeQuotedScalar(object) {
+ var checkpoint, position, length, character;
+
+ result = '';
+ checkpoint = 0;
+
+ for (position = 0, length = object.length; position < length; position += 1) {
+ character = object.charCodeAt(position);
+
+ if (ESCAPE_SEQUENCES[character] ||
+ !((0x00020 <= character && character <= 0x00007E) ||
+ (0x00085 === character) ||
+ (0x000A0 <= character && character <= 0x00D7FF) ||
+ (0x0E000 <= character && character <= 0x00FFFD) ||
+ (0x10000 <= character && character <= 0x10FFFF))) {
+ result += object.slice(checkpoint, position);
+ result += ESCAPE_SEQUENCES[character] || encodeHex(character);
+ checkpoint = position + 1;
+ }
+ }
+
+ if (checkpoint < position) {
+ result += object.slice(checkpoint, position);
+ }
+
+ result = '"' + result + '"';
+ }
+
+ function writeFlowSequence(level, object) {
+ var _result = '',
+ _tag = tag,
+ index,
+ length;
+
+ for (index = 0, length = object.length; index < length; index += 1) {
+ if (0 !== index) {
+ _result += ', ';
+ }
+
+ writeNode(level, object[index], false, false);
+ _result += result;
+ }
+
+ tag = _tag;
+ result = '[' + _result + ']';
+ }
+
+ function writeBlockSequence(level, object, compact) {
+ var _result = '',
+ _tag = tag,
+ index,
+ length;
+
+ for (index = 0, length = object.length; index < length; index += 1) {
+ if (!compact || 0 !== index) {
+ _result += generateNextLine(level);
+ }
+
+ writeNode(level + 1, object[index], true, true);
+ _result += '- ' + result;
+ }
+
+ tag = _tag;
+ result = _result;
+ }
+
+ function writeFlowMapping(level, object) {
+ var _result = '',
+ _tag = tag,
+ objectKeyList = Object.keys(object),
+ index,
+ length,
+ objectKey,
+ objectValue;
+
+ for (index = 0, length = objectKeyList.length; index < length; index += 1) {
+ if (0 !== index) {
+ _result += ', ';
+ }
+
+ objectKey = objectKeyList[index];
+ objectValue = object[objectKey];
+
+ writeNode(level, objectKey, false, false);
+
+ if (result.length > 1024) {
+ _result += '? ';
+ }
+
+ _result += result + ': ';
+ writeNode(level, objectValue, false, false);
+ _result += result;
+ }
+
+ tag = _tag;
+ result = '{' + _result + '}';
+ }
+
+ function writeBlockMapping(level, object, compact) {
+ var _result = '',
+ _tag = tag,
+ objectKeyList = Object.keys(object),
+ index,
+ length,
+ objectKey,
+ objectValue,
+ explicitPair;
+
+ for (index = 0, length = objectKeyList.length; index < length; index += 1) {
+ if (!compact || 0 !== index) {
+ _result += generateNextLine(level);
+ }
+
+ objectKey = objectKeyList[index];
+ objectValue = object[objectKey];
+
+ writeNode(level + 1, objectKey, true, true);
+ explicitPair = (null !== tag && '?' !== tag && result.length <= 1024);
+
+ if (explicitPair) {
+ _result += '? ';
+ }
+
+ _result += result;
+
+ if (explicitPair) {
+ _result += generateNextLine(level);
+ }
+
+ writeNode(level + 1, objectValue, true, explicitPair);
+ _result += ': ' + result;
+ }
+
+ tag = _tag;
+ result = _result;
+ }
+
+ function detectType(object, explicit) {
+ var _result, typeList, index, length, type, style;
+
+ typeList = explicit ? explicitTypes : implicitTypes;
+ kind = kindOf(object);
+
+ for (index = 0, length = typeList.length; index < length; index += 1) {
+ type = typeList[index];
+
+ if ((null !== type.dumper) &&
+ (null === type.dumper.kind || kind === type.dumper.kind) &&
+ (null === type.dumper.instanceOf || object instanceof type.dumper.instanceOf) &&
+ (null === type.dumper.predicate || type.dumper.predicate(object))) {
+ tag = explicit ? type.tag : '?';
+
+ if (null !== type.dumper.representer) {
+ style = styleMap[type.tag] || type.dumper.defaultStyle;
+
+ if ('function' === typeof type.dumper.representer) {
+ _result = type.dumper.representer(object, style);
+ } else if (_hasOwnProperty.call(type.dumper.representer, style)) {
+ _result = type.dumper.representer[style](object, style);
+ } else {
+ throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
+ }
+
+ if (NIL !== _result) {
+ kind = kindOf(_result);
+ result = _result;
+ } else {
+ if (explicit) {
+ throw new YAMLException('cannot represent an object of !<' + type.tag + '> type');
+ } else {
+ continue;
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function writeNode(level, object, block, compact) {
+ tag = null;
+ result = object;
+
+ if (!detectType(object, false)) {
+ detectType(object, true);
+ }
+
+ if (block) {
+ block = (0 > flowLevel || flowLevel > level);
+ }
+
+ if ((null !== tag && '?' !== tag) || (2 !== indent && level > 0)) {
+ compact = false;
+ }
+
+ if ('object' === kind) {
+ if (block) {
+ writeBlockMapping(level, result, compact);
+ } else {
+ writeFlowMapping(level, result);
+ }
+ } else if ('array' === kind) {
+ if (block) {
+ writeBlockSequence(level, result, compact);
+ } else {
+ writeFlowSequence(level, result);
+ }
+ } else if ('string' === kind) {
+ if ('?' !== tag) {
+ writeQuotedScalar(result);
+ }
+ } else {
+ throw new YAMLException('unacceptabe kind of an object to dump (' + kind + ')');
+ }
+
+ if (null !== tag && '?' !== tag) {
+ result = '!<' + tag + '> ' + result;
+ }
+ }
+
+ writeNode(0, input, true, true);
+ return result;
+}
+
+
+function safeDump(input, settings) {
+ return dump(input, common.extend({ schema: SAFE_SCHEMA }, settings));
}
-module.exports.dump = dump;
+module.exports.dump = dump;
+module.exports.safeDump = safeDump;
View
@@ -38,16 +38,21 @@ Type.Loader = function TypeLoader(settings) {
Type.Dumper = function TypeDumper(settings) {
- this.kind = common.getSetting(settings, 'kind');
- this.instanceOf = common.getOption(settings, 'instanceOf', null);
- this.predicate = common.getOption(settings, 'predicate', null);
- this.representer = common.getOption(settings, 'representer', null);
-
- if ('integer' !== this.kind &&
- 'float' !== this.kind &&
- 'string' !== this.kind &&
- 'array' !== this.kind &&
- 'object' !== this.kind) {
+ this.kind = common.getSetting(settings, 'kind');
+ this.defaultStyle = common.getOption(settings, 'defaultStyle', null);
+ this.instanceOf = common.getOption(settings, 'instanceOf', null);
+ this.predicate = common.getOption(settings, 'predicate', null);
+ this.representer = common.getOption(settings, 'representer', null);
+
+ if ('undefined' !== this.kind &&
+ 'null' !== this.kind &&
+ 'boolean' !== this.kind &&
+ 'integer' !== this.kind &&
+ 'float' !== this.kind &&
+ 'string' !== this.kind &&
+ 'array' !== this.kind &&
+ 'object' !== this.kind &&
+ 'function' !== this.kind) {
throw new YAMLException('Unacceptable "kind" setting of a type dumper.');
}
};
Oops, something went wrong.

0 comments on commit a605468

Please sign in to comment.