'use strict'; var common = require('./common'); var NIL = common.NIL; var YAMLException = require('./exception'); var DEFAULT_SCHEMA = require('./schema/default'); var SAFE_SCHEMA = require('./schema/safe'); var _hasOwnProperty = Object.prototype.hasOwnProperty; var CHAR_TAB = 0x09; /* Tab */ var CHAR_LINE_FEED = 0x0A; /* LF */ var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ var CHAR_SPACE = 0x20; /* Space */ var CHAR_EXCLAMATION = 0x21; /* ! */ var CHAR_DOUBLE_QUOTE = 0x22; /* " */ var CHAR_SHARP = 0x23; /* # */ var CHAR_PERCENT = 0x25; /* % */ var CHAR_AMPERSAND = 0x26; /* & */ var CHAR_SINGLE_QUOTE = 0x27; /* ' */ var CHAR_ASTERISK = 0x2A; /* * */ var CHAR_COMMA = 0x2C; /* , */ var CHAR_MINUS = 0x2D; /* - */ var CHAR_COLON = 0x3A; /* : */ var CHAR_GREATER_THAN = 0x3E; /* > */ var CHAR_QUESTION = 0x3F; /* ? */ var CHAR_COMMERCIAL_AT = 0x40; /* @ */ var CHAR_LEFT_SQUARE_BRACKET = 0x5B; /* [ */ var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */ var CHAR_GRAVE_ACCENT = 0x60; /* ` */ var CHAR_LEFT_CURLY_BRACKET = 0x7B; /* { */ var CHAR_VERTICAL_LINE = 0x7C; /* | */ var CHAR_RIGHT_CURLY_BRACKET = 0x7D; /* } */ 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(schema, map) { var result, keys, index, length, tag, style, type; if (null === map) { return {}; } result = {}; keys = Object.keys(map); for (index = 0, length = keys.length; index < length; index += 1) { tag = keys[index]; style = String(map[tag]); if ('!!' === tag.slice(0, 2)) { tag = 'tag:yaml.org,2002:' + tag.slice(2); } type = schema.compiledTypeMap[tag]; if (type && type.dumper) { if (_hasOwnProperty.call(type.dumper.styleAliases, style)) { style = type.dumper.styleAliases[style]; } } result[tag] = style; } 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, options) { options = options || {}; var schema = options['schema'] || DEFAULT_SCHEMA, indent = Math.max(1, (options['indent'] || 2)), flowLevel = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']), styleMap = compileStyleMap(schema, options['styles'] || null), implicitTypes = schema.compiledImplicit, explicitTypes = schema.compiledExplicit, kind, tag, result; function generateNextLine(level) { return '\n' + common.repeat(' ', indent * level); } function testImplicitResolving(object) { var index, length, type; for (index = 0, length = implicitTypes.length; index < length; index += 1) { type = implicitTypes[index]; if (null !== type.loader && NIL !== type.loader.resolver(object, false)) { return true; } } return false; } function writeScalar(object) { var isQuoted, checkpoint, position, length, character; result = ''; isQuoted = false; checkpoint = 0; if (0 === object.length || CHAR_SPACE === object.charCodeAt(0) || CHAR_SPACE === object.charCodeAt(object.length - 1)) { isQuoted = true; } for (position = 0, length = object.length; position < length; position += 1) { character = object.charCodeAt(position); if (!isQuoted) { if (CHAR_TAB === character || CHAR_LINE_FEED === character || CHAR_CARRIAGE_RETURN === character || CHAR_COMMA === character || CHAR_LEFT_SQUARE_BRACKET === character || CHAR_RIGHT_SQUARE_BRACKET === character || CHAR_LEFT_CURLY_BRACKET === character || CHAR_RIGHT_CURLY_BRACKET === character || CHAR_SHARP === character || CHAR_AMPERSAND === character || CHAR_ASTERISK === character || CHAR_EXCLAMATION === character || CHAR_VERTICAL_LINE === character || CHAR_GREATER_THAN === character || CHAR_SINGLE_QUOTE === character || CHAR_DOUBLE_QUOTE === character || CHAR_PERCENT === character || CHAR_COMMERCIAL_AT === character || CHAR_GRAVE_ACCENT === character || CHAR_QUESTION === character || CHAR_COLON === character || CHAR_MINUS === character) { isQuoted = true; } } 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; isQuoted = true; } } if (checkpoint < position) { result += object.slice(checkpoint, position); } if (!isQuoted && testImplicitResolving(result)) { isQuoted = true; } if (isQuoted) { 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 && (0 !== Object.keys(result).length)) { writeBlockMapping(level, result, compact); } else { writeFlowMapping(level, result); } } else if ('array' === kind) { if (block && (0 !== result.length)) { writeBlockSequence(level, result, compact); } else { writeFlowSequence(level, result); } } else if ('string' === kind) { if ('?' !== tag) { writeScalar(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 + '\n'; } function safeDump(input, options) { return dump(input, common.extend({ schema: SAFE_SCHEMA }, options)); } module.exports.dump = dump; module.exports.safeDump = safeDump;