diff --git a/jquery.parse.js b/jquery.parse.js new file mode 100644 index 0000000..693d2d8 --- /dev/null +++ b/jquery.parse.js @@ -0,0 +1,283 @@ +/* + jQuery Parse plugin + v0.5.0 + https://github.com/mholt/jquery.parse +*/ + +(function($) +{ + var defaults = { + delimiter: ",", + header: true + }; + + $.parse = function(input, options) + { + options = verifyOptions(options); + var parser = new Parser(input, options); + return { + results: parser.parse(), + errors: parser.getErrors() + }; + }; + + function verifyOptions(opt) + { + opt.delimeter = opt.delimiter || defaults.delimiter; + opt.header = typeof opt.header === 'undefined' ? defaults.header : opt.header; + + if (opt.delimiter.length > 1) + opt.delimiter = opt.delimiter[0]; + + return opt; + } + + function Parser(input, config) + { + var self = this; + var _input = input; + var _config = config; + var _errors = []; + var _state = emptyState(); + + this.parse = function(arg) + { + if (typeof arg === 'object') + self.setConfig(arg) + else if (typeof arg === 'string') + self.setInput(arg); + + _errors = []; + _state = emptyState(); + + for (_state.i = 0; _state.i < _input.length; _state.i++) + { + _state.ch = _input[_state.i]; + + if (_state.ch == '"') + handleQuote(); + else if (_state.inQuotes) + inQuotes(); + else + notInQuotes(); + } + + // Treat the last line and its last field + saveField(); + trimEmptyLastLine(); + inspectFieldCount(); + + if (_state.inQuotes) + addError("Unescaped or mismatched quotes"); + + return self.getParsed(); + }; + + this.getDelimiter = function() + { + return config.delimiter; + }; + + this.setDelimiter = function(delim) + { + delim = delim || ","; + _config.delimiter = delim[0]; + }; + + this.setConfig = function(opt) + { + if ((typeof opt.header !== 'undefined' + && opt.header != config.header) + || (typeof opt.delimiter !== 'undefined' + && opt.delimiter != config.delimiter)) + { + _state.parsed = emptyParsed(opt.header); + } + + _config = opt; + } + + this.getInput = function() + { + return _input; + } + + this.setInput = function(input) + { + _input = input; + } + + this.getParsed = function() + { + return _state.parsed; + } + + this.getErrors = function() + { + return _errors; + } + + + function emptyParsed(header) + { + return header ? { fields: [], rows: [] } : [ [] ]; + } + + function emptyState() + { + return { + i: 0, + line: 1, + field: 0, + fieldVal: "", + ch: "", + inQuotes: false, + parsed: emptyParsed(config.header) + }; + } + + function handleQuote() + { + if (_state.i < _input.length - 1) + { + if (_input[_state.i+1] == '"' && _state.inQuotes) + { + _state.fieldVal += '"' + _state.i++; + } + else if (_input[_state.i+1] != _config.delimiter && _state.inQuotes) + return addError("Unescaped quote in field value"); + } + + _state.inQuotes = !_state.inQuotes; + } + + function inQuotes() + { + appendCharToField(); + } + + function appendCharToField() + { + _state.fieldVal += _state.ch; + } + + function notInQuotes() + { + if (_state.ch == _config.delimiter) + { + saveField(); + } + else if (_state.ch == "\n") + { + saveField(); + newRow(); + } + else + { + appendCharToField(); + } + } + + function saveField() + { + if (_config.header) + { + if (_state.line == 1) + { + _state.parsed.fields.push(_state.fieldVal) + } + else + { + var currentRow = _state.parsed.rows[_state.parsed.rows.length - 1]; + var fieldName = _state.parsed.fields[_state.field]; + if (fieldName) + currentRow[fieldName] = _state.fieldVal; + else + addError("Too many fields; expected " + _state.parsed.fields.length + " fields, found extra value: '" + _state.fieldVal + "'"); + } + } + else + _state.parsed[_state.parsed.length - 1].push(_state.fieldVal); + + _state.fieldVal = ""; + _state.field ++; + } + + function newRow() + { + trimEmptyLastLine(); + + if (_config.header) + { + inspectFieldCount(); + if (_state.line > 0) + _state.parsed.rows.push({}); + } + else + _state.parsed.push([]); + + _state.line ++; + _state.field = 0; + } + + function trimEmptyLastLine() + { + if (_config.header) + { + if (_state.line == 1) + { + if (_state.parsed.fields.length == 1 + && _state.parsed.fields[0].length == 0) + { + _state.parsed.fields = []; + _state.line --; + } + } + else + { + var lastRow = _state.parsed.rows[_state.parsed.rows.length - 1]; + if (!lastRow[_state.parsed.fields[0]]) + _state.parsed.rows.splice(_state.parsed.rows.length - 1, 1); + } + } + else + { + var lastRow = _state.parsed[_state.parsed.length - 1]; + if (lastRow.length == 0 || (lastRow[0].length == 0)) + _state.parsed.splice(_state.parsed.length - 1, 1); + } + } + + function inspectFieldCount() + { + if (!_config.header) + return true; + + if (_state.parsed.rows.length == 0) + return true; + + var expected = _state.parsed.fields.length; + var actual = Object.keys(_state.parsed.rows[_state.parsed.rows.length - 1]).length; + + if (expected != actual) + return addError("Too few fields; expected " + expected + " fields, parsed " + actual); + + return true; + } + + function addError(msg) + { + _errors.push({ + message: msg, + line: _state.line, + row: _config.header ? _state.parsed.rows.length - 1 : _state.parsed.length - 1, + index: _state.i + }); + + return false; + } + + } + +})(jQuery); \ No newline at end of file diff --git a/jquery.parse.min.js b/jquery.parse.min.js new file mode 100644 index 0000000..186b2bf --- /dev/null +++ b/jquery.parse.min.js @@ -0,0 +1,6 @@ +/* + jQuery Parse plugin + v0.5.0 + https://github.com/mholt/jquery.parse +*/ +;(function(e){function n(e){e.delimeter=e.delimiter||t.delimiter;e.header=typeof e.header==="undefined"?t.header:e.header;if(e.delimiter.length>1)e.delimiter=e.delimiter[0];return e}function r(e,t){function u(e){return e?{fields:[],rows:[]}:[[]]}function a(){return{i:0,line:1,field:0,fieldVal:"",ch:"",inQuotes:false,parsed:u(t.header)}}function f(){if(o.i0)o.parsed.rows.push({})}else o.parsed.push([]);o.line++;o.field=0}function v(){if(i.header){if(o.line==1){if(o.parsed.fields.length==1&&o.parsed.fields[0].length==0){o.parsed.fields=[];o.line--}}else{var e=o.parsed.rows[o.parsed.rows.length-1];if(!e[o.parsed.fields[0]])o.parsed.rows.splice(o.parsed.rows.length-1,1)}}else{var e=o.parsed[o.parsed.length-1];if(e.length==0||e[0].length==0)o.parsed.splice(o.parsed.length-1,1)}}function m(){if(!i.header)return true;if(o.parsed.rows.length==0)return true;var e=o.parsed.fields.length;var t=Object.keys(o.parsed.rows[o.parsed.rows.length-1]).length;if(e!=t)return g("Too few fields; expected "+e+" fields, parsed "+t);return true}function g(e){s.push({message:e,line:o.line,row:i.header?o.parsed.rows.length-1:o.parsed.length-1,index:o.i});return false}var n=this;var r=e;var i=t;var s=[];var o=a();this.parse=function(e){if(typeof e==="object")n.setConfig(e);else if(typeof e==="string")n.setInput(e);s=[];o=a();for(o.i=0;o.i