diff options
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/json2yaml | 70 | ||||
-rw-r--r-- | bin/yaml.js | 2087 | ||||
-rw-r--r-- | bin/yaml.min.js | 21 | ||||
-rwxr-xr-x | bin/yaml2json | 89 |
4 files changed, 101 insertions, 2166 deletions
diff --git a/bin/json2yaml b/bin/json2yaml index 4e92bf8..f0a8791 100755 --- a/bin/json2yaml +++ b/bin/json2yaml @@ -4,7 +4,7 @@ * yaml2json cli program */ -var YAML = require('./yaml.js'); +var YAML = require('../lib/Yaml.js'); var ArgumentParser = require('argparse').ArgumentParser; var cli = new ArgumentParser({ @@ -56,7 +56,7 @@ cli.addArgument( ); cli.addArgument(['input'], { - help: 'JSON file or directory containing JSON files.' + help: 'JSON file or directory containing JSON files or - to read JSON from stdin.' }); try { @@ -67,6 +67,7 @@ try { var rootPath = process.cwd(); var parsePath = function(input) { + if (input == '-') return '-'; var output; if (!(input != null)) { return rootPath; @@ -86,33 +87,39 @@ try { // Find files var findFiles = function(input) { - var isDirectory = fs.statSync(input).isDirectory(); - var files = []; + if (input != '-' && input != null) { + var isDirectory = fs.statSync(input).isDirectory(); + var files = []; - if (!isDirectory) { - files.push(input); - } - else { - if (options.recursive) { - files = files.concat(glob.sync(input+'/**/*.json')); + if (!isDirectory) { + files.push(input); } else { - files = files.concat(glob.sync(input+'/*.json')); + if (options.recursive) { + files = files.concat(glob.sync(input+'/**/*.json')); + } + else { + files = files.concat(glob.sync(input+'/*.json')); + } } + + return files; } - - return files; + return null; }; // Convert to JSON - var convertToYAML = function(input, inline, save, spaces) { + var convertToYAML = function(input, inline, save, spaces, str) { var yaml; if (inline == null) inline = 2; if (spaces == null) spaces = 2; - yaml = YAML.stringify(JSON.parse(fs.readFileSync(input)), inline, spaces); + if (str == null) { + str = ''+fs.readFileSync(input); + } + yaml = YAML.dump(JSON.parse(str), inline, spaces); - if (!save) { + if (!save || input == null) { // Ouput result process.stdout.write(yaml); } @@ -139,18 +146,29 @@ try { var runCommand = function() { try { var files = findFiles(input); - var len = files.length; - - for (var i = 0; i < len; i++) { - var file = files[i]; - var stat = fs.statSync(file); - var time = stat.mtime.getTime(); - if (!stat.isDirectory()) { - if (!mtimes[file] || mtimes[file] < time) { - mtimes[file] = time; - convertToYAML(file, options.depth, options.save, options.indentation); + if (files != null) { + var len = files.length; + for (var i = 0; i < len; i++) { + var file = files[i]; + var stat = fs.statSync(file); + var time = stat.mtime.getTime(); + if (!stat.isDirectory()) { + if (!mtimes[file] || mtimes[file] < time) { + mtimes[file] = time; + convertToYAML(file, options.depth, options.save, options.indentation); + } } } + } else { + // Read from STDIN + var stdin = process.openStdin(); + var data = ""; + stdin.on('data', function(chunk) { + data += chunk; + }); + stdin.on('end', function() { + convertToYAML(null, options.depth, options.save, options.indentation, data); + }); } } catch (e) { process.stderr.write((e.message ? e.message : e)+"\n"); diff --git a/bin/yaml.js b/bin/yaml.js deleted file mode 100644 index 88c1a28..0000000 --- a/bin/yaml.js +++ /dev/null @@ -1,2087 +0,0 @@ -/* -Copyright (c) 2010 Jeremy Faivre - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ -(function(){ -/** - * Exception class thrown when an error occurs during parsing. - * - * @author Fabien Potencier <fabien@symfony.com> - * - * @api - */ - -/** - * Constructor. - * - * @param string message The error message - * @param integer parsedLine The line where the error occurred - * @param integer snippet The snippet of code near the problem - * @param string parsedFile The file name where the error occurred - */ - -var YamlParseException = function(message, parsedLine, snippet, parsedFile){ - - this.rawMessage = message; - this.parsedLine = (parsedLine !== undefined) ? parsedLine : -1; - this.snippet = (snippet !== undefined) ? snippet : null; - this.parsedFile = (parsedFile !== undefined) ? parsedFile : null; - - this.updateRepr(); - - this.message = message; - -}; -YamlParseException.prototype = -{ - - name: 'YamlParseException', - message: null, - - parsedFile: null, - parsedLine: -1, - snippet: null, - rawMessage: null, - - isDefined: function(input) - { - return input != undefined && input != null; - }, - - /** - * Gets the snippet of code near the error. - * - * @return string The snippet of code - */ - getSnippet: function() - { - return this.snippet; - }, - - /** - * Sets the snippet of code near the error. - * - * @param string snippet The code snippet - */ - setSnippet: function(snippet) - { - this.snippet = snippet; - - this.updateRepr(); - }, - - /** - * Gets the filename where the error occurred. - * - * This method returns null if a string is parsed. - * - * @return string The filename - */ - getParsedFile: function() - { - return this.parsedFile; - }, - - /** - * Sets the filename where the error occurred. - * - * @param string parsedFile The filename - */ - setParsedFile: function(parsedFile) - { - this.parsedFile = parsedFile; - - this.updateRepr(); - }, - - /** - * Gets the line where the error occurred. - * - * @return integer The file line - */ - getParsedLine: function() - { - return this.parsedLine; - }, - - /** - * Sets the line where the error occurred. - * - * @param integer parsedLine The file line - */ - setParsedLine: function(parsedLine) - { - this.parsedLine = parsedLine; - - this.updateRepr(); - }, - - updateRepr: function() - { - this.message = this.rawMessage; - - var dot = false; - if ('.' === this.message.charAt(this.message.length - 1)) { - this.message = this.message.substring(0, this.message.length - 1); - dot = true; - } - - if (null !== this.parsedFile) { - this.message += ' in ' + JSON.stringify(this.parsedFile); - } - - if (this.parsedLine >= 0) { - this.message += ' at line ' + this.parsedLine; - } - - if (this.snippet) { - this.message += ' (near "' + this.snippet + '")'; - } - - if (dot) { - this.message += '.'; - } - } -} -/** - * Yaml offers convenience methods to parse and dump YAML. - * - * @author Fabien Potencier <fabien@symfony.com> - * - * @api - */ - -var YamlRunningUnderNode = false; -var Yaml = function(){}; -Yaml.prototype = -{ - - /** - * Parses YAML into a JS representation. - * - * The parse method, when supplied with a YAML stream (file), - * will do its best to convert YAML in a file into a JS representation. - * - * Usage: - * <code> - * obj = yaml.parseFile('config.yml'); - * </code> - * - * @param string input Path of YAML file - * - * @return array The YAML converted to a JS representation - * - * @throws YamlParseException If the YAML is not valid - */ - parseFile: function(file /* String */, callback /* Function */) - { - if ( callback == null ) - { - var input = this.getFileContents(file); - var ret = null; - try - { - ret = this.parse(input); - } - catch ( e ) - { - if ( e instanceof YamlParseException ) { - e.setParsedFile(file); - } - throw e; - } - return ret; - } - - this.getFileContents(file, function(data) - { - callback(new Yaml().parse(data)); - }); - }, - - /** - * Parses YAML into a JS representation. - * - * The parse method, when supplied with a YAML stream (string), - * will do its best to convert YAML into a JS representation. - * - * Usage: - * <code> - * obj = yaml.parse(...); - * </code> - * - * @param string input string containing YAML - * - * @return array The YAML converted to a JS representation - * - * @throws YamlParseException If the YAML is not valid - */ - parse: function(input /* String */) - { - var yaml = new YamlParser(); - - return yaml.parse(input); - }, - - /** - * Dumps a JS representation to a YAML string. - * - * The dump method, when supplied with an array, will do its best - * to convert the array into friendly YAML. - * - * @param array array JS representation - * @param integer inline The level where you switch to inline YAML - * - * @return string A YAML string representing the original JS representation - * - * @api - */ - dump: function(array, inline, spaces) - { - if ( inline == null ) inline = 2; - - var yaml = new YamlDumper(); - if (spaces) { - yaml.numSpacesForIndentation = spaces; - } - - return yaml.dump(array, inline); - }, - - getXHR: function() - { - if ( window.XMLHttpRequest ) - return new XMLHttpRequest(); - - if ( window.ActiveXObject ) - { - var names = [ - "Msxml2.XMLHTTP.6.0", - "Msxml2.XMLHTTP.3.0", - "Msxml2.XMLHTTP", - "Microsoft.XMLHTTP" - ]; - - for ( var i = 0; i < 4; i++ ) - { - try{ return new ActiveXObject(names[i]); } - catch(e){} - } - } - return null; - }, - - getFileContents: function(file, callback) - { - if ( YamlRunningUnderNode ) - { - var fs = require('fs'); - if ( callback == null ) - { - var data = fs.readFileSync(file); - if (data == null) return null; - return ''+data; - } - else - { - fs.readFile(file, function(err, data) - { - if (err) - callback(null); - else - callback(data); - }); - } - } - else - { - var request = this.getXHR(); - - // Sync - if ( callback == null ) - { - request.open('GET', file, false); - request.send(null); - - if ( request.status == 200 || request.status == 0 ) - return request.responseText; - - return null; - } - - // Async - request.onreadystatechange = function() - { - if ( request.readyState == 4 ) - if ( request.status == 200 || request.status == 0 ) - callback(request.responseText); - else - callback(null); - }; - request.open('GET', file, true); - request.send(null); - } - } -}; - -var YAML = -{ - /* - * @param integer inline The level where you switch to inline YAML - */ - - stringify: function(input, inline, spaces) - { - return new Yaml().dump(input, inline, spaces); - }, - - parse: function(input) - { - return new Yaml().parse(input); - }, - - load: function(file, callback) - { - return new Yaml().parseFile(file, callback); - } -}; - -// Handle node.js case -if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = YAML; - YamlRunningUnderNode = true; - - // Add require handler - (function () { - var require_handler = function (module, filename) { - // fill in result - module.exports = YAML.load(filename); - }; - - // register require extensions only if we're on node.js - // hack for browserify - if ( undefined !== require.extensions ) { - require.extensions['.yml'] = require_handler; - require.extensions['.yaml'] = require_handler; - } - }()); - } -} - -// Handle browser case -if ( typeof(window) != "undefined" ) -{ - window.YAML = YAML; -} - -/** - * YamlInline implements a YAML parser/dumper for the YAML inline syntax. - */ -var YamlInline = function(){}; -YamlInline.prototype = -{ - i: null, - - /** - * Convert a YAML string to a JS object. - * - * @param string value A YAML string - * - * @return object A JS object representing the YAML string - */ - parse: function(value) - { - var result = null; - value = this.trim(value); - - if ( 0 == value.length ) - { - return ''; - } - - switch ( value.charAt(0) ) - { - case '[': - result = this.parseSequence(value); - break; - case '{': - result = this.parseMapping(value); - break; - default: - result = this.parseScalar(value); - } - - // some comment can end the scalar - if ( value.substr(this.i+1).replace(/^\s*#.*$/, '') != '' ) { - console.log("oups "+value.substr(this.i+1)); - throw new YamlParseException('Unexpected characters near "'+value.substr(this.i)+'".'); - } - - return result; - }, - - /** - * Dumps a given JS variable to a YAML string. - * - * @param mixed value The JS variable to convert - * - * @return string The YAML string representing the JS object - */ - dump: function(value) - { - if ( undefined == value || null == value ) - return 'null'; - if ( value instanceof Date) - return value.toISOString(); - if ( typeof(value) == 'object') - return this.dumpObject(value); - if ( typeof(value) == 'boolean' ) - return value ? 'true' : 'false'; - if ( /^\d+$/.test(value) ) - return typeof(value) == 'string' ? "'"+value+"'" : parseInt(value); - if ( this.isNumeric(value) ) - return typeof(value) == 'string' ? "'"+value+"'" : parseFloat(value); - if ( typeof(value) == 'number' ) - return value == Infinity ? '.Inf' : ( value == -Infinity ? '-.Inf' : ( isNaN(value) ? '.NAN' : value ) ); - var yaml = new YamlEscaper(); - if ( yaml.requiresDoubleQuoting(value) ) - return yaml.escapeWithDoubleQuotes(value); - if ( yaml.requiresSingleQuoting(value) ) - return yaml.escapeWithSingleQuotes(value); - if ( '' == value ) - return '""'; - if ( this.getTimestampRegex().test(value) ) - return "'"+value+"'"; - if ( this.inArray(value.toLowerCase(), ['null','~','true','false']) ) - return "'"+value+"'"; - // default - return value; - }, - - /** - * Dumps a JS object to a YAML string. - * - * @param object value The JS array to dump - * - * @return string The YAML string representing the JS object - */ - dumpObject: function(value) - { - var keys = this.getKeys(value); - var output = null; - var i; - var len = keys.length; - - // array - if ( value instanceof Array ) - /*( 1 == len && '0' == keys[0] ) - || - ( len > 1 && this.reduceArray(keys, function(v,w){return Math.floor(v+w);}, 0) == len * (len - 1) / 2) )*/ - { - output = []; - for ( i = 0; i < len; i++ ) - { - output.push(this.dump(value[keys[i]])); - } - - return '['+output.join(', ')+']'; - } - - // mapping - output = []; - for ( i = 0; i < len; i++ ) - { - output.push(this.dump(keys[i])+': '+this.dump(value[keys[i]])); - } - - return '{ '+output.join(', ')+' }'; - }, - - /** - * Parses a scalar to a YAML string. - * - * @param scalar scalar - * @param string delimiters - * @param object stringDelimiters - * @param integer i - * @param boolean evaluate - * - * @return string A YAML string - * - * @throws YamlParseException When malformed inline YAML string is parsed - */ - parseScalar: function(scalar, delimiters, stringDelimiters, i, evaluate) - { - if ( delimiters == undefined ) delimiters = null; - if ( stringDelimiters == undefined ) stringDelimiters = ['"', "'"]; - if ( i == undefined ) i = 0; - if ( evaluate == undefined ) evaluate = true; - - var output = null; - var pos = null; - var matches = null; - - if ( this.inArray(scalar[i], stringDelimiters) ) - { - // quoted scalar - output = this.parseQuotedScalar(scalar, i); - i = this.i; - if (null !== delimiters) { - var tmp = scalar.substr(i).replace(/^\s+/, ''); - if (!this.inArray(tmp.charAt(0), delimiters)) { - throw new YamlParseException('Unexpected characters ('+scalar.substr(i)+').'); - } - } - } - else - { - // "normal" string - if ( !delimiters ) - { - output = (scalar+'').substring(i); - - i += output.length; - - // remove comments - pos = output.indexOf(' #'); - if ( pos != -1 ) - { - output = output.substr(0, pos).replace(/\s+$/g,''); - } - } - else if ( matches = new RegExp('^(.+?)('+delimiters.join('|')+')').exec((scalar+'').substring(i)) ) - { - output = matches[1]; - i += output.length; - } - else - { - throw new YamlParseException('Malformed inline YAML string ('+scalar+').'); - } - output = evaluate ? this.evaluateScalar(output) : output; - } - - this.i = i; - - return output; - }, - - /** - * Parses a quoted scalar to YAML. - * - * @param string scalar - * @param integer i - * - * @return string A YAML string - * - * @throws YamlParseException When malformed inline YAML string is parsed - */ - parseQuotedScalar: function(scalar, i) - { - var matches = null; - //var item = /^(.*?)['"]\s*(?:[,:]|[}\]]\s*,)/.exec((scalar+'').substring(i))[1]; - - if ( !(matches = new RegExp('^'+YamlInline.REGEX_QUOTED_STRING).exec((scalar+'').substring(i))) ) - { - throw new YamlParseException('Malformed inline YAML string ('+(scalar+'').substring(i)+').'); - } - - var output = matches[0].substr(1, matches[0].length - 2); - - var unescaper = new YamlUnescaper(); - - if ( '"' == (scalar+'').charAt(i) ) - { - output = unescaper.unescapeDoubleQuotedString(output); - } - else - { - output = unescaper.unescapeSingleQuotedString(output); - } - - i += matches[0].length; - - this.i = i; - return output; - }, - - /** - * Parses a sequence to a YAML string. - * - * @param string sequence - * @param integer i - * - * @return string A YAML string - * - * @throws YamlParseException When malformed inline YAML string is parsed - */ - parseSequence: function(sequence, i) - { - if ( i == undefined ) i = 0; - - var output = []; - var len = sequence.length; - i += 1; - - // [foo, bar, ...] - while ( i < len ) - { - switch ( sequence.charAt(i) ) - { - case '[': - // nested sequence - output.push(this.parseSequence(sequence, i)); - i = this.i; - break; - case '{': - // nested mapping - output.push(this.parseMapping(sequence, i)); - i = this.i; - break; - case ']': - this.i = i; - return output; - case ',': - case ' ': - break; - default: - var isQuoted = this.inArray(sequence.charAt(i), ['"', "'"]); - var value = this.parseScalar(sequence, [',', ']'], ['"', "'"], i); - i = this.i; - - if ( !isQuoted && (value+'').indexOf(': ') != -1 ) - { - // embedded mapping? - try - { - value = this.parseMapping('{'+value+'}'); - } - catch ( e ) - { - if ( !(e instanceof YamlParseException ) ) throw e; - // no, it's not - } - } - - output.push(value); - - i--; - } - - i++; - } - - throw new YamlParseException('Malformed inline YAML string "'+sequence+'"'); - }, - - /** - * Parses a mapping to a YAML string. - * - * @param string mapping - * @param integer i - * - * @return string A YAML string - * - * @throws YamlParseException When malformed inline YAML string is parsed - */ - parseMapping: function(mapping, i) - { - if ( i == undefined ) i = 0; - var output = {}; - var len = mapping.length; - i += 1; - var done = false; - var doContinue = false; - - // {foo: bar, bar:foo, ...} - while ( i < len ) - { - doContinue = false; - - switch ( mapping.charAt(i) ) - { - case ' ': - case ',': - i++; - doContinue = true; - break; - case '}': - this.i = i; - return output; - } - - if ( doContinue ) continue; - - // key - var key = this.parseScalar(mapping, [':', ' '], ['"', "'"], i, false); - i = this.i; - - // value - done = false; - while ( i < len ) - { - switch ( mapping.charAt(i) ) - { - case '[': - // nested sequence - output[key] = this.parseSequence(mapping, i); - i = this.i; - done = true; - break; - case '{': - // nested mapping - output[key] = this.parseMapping(mapping, i); - i = this.i; - done = true; - break; - case ':': - case ' ': - break; - default: - output[key] = this.parseScalar(mapping, [',', '}'], ['"', "'"], i); - i = this.i; - done = true; - i--; - } - - ++i; - - if ( done ) - { - doContinue = true; - break; - } - } - - if ( doContinue ) continue; - } - - throw new YamlParseException('Malformed inline YAML string "'+mapping+'"'); - }, - - /** - * Evaluates scalars and replaces magic values. - * - * @param string scalar - * - * @return string A YAML string - */ - evaluateScalar: function(scalar) - { - scalar = this.trim(scalar); - - var raw = null; - var cast = null; - - if ( ( 'null' == scalar.toLowerCase() ) || - ( '' == scalar ) || - ( '~' == scalar ) ) - return null; - if ( (scalar+'').indexOf('!str ') == 0 ) - return (''+scalar).substring(5); - if ( (scalar+'').indexOf('! ') == 0 ) - return parseInt(this.parseScalar((scalar+'').substr(2))); - if ( /^\d+$/.test(scalar) ) - { - raw = scalar; - cast = parseInt(scalar); - return '0' == scalar.charAt(0) ? this.octdec(scalar) : (( ''+raw == ''+cast ) ? cast : raw); - } - if ( 'true' == (scalar+'').toLowerCase() ) - return true; - if ( 'false' == (scalar+'').toLowerCase() ) - return false; - if ( this.isNumeric(scalar) ) - return '0x' == (scalar+'').substr(0, 2) ? this.hexdec(scalar) : parseFloat(scalar); - if ( scalar.toLowerCase() == '.inf' ) - return Infinity; - if ( scalar.toLowerCase() == '.nan' ) - return NaN; - if ( scalar.toLowerCase() == '-.inf' ) - return -Infinity; - if ( /^(-|\+)?[0-9,]+(\.[0-9]+)?$/.test(scalar) ) - return parseFloat(scalar.split(',').join('')); - if ( this.getTimestampRegex().test(scalar) ) - return new Date(this.strtotime(scalar)); - //else - return ''+scalar; - }, - - /** - * Gets a regex that matches an unix timestamp - * - * @return string The regular expression - */ - getTimestampRegex: function() - { - return new RegExp('^'+ - '([0-9][0-9][0-9][0-9])'+ - '-([0-9][0-9]?)'+ - '-([0-9][0-9]?)'+ - '(?:(?:[Tt]|[ \t]+)'+ - '([0-9][0-9]?)'+ - ':([0-9][0-9])'+ - ':([0-9][0-9])'+ - '(?:\.([0-9]*))?'+ - '(?:[ \t]*(Z|([-+])([0-9][0-9]?)'+ - '(?::([0-9][0-9]))?))?)?'+ - '$','gi'); - }, - - trim: function(str /* String */) - { - return (str+'').replace(/^\s+/,'').replace(/\s+$/,''); - }, - - isNumeric: function(input) - { - return (input - 0) == input && input.length > 0 && input.replace(/\s+/g,'') != ''; - }, - - inArray: function(key, tab) - { - var i; - var len = tab.length; - for ( i = 0; i < len; i++ ) - { - if ( key == tab[i] ) return true; - } - return false; - }, - - getKeys: function(tab) - { - var ret = []; - - for ( var name in tab ) - { - if ( tab.hasOwnProperty(name) ) - { - ret.push(name); - } - } - - return ret; - }, - - /*reduceArray: function(tab, fun) - { - var len = tab.length; - if (typeof fun != "function") - throw new YamlParseException("fun is not a function"); - - // no value to return if no initial value and an empty array - if (len == 0 && arguments.length == 1) - throw new YamlParseException("empty array"); - - var i = 0; - if (arguments.length >= 2) - { - var rv = arguments[1]; - } - else - { - do - { - if (i in tab) - { - rv = tab[i++]; - break; - } - - // if array contains no values, no initial value to return - if (++i >= len) - throw new YamlParseException("no initial value to return"); - } - while (true); - } - - for (; i < len; i++) - { - if (i in tab) - rv = fun.call(null, rv, tab[i], i, tab); - } - - return rv; - },*/ - - octdec: function(input) - { - return parseInt((input+'').replace(/[^0-7]/gi, ''), 8); - }, - - hexdec: function(input) - { - input = this.trim(input); - if ( (input+'').substr(0, 2) == '0x' ) input = (input+'').substring(2); - return parseInt((input+'').replace(/[^a-f0-9]/gi, ''), 16); - }, - - /** - * @see http://phpjs.org/functions/strtotime - * @note we need timestamp with msecs so /1000 removed - * @note original contained binary | 0 (wtf?!) everywhere, which messes everything up - */ - strtotime: function (h,b){var f,c,g,k,d="";h=(h+"").replace(/\s{2,}|^\s|\s$/g," ").replace(/[\t\r\n]/g,"");if(h==="now"){return b===null||isNaN(b)?new Date().getTime()||0:b||0}else{if(!isNaN(d=Date.parse(h))){return d||0}else{if(b){b=new Date(b)}else{b=new Date()}}}h=h.toLowerCase();var e={day:{sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6},mon:["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]};var a=function(i){var o=(i[2]&&i[2]==="ago");var n=(n=i[0]==="last"?-1:1)*(o?-1:1);switch(i[0]){case"last":case"next":switch(i[1].substring(0,3)){case"yea":b.setFullYear(b.getFullYear()+n);break;case"wee":b.setDate(b.getDate()+(n*7));break;case"day":b.setDate(b.getDate()+n);break;case"hou":b.setHours(b.getHours()+n);break;case"min":b.setMinutes(b.getMinutes()+n);break;case"sec":b.setSeconds(b.getSeconds()+n);break;case"mon":if(i[1]==="month"){b.setMonth(b.getMonth()+n);break}default:var l=e.day[i[1].substring(0,3)];if(typeof l!=="undefined"){var p=l-b.getDay();if(p===0){p=7*n}else{if(p>0){if(i[0]==="last"){p-=7}}else{if(i[0]==="next"){p+=7}}}b.setDate(b.getDate()+p);b.setHours(0,0,0,0)}}break;default:if(/\d+/.test(i[0])){n*=parseInt(i[0],10);switch(i[1].substring(0,3)){case"yea":b.setFullYear(b.getFullYear()+n);break;case"mon":b.setMonth(b.getMonth()+n);break;case"wee":b.setDate(b.getDate()+(n*7));break;case"day":b.setDate(b.getDate()+n);break;case"hou":b.setHours(b.getHours()+n);break;case"min":b.setMinutes(b.getMinutes()+n);break;case"sec":b.setSeconds(b.getSeconds()+n);break}}else{return false}break}return true};g=h.match(/^(\d{2,4}-\d{2}-\d{2})(?:\s(\d{1,2}:\d{2}(:\d{2})?)?(?:\.(\d+))?)?$/);if(g!==null){if(!g[2]){g[2]="00:00:00"}else{if(!g[3]){g[2]+=":00"}}k=g[1].split(/-/g);k[1]=e.mon[k[1]-1]||k[1];k[0]=+k[0];k[0]=(k[0]>=0&&k[0]<=69)?"20"+(k[0]<10?"0"+k[0]:k[0]+""):(k[0]>=70&&k[0]<=99)?"19"+k[0]:k[0]+"";return parseInt(this.strtotime(k[2]+" "+k[1]+" "+k[0]+" "+g[2])+(g[4]?g[4]:""),10)}var j="([+-]?\\d+\\s(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday)|(last|next)\\s(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday))(\\sago)?";g=h.match(new RegExp(j,"gi"));if(g===null){return false}for(f=0,c=g.length;f<c;f++){if(!a(g[f].split(" "))){return false}}return b.getTime()||0} - -}; - -/* - * @note uses only non-capturing sub-patterns (unlike PHP original) - */ -YamlInline.REGEX_QUOTED_STRING = '(?:"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\']*(?:\'\'[^\']*)*)\')'; - - -/** - * YamlParser parses YAML strings to convert them to JS objects - * (port of Yaml Symfony Component) - */ -var YamlParser = function(offset /* Integer */) -{ - this.offset = (offset !== undefined) ? offset : 0; -}; -YamlParser.prototype = -{ - offset: 0, - lines: [], - currentLineNb: -1, - currentLine: '', - refs: {}, - - /** - * Parses a YAML string to a JS value. - * - * @param String value A YAML string - * - * @return mixed A JS value - */ - parse: function(value /* String */) - { - this.currentLineNb = -1; - this.currentLine = ''; - this.lines = this.cleanup(value).split("\n"); - - var data = null; - var context = null; - - while ( this.moveToNextLine() ) - { - if ( this.isCurrentLineEmpty() ) - { - continue; - } - - // tab? - if ( this.currentLine.charAt(0) == '\t' ) - { - throw new YamlParseException('A YAML file cannot contain tabs as indentation.', this.getRealCurrentLineNb() + 1, this.currentLine); - } - - var isRef = false; - var isInPlace = false; - var isProcessed = false; - var values = null; - var matches = null; - var c = null; - var parser = null; - var block = null; - var key = null; - var parsed = null; - var len = null; - var reverse = null; - - if ( values = /^\-((\s+)(.+?))?\s*$/.exec(this.currentLine) ) - { - - if (context && 'mapping' == context) { - throw new YamlParseException('You cannot define a sequence item when in a mapping', this.getRealCurrentLineNb() + 1, this.currentLine); - } - context = 'sequence'; - - if ( !this.isDefined(data) ) data = []; - //if ( !(data instanceof Array) ) throw new YamlParseException("Non array entry", this.getRealCurrentLineNb() + 1, this.currentLine); - - values = {leadspaces: values[2], value: values[3]}; - - if ( this.isDefined(values.value) && ( matches = /^&([^ ]+) *(.*)/.exec(values.value) ) ) - { - matches = {ref: matches[1], value: matches[2]}; - isRef = matches.ref; - values.value = matches.value; - } - - // array - if ( !this.isDefined(values.value) || '' == this.trim(values.value) || values.value.replace(/^ +/,'').charAt(0) == '#' ) - { - c = this.getRealCurrentLineNb() + 1; - parser = new YamlParser(c); - parser.refs = this.refs; - data.push(parser.parse(this.getNextEmbedBlock())); - this.refs = parser.refs; - } - else - { - if ( this.isDefined(values.leadspaces) && - ' ' == values.leadspaces && - ( matches = new RegExp('^('+YamlInline.REGEX_QUOTED_STRING+'|[^ \'"\{\[].*?) *\:(\\s+(.+?))?\\s*$').exec(values.value) ) - ) { - matches = {key: matches[1], value: matches[3]}; - // this is a compact notation element, add to next block and parse - c = this.getRealCurrentLineNb(); - parser = new YamlParser(c); - parser.refs = this.refs; - block = values.value; - - if ( !this.isNextLineIndented() ) - { - block += "\n"+this.getNextEmbedBlock(this.getCurrentLineIndentation() + 2); - } - - data.push(parser.parse(block)); - this.refs = parser.refs; - } - else - { - data.push(this.parseValue(values.value)); - } - } - } - else if ( values = new RegExp('^('+YamlInline.REGEX_QUOTED_STRING+'|[^ \'"\[\{].*?) *\:(\\s+(.+?))?\\s*$').exec(this.currentLine) ) - { - if ( !this.isDefined(data) ) data = {}; - if (context && 'sequence' == context) { - throw new YamlParseException('You cannot define a mapping item when in a sequence', this.getRealCurrentLineNb() + 1, this.currentLine); - } - context = 'mapping'; - //if ( data instanceof Array ) throw new YamlParseException("Non mapped entry", this.getRealCurrentLineNb() + 1, this.currentLine); - - values = {key: values[1], value: values[3]}; - - try { - key = new YamlInline().parseScalar(values.key); - } catch (e) { - if ( e instanceof YamlParseException ) { - e.setParsedLine(this.getRealCurrentLineNb() + 1); - e.setSnippet(this.currentLine); - } - throw e; - } - - - if ( '<<' == key ) - { - if ( this.isDefined(values.value) && '*' == (values.value+'').charAt(0) ) - { - isInPlace = values.value.substr(1); - if ( this.refs[isInPlace] == undefined ) - { - throw new YamlParseException('Reference "'+value+'" does not exist', this.getRealCurrentLineNb() + 1, this.currentLine); - } - } - else - { - if ( this.isDefined(values.value) && values.value != '' ) - { - value = values.value; - } - else - { - value = this.getNextEmbedBlock(); - } - - c = this.getRealCurrentLineNb() + 1; - parser = new YamlParser(c); - parser.refs = this.refs; - parsed = parser.parse(value); - this.refs = parser.refs; - - var merged = []; - if ( !this.isObject(parsed) ) - { - throw new YamlParseException("YAML merge keys used with a scalar value instead of an array", this.getRealCurrentLineNb() + 1, this.currentLine); - } - else if ( this.isDefined(parsed[0]) ) - { - // Numeric array, merge individual elements - reverse = this.reverseArray(parsed); - len = reverse.length; - for ( var i = 0; i < len; i++ ) - { - var parsedItem = reverse[i]; - if ( !this.isObject(reverse[i]) ) - { - throw new YamlParseException("Merge items must be arrays", this.getRealCurrentLineNb() + 1, this.currentLine); - } - merged = this.mergeObject(reverse[i], merged); - } - } - else - { - // Associative array, merge - merged = this.mergeObject(merged, parsed); - } - - isProcessed = merged; - } - } - else if ( this.isDefined(values.value) && (matches = /^&([^ ]+) *(.*)/.exec(values.value) ) ) - { - matches = {ref: matches[1], value: matches[2]}; - isRef = matches.ref; - values.value = matches.value; - } - - if ( isProcessed ) - { - // Merge keys - data = isProcessed; - } - // hash - else if ( !this.isDefined(values.value) || '' == this.trim(values.value) || this.trim(values.value).charAt(0) == '#' ) - { - // if next line is less indented or equal, then it means that the current value is null - if ( this.isNextLineIndented() && !this.isNextLineUnIndentedCollection() ) - { - data[key] = null; - } - else - { - c = this.getRealCurrentLineNb() + 1; - parser = new YamlParser(c); - parser.refs = this.refs; - data[key] = parser.parse(this.getNextEmbedBlock()); - this.refs = parser.refs; - } - } - else - { - if ( isInPlace ) - { - data = this.refs[isInPlace]; - } - else - { - data[key] = this.parseValue(values.value); - } - } - } - else - { - // 1-liner followed by newline - if ( 2 == this.lines.length && this.isEmpty(this.lines[1]) ) - { - try { - value = new YamlInline().parse(this.lines[0]); - } catch (e) { - if ( e instanceof YamlParseException ) { - e.setParsedLine(this.getRealCurrentLineNb() + 1); - e.setSnippet(this.currentLine); - } - throw e; - } - - if ( this.isObject(value) ) - { - var first = value[0]; - if ( typeof(value) == 'string' && '*' == first.charAt(0) ) - { - data = []; - len = value.length; - for ( var i = 0; i < len; i++ ) - { - data.push(this.refs[value[i].substr(1)]); - } - value = data; - } - } - - return value; - } - - throw new YamlParseException('Unable to parse.', this.getRealCurrentLineNb() + 1, this.currentLine); - } - - if ( isRef ) - { - if ( data instanceof Array ) - this.refs[isRef] = data[data.length-1]; - else - { - var lastKey = null; - for ( var k in data ) - { - if ( data.hasOwnProperty(k) ) lastKey = k; - } - this.refs[isRef] = data[k]; - } - } - } - - return this.isEmpty(data) ? null : data; - }, - - /** - * Returns the current line number (takes the offset into account). - * - * @return integer The current line number - */ - getRealCurrentLineNb: function() - { - return this.currentLineNb + this.offset; - }, - - /** - * Returns the current line indentation. - * - * @return integer The current line indentation - */ - getCurrentLineIndentation: function() - { - return this.currentLine.length - this.currentLine.replace(/^ +/g, '').length; - }, - - /** - * Returns the next embed block of YAML. - * - * @param integer indentation The indent level at which the block is to be read, or null for default - * - * @return string A YAML string - * - * @throws YamlParseException When indentation problem are detected - */ - getNextEmbedBlock: function(indentation) - { - this.moveToNextLine(); - var newIndent = null; - var indent = null; - - if ( !this.isDefined(indentation) ) - { - newIndent = this.getCurrentLineIndentation(); - - var unindentedEmbedBlock = this.isStringUnIndentedCollectionItem(this.currentLine); - - if ( !this.isCurrentLineEmpty() && 0 == newIndent && !unindentedEmbedBlock ) - { - throw new YamlParseException('Indentation problem A', this.getRealCurrentLineNb() + 1, this.currentLine); - } - } - else - { - newIndent = indentation; - } - - var data = [this.currentLine.substr(newIndent)]; - - var isUnindentedCollection = this.isStringUnIndentedCollectionItem(this.currentLine); - - var continuationIndent = -1; - if (isUnindentedCollection === true) { - continuationIndent = 1 + /^\-((\s+)(.+?))?\s*$/.exec(this.currentLine)[2].length; - } - - while ( this.moveToNextLine() ) - { - - if (isUnindentedCollection && !this.isStringUnIndentedCollectionItem(this.currentLine) && this.getCurrentLineIndentation() != continuationIndent) { - this.moveToPreviousLine(); - break; - } - - if ( this.isCurrentLineEmpty() ) - { - if ( this.isCurrentLineBlank() ) - { - data.push(this.currentLine.substr(newIndent)); - } - - continue; - } - - indent = this.getCurrentLineIndentation(); - var matches; - if ( matches = /^( *)$/.exec(this.currentLine) ) - { - // empty line - data.push(matches[1]); - } - else if ( indent >= newIndent ) - { - data.push(this.currentLine.substr(newIndent)); - } - else if ( 0 == indent ) - { - this.moveToPreviousLine(); - - break; - } - else - { - throw new YamlParseException('Indentation problem B', this.getRealCurrentLineNb() + 1, this.currentLine); - } - } - - return data.join("\n"); - }, - - /** - * Moves the parser to the next line. - * - * @return Boolean - */ - moveToNextLine: function() - { - if ( this.currentLineNb >= this.lines.length - 1 ) - { - return false; - } - - this.currentLineNb++; - this.currentLine = this.lines[this.currentLineNb]; - - return true; - }, - - /** - * Moves the parser to the previous line. - */ - moveToPreviousLine: function() - { - this.currentLineNb--; - this.currentLine = this.lines[this.currentLineNb]; - }, - - /** - * Parses a YAML value. - * - * @param string value A YAML value - * - * @return mixed A JS value - * - * @throws YamlParseException When reference does not exist - */ - parseValue: function(value) - { - if ( '*' == (value+'').charAt(0) ) - { - if ( this.trim(value).charAt(0) == '#' ) - { - value = (value+'').substr(1, value.indexOf('#') - 2); - } - else - { - value = (value+'').substr(1); - } - - if ( this.refs[value] == undefined ) - { - throw new YamlParseException('Reference "'+value+'" does not exist', this.getRealCurrentLineNb() + 1, this.currentLine); - } - return this.refs[value]; - } - - var matches = null; - if ( matches = /^(\||>)(\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?( +#.*)?$/.exec(value) ) - { - matches = {separator: matches[1], modifiers: matches[2], comments: matches[3]}; - var modifiers = this.isDefined(matches.modifiers) ? matches.modifiers : ''; - - return this.parseFoldedScalar(matches.separator, modifiers.replace(/\d+/g, ''), Math.abs(parseInt(modifiers))); - } - try { - return new YamlInline().parse(value); - } catch (e) { - if ( e instanceof YamlParseException ) { - e.setParsedLine(this.getRealCurrentLineNb() + 1); - e.setSnippet(this.currentLine); - } - throw e; - } - }, - - /** - * Parses a folded scalar. - * - * @param string separator The separator that was used to begin this folded scalar (| or >) - * @param string indicator The indicator that was used to begin this folded scalar (+ or -) - * @param integer indentation The indentation that was used to begin this folded scalar - * - * @return string The text value - */ - parseFoldedScalar: function(separator, indicator, indentation) - { - if ( indicator == undefined ) indicator = ''; - if ( indentation == undefined ) indentation = 0; - - separator = '|' == separator ? "\n" : ' '; - var text = ''; - var diff = null; - - var notEOF = this.moveToNextLine(); - - while ( notEOF && this.isCurrentLineBlank() ) - { - text += "\n"; - - notEOF = this.moveToNextLine(); - } - - if ( !notEOF ) - { - return ''; - } - - var matches = null; - if ( !(matches = new RegExp('^('+(indentation ? this.strRepeat(' ', indentation) : ' +')+')(.*)$').exec(this.currentLine)) ) - { - this.moveToPreviousLine(); - - return ''; - } - - matches = {indent: matches[1], text: matches[2]}; - - var textIndent = matches.indent; - var previousIndent = 0; - - text += matches.text + separator; - while ( this.currentLineNb + 1 < this.lines.length ) - { - this.moveToNextLine(); - - if ( matches = new RegExp('^( {'+textIndent.length+',})(.+)$').exec(this.currentLine) ) - { - matches = {indent: matches[1], text: matches[2]}; - - if ( ' ' == separator && previousIndent != matches.indent ) - { - text = text.substr(0, text.length - 1)+"\n"; - } - - previousIndent = matches.indent; - - diff = matches.indent.length - textIndent.length; - text += this.strRepeat(' ', diff) + matches.text + (diff != 0 ? "\n" : separator); - } - else if ( matches = /^( *)$/.exec(this.currentLine) ) - { - text += matches[1].replace(new RegExp('^ {1,'+textIndent.length+'}','g'), '')+"\n"; - } - else - { - this.moveToPreviousLine(); - - break; - } - } - - if ( ' ' == separator ) - { - // replace last separator by a newline - text = text.replace(/ (\n*)$/g, "\n$1"); - } - - switch ( indicator ) - { - case '': - text = text.replace(/\n+$/g, "\n"); - break; - case '+': - break; - case '-': - text = text.replace(/\n+$/g, ''); - break; - } - - return text; - }, - - /** - * Returns true if the next line is indented. - * - * @return Boolean Returns true if the next line is indented, false otherwise - */ - isNextLineIndented: function() - { - var currentIndentation = this.getCurrentLineIndentation(); - var notEOF = this.moveToNextLine(); - - while ( notEOF && this.isCurrentLineEmpty() ) - { - notEOF = this.moveToNextLine(); - } - - if ( false == notEOF ) - { - return false; - } - - var ret = false; - if ( this.getCurrentLineIndentation() <= currentIndentation ) - { - ret = true; - } - - this.moveToPreviousLine(); - - return ret; - }, - - /** - * Returns true if the current line is blank or if it is a comment line. - * - * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise - */ - isCurrentLineEmpty: function() - { - return this.isCurrentLineBlank() || this.isCurrentLineComment(); - }, - - /** - * Returns true if the current line is blank. - * - * @return Boolean Returns true if the current line is blank, false otherwise - */ - isCurrentLineBlank: function() - { - return '' == this.trim(this.currentLine); - }, - - /** - * Returns true if the current line is a comment line. - * - * @return Boolean Returns true if the current line is a comment line, false otherwise - */ - isCurrentLineComment: function() - { - //checking explicitly the first char of the trim is faster than loops or strpos - var ltrimmedLine = this.currentLine.replace(/^ +/g, ''); - return ltrimmedLine.charAt(0) == '#'; - }, - - /** - * Cleanups a YAML string to be parsed. - * - * @param string value The input YAML string - * - * @return string A cleaned up YAML string - */ - cleanup: function(value) - { - value = value.split("\r\n").join("\n").split("\r").join("\n"); - - if ( !/\n$/.test(value) ) - { - value += "\n"; - } - - // strip YAML header - var count = 0; - var regex = /^\%YAML[: ][\d\.]+.*\n/; - while ( regex.test(value) ) - { - value = value.replace(regex, ''); - count++; - } - this.offset += count; - - // remove leading comments - regex = /^(#.*?\n)+/; - if ( regex.test(value) ) - { - var trimmedValue = value.replace(regex, ''); - - // items have been removed, update the offset - this.offset += this.subStrCount(value, "\n") - this.subStrCount(trimmedValue, "\n"); - value = trimmedValue; - } - - // remove start of the document marker (---) - regex = /^\-\-\-.*?\n/; - if ( regex.test(value) ) - { - trimmedValue = value.replace(regex, ''); - - // items have been removed, update the offset - this.offset += this.subStrCount(value, "\n") - this.subStrCount(trimmedValue, "\n"); - value = trimmedValue; - - // remove end of the document marker (...) - value = value.replace(/\.\.\.\s*$/g, ''); - } - - return value; - }, - - /** - * Returns true if the next line starts unindented collection - * - * @return Boolean Returns true if the next line starts unindented collection, false otherwise - */ - isNextLineUnIndentedCollection: function() - { - var currentIndentation = this.getCurrentLineIndentation(); - var notEOF = this.moveToNextLine(); - - while (notEOF && this.isCurrentLineEmpty()) { - notEOF = this.moveToNextLine(); - } - - if (false === notEOF) { - return false; - } - - var ret = false; - if ( - this.getCurrentLineIndentation() == currentIndentation - && - this.isStringUnIndentedCollectionItem(this.currentLine) - ) { - ret = true; - } - - this.moveToPreviousLine(); - - return ret; - }, - - /** - * Returns true if the string is unindented collection item - * - * @return Boolean Returns true if the string is unindented collection item, false otherwise - */ - isStringUnIndentedCollectionItem: function(string) - { - return (0 === this.currentLine.indexOf('- ')); - }, - - isObject: function(input) - { - return typeof(input) == 'object' && this.isDefined(input); - }, - - isEmpty: function(input) - { - return input == undefined || input == null || input == '' || input == 0 || input == "0" || input == false; - }, - - isDefined: function(input) - { - return input != undefined && input != null; - }, - - reverseArray: function(input /* Array */) - { - var result = []; - var len = input.length; - for ( var i = len-1; i >= 0; i-- ) - { - result.push(input[i]); - } - - return result; - }, - - merge: function(a /* Object */, b /* Object */) - { - var c = {}; - var i; - - for ( i in a ) - { - if ( a.hasOwnProperty(i) ) - if ( /^\d+$/.test(i) ) c.push(a); - else c[i] = a[i]; - } - for ( i in b ) - { - if ( b.hasOwnProperty(i) ) - if ( /^\d+$/.test(i) ) c.push(b); - else c[i] = b[i]; - } - - return c; - }, - - strRepeat: function(str /* String */, count /* Integer */) - { - var i; - var result = ''; - for ( i = 0; i < count; i++ ) result += str; - return result; - }, - - subStrCount: function(string, subString, start, length) - { - var c = 0; - - string = '' + string; - subString = '' + subString; - - if ( start != undefined ) string = string.substr(start); - if ( length != undefined ) string = string.substr(0, length); - - var len = string.length; - var sublen = subString.length; - for ( var i = 0; i < len; i++ ) - { - if ( subString == string.substr(i, sublen) ) - c++; - i += sublen - 1; - } - - return c; - }, - - trim: function(str /* String */) - { - return (str+'').replace(/^ +/,'').replace(/ +$/,''); - } -}; -/** - * YamlEscaper encapsulates escaping rules for single and double-quoted - * YAML strings. - * - * @author Matthew Lewinski <matthew@lewinski.org> - */ -YamlEscaper = function(){}; -YamlEscaper.prototype = -{ - /** - * Determines if a JS value would require double quoting in YAML. - * - * @param string value A JS value - * - * @return Boolean True if the value would require double quotes. - */ - requiresDoubleQuoting: function(value) - { - return new RegExp(YamlEscaper.REGEX_CHARACTER_TO_ESCAPE).test(value); - }, - - /** - * Escapes and surrounds a JS value with double quotes. - * - * @param string value A JS value - * - * @return string The quoted, escaped string - */ - escapeWithDoubleQuotes: function(value) - { - value = value + ''; - var len = YamlEscaper.escapees.length; - var maxlen = YamlEscaper.escaped.length; - var esc = YamlEscaper.escaped; - for (var i = 0; i < len; ++i) - if ( i >= maxlen ) esc.push(''); - - var ret = ''; - ret = value.replace(new RegExp(YamlEscaper.escapees.join('|'),'g'), function(str){ - for(var i = 0; i < len; ++i){ - if( str == YamlEscaper.escapees[i] ) - return esc[i]; - } - }); - return '"' + ret + '"'; - }, - - /** - * Determines if a JS value would require single quoting in YAML. - * - * @param string value A JS value - * - * @return Boolean True if the value would require single quotes. - */ - requiresSingleQuoting: function(value) - { - return /[\s'":{}[\],&*#?]|^[-?|<>=!%@`]/.test(value); - }, - - /** - * Escapes and surrounds a JS value with single quotes. - * - * @param string value A JS value - * - * @return string The quoted, escaped string - */ - escapeWithSingleQuotes : function(value) - { - return "'" + value.replace(/'/g, "''") + "'"; - } -}; - -// Characters that would cause a dumped string to require double quoting. -YamlEscaper.REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9"; - -// Mapping arrays for escaping a double quoted string. The backslash is -// first to ensure proper escaping. -YamlEscaper.escapees = ['\\\\', '\\"', '"', - "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", - "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", - "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", - "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", - "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9"]; -YamlEscaper.escaped = ['\\"', '\\\\', '\\"', - "\\0", "\\x01", "\\x02", "\\x03", "\\x04", "\\x05", "\\x06", "\\a", - "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "\\x0e", "\\x0f", - "\\x10", "\\x11", "\\x12", "\\x13", "\\x14", "\\x15", "\\x16", "\\x17", - "\\x18", "\\x19", "\\x1a", "\\e", "\\x1c", "\\x1d", "\\x1e", "\\x1f", - "\\N", "\\_", "\\L", "\\P"]; -/** - * YamlUnescaper encapsulates unescaping rules for single and double-quoted - * YAML strings. - * - * @author Matthew Lewinski <matthew@lewinski.org> - */ -var YamlUnescaper = function(){}; -YamlUnescaper.prototype = -{ - /** - * Unescapes a single quoted string. - * - * @param string value A single quoted string. - * - * @return string The unescaped string. - */ - unescapeSingleQuotedString: function(value) - { - return value.replace(/''/g, "'"); - }, - - /** - * Unescapes a double quoted string. - * - * @param string value A double quoted string. - * - * @return string The unescaped string. - */ - unescapeDoubleQuotedString: function(value) - { - var callback = function(m) { - return new YamlUnescaper().unescapeCharacter(m); - }; - - // evaluate the string - return value.replace(new RegExp(YamlUnescaper.REGEX_ESCAPED_CHARACTER, 'g'), callback); - }, - - /** - * Unescapes a character that was found in a double-quoted string - * - * @param string value An escaped character - * - * @return string The unescaped character - */ - unescapeCharacter: function(value) - { - switch (value.charAt(1)) { - case '0': - return String.fromCharCode(0); - case 'a': - return String.fromCharCode(7); - case 'b': - return String.fromCharCode(8); - case 't': - return "\t"; - case "\t": - return "\t"; - case 'n': - return "\n"; - case 'v': - return String.fromCharCode(11); - case 'f': - return String.fromCharCode(12); - case 'r': - return String.fromCharCode(13); - case 'e': - return "\x1b"; - case ' ': - return ' '; - case '"': - return '"'; - case '/': - return '/'; - case '\\': - return '\\'; - case 'N': - // U+0085 NEXT LINE - return "\x00\x85"; - case '_': - // U+00A0 NO-BREAK SPACE - return "\x00\xA0"; - case 'L': - // U+2028 LINE SEPARATOR - return "\x20\x28"; - case 'P': - // U+2029 PARAGRAPH SEPARATOR - return "\x20\x29"; - case 'x': - return this.pack('n', new YamlInline().hexdec(value.substr(2, 2))); - case 'u': - return this.pack('n', new YamlInline().hexdec(value.substr(2, 4))); - case 'U': - return this.pack('N', new YamlInline().hexdec(value.substr(2, 8))); - } - }, - - /** - * @see http://phpjs.org/functions/pack - * @warning only modes used above copied - */ - pack: function(B){var g=0,o=1,m="",l="",z=0,p=[],E,s,C,I,h,c;var d,b,x,H,u,e,A,q,D,t,w,a,G,F,y,v,f;while(g<B.length){E=B.charAt(g);s="";g++;while((g<B.length)&&(B.charAt(g).match(/[\d\*]/)!==null)){s+=B.charAt(g);g++}if(s===""){s="1"}switch(E){case"n":if(s==="*"){s=arguments.length-o}if(s>(arguments.length-o)){throw new Error("Warning: pack() Type "+E+": too few arguments")}for(z=0;z<s;z++){m+=String.fromCharCode(arguments[o]>>8&255);m+=String.fromCharCode(arguments[o]&255);o++}break;case"N":if(s==="*"){s=arguments.length-o}if(s>(arguments.length-o)){throw new Error("Warning: pack() Type "+E+": too few arguments")}for(z=0;z<s;z++){m+=String.fromCharCode(arguments[o]>>24&255);m+=String.fromCharCode(arguments[o]>>16&255);m+=String.fromCharCode(arguments[o]>>8&255);m+=String.fromCharCode(arguments[o]&255);o++}break;default:throw new Error("Warning: pack() Type "+E+": unknown format code")}}if(o<arguments.length){throw new Error("Warning: pack(): "+(arguments.length-o)+" arguments unused")}return m} -} - -// Regex fragment that matches an escaped character in a double quoted -// string. -// why escape quotes, ffs! -YamlUnescaper.REGEX_ESCAPED_CHARACTER = '\\\\([0abt\tnvfre "\\/\\\\N_LP]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})'; - -/** - * YamlDumper dumps JS variables to YAML strings. - * - * @author Fabien Potencier <fabien@symfony.com> - */ -var YamlDumper = function(){}; -YamlDumper.prototype = -{ - /** - * Dumps a JS value to YAML. - * - * @param mixed input The JS value - * @param integer inline The level where you switch to inline YAML - * @param integer indent The level o indentation indentation (used internally) - * - * @return string The YAML representation of the JS value - */ - dump: function(input, inline, indent) - { - if ( inline == null ) inline = 0; - if ( indent == null ) indent = 0; - var output = ''; - var prefix = indent ? this.strRepeat(' ', indent) : ''; - var yaml; - if (!this.numSpacesForIndentation) this.numSpacesForIndentation = 2; - - if ( inline <= 0 || !this.isObject(input) || this.isEmpty(input) ) - { - yaml = new YamlInline(); - output += prefix + yaml.dump(input); - } - else - { - var isAHash = !this.arrayEquals(this.getKeys(input), this.range(0,input.length - 1)); - var willBeInlined; - - for ( var key in input ) - { - if ( input.hasOwnProperty(key) ) - { - willBeInlined = inline - 1 <= 0 || !this.isObject(input[key]) || this.isEmpty(input[key]); - - if ( isAHash ) yaml = new YamlInline(); - - output += - prefix + '' + - (isAHash ? yaml.dump(key)+':' : '-') + '' + - (willBeInlined ? ' ' : "\n") + '' + - this.dump(input[key], inline - 1, (willBeInlined ? 0 : indent + this.numSpacesForIndentation)) + '' + - (willBeInlined ? "\n" : ''); - } - } - } - - return output; - }, - - strRepeat: function(str /* String */, count /* Integer */) - { - var i; - var result = ''; - for ( i = 0; i < count; i++ ) result += str; - return result; - }, - - isObject: function(input) - { - return this.isDefined(input) && typeof(input) == 'object'; - }, - - isEmpty: function(input) - { - var ret = input == undefined || input == null || input == '' || input == 0 || input == "0" || input == false; - if ( !ret && typeof(input) == "object" && !(input instanceof Array)){ - var propCount = 0; - for ( var key in input ) - if ( input.hasOwnProperty(key) ) propCount++; - ret = !propCount; - } - return ret; - }, - - isDefined: function(input) - { - return input != undefined && input != null; - }, - - getKeys: function(tab) - { - var ret = []; - - for ( var name in tab ) - { - if ( tab.hasOwnProperty(name) ) - { - ret.push(name); - } - } - - return ret; - }, - - range: function(start, end) - { - if ( start > end ) return []; - - var ret = []; - - for ( var i = start; i <= end; i++ ) - { - ret.push(i); - } - - return ret; - }, - - arrayEquals: function(a,b) - { - if ( a.length != b.length ) return false; - - var len = a.length; - - for ( var i = 0; i < len; i++ ) - { - if ( a[i] != b[i] ) return false; - } - - return true; - } -}; -})(); diff --git a/bin/yaml.min.js b/bin/yaml.min.js deleted file mode 100644 index c1440ac..0000000 --- a/bin/yaml.min.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -Copyright (c) 2010 Jeremy Faivre - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ diff --git a/bin/yaml2json b/bin/yaml2json index 3d9075c..550230c 100755 --- a/bin/yaml2json +++ b/bin/yaml2json @@ -4,7 +4,7 @@ * yaml2json cli program */ -var YAML = require('./yaml.js'); +var YAML = require('../lib/Yaml.js'); var ArgumentParser = require('argparse').ArgumentParser; var cli = new ArgumentParser({ @@ -55,7 +55,7 @@ cli.addArgument( ); cli.addArgument(['input'], { - help: 'YAML file or directory containing YAML files.' + help: 'YAML file or directory containing YAML files or - to read YAML from stdin.' }); try { @@ -66,6 +66,7 @@ try { var rootPath = process.cwd(); var parsePath = function(input) { + if (input == '-') return '-'; var output; if (!(input != null)) { return rootPath; @@ -85,38 +86,50 @@ try { // Find files var findFiles = function(input) { - var isDirectory = fs.statSync(input).isDirectory(); - var files = []; + if (input != '-' && input != null) { + var isDirectory = fs.statSync(input).isDirectory(); + var files = []; - if (!isDirectory) { - files.push(input); - } - else { - if (options.recursive) { - files = files.concat(glob.sync(input+'/**/*.yml')); - files = files.concat(glob.sync(input+'/**/*.yaml')); + if (!isDirectory) { + files.push(input); } else { - files = files.concat(glob.sync(input+'/*.yml')); - files = files.concat(glob.sync(input+'/*.yaml')); + if (options.recursive) { + files = files.concat(glob.sync(input+'/**/*.yml')); + files = files.concat(glob.sync(input+'/**/*.yaml')); + } + else { + files = files.concat(glob.sync(input+'/*.yml')); + files = files.concat(glob.sync(input+'/*.yaml')); + } } + + return files; } - - return files; + return null; }; // Convert to JSON - var convertToJSON = function(input, pretty, save, spaces) { + var convertToJSON = function(input, pretty, save, spaces, str) { var json; if (spaces == null) spaces = 2; - if (pretty) { - json = JSON.stringify(YAML.load(input), null, spaces); - } - else { - json = JSON.stringify(YAML.load(input)); + if (str != null) { + if (pretty) { + json = JSON.stringify(YAML.parse(str), null, spaces); + } + else { + json = JSON.stringify(YAML.parse(str)); + } + } else { + if (pretty) { + json = JSON.stringify(YAML.parseFile(input), null, spaces); + } + else { + json = JSON.stringify(YAML.parseFile(input)); + } } - if (!save) { + if (!save || input == null) { // Ouput result process.stdout.write(json+"\n"); } @@ -146,18 +159,30 @@ try { var runCommand = function() { try { var files = findFiles(input); - var len = files.length; - - for (var i = 0; i < len; i++) { - var file = files[i]; - var stat = fs.statSync(file); - var time = stat.mtime.getTime(); - if (!stat.isDirectory()) { - if (!mtimes[file] || mtimes[file] < time) { - mtimes[file] = time; - convertToJSON(file, options.pretty, options.save, options.indentation); + if (files != null) { + var len = files.length; + + for (var i = 0; i < len; i++) { + var file = files[i]; + var stat = fs.statSync(file); + var time = stat.mtime.getTime(); + if (!stat.isDirectory()) { + if (!mtimes[file] || mtimes[file] < time) { + mtimes[file] = time; + convertToJSON(file, options.pretty, options.save, options.indentation); + } } } + } else { + // Read from STDIN + var stdin = process.openStdin(); + var data = ""; + stdin.on('data', function(chunk) { + data += chunk; + }); + stdin.on('end', function() { + convertToJSON(null, options.pretty, options.save, options.indentation, data); + }); } } catch (e) { process.stderr.write((e.message ? e.message : e)+"\n"); |