├── .gitignore ├── .travis.yml ├── .npmignore ├── CHANGELOG ├── .editorconfig ├── Makefile ├── .jshintrc ├── package.json ├── LICENSE ├── test └── superqs.spec.js ├── README.md ├── lib └── superqs.js └── CONTRIBUTING.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea/ 3 | *.log 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.8' 4 | - '0.10' 5 | - '0.11' 6 | - '0.12' 7 | - '4.2.1' 8 | - '5.3.0' 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | example 4 | docs 5 | .idea 6 | 7 | 8 | # don't ignore .npmignore files 9 | !.npmignore 10 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | v0.1.1: 2 | date: 2016-04-6 3 | changes: 4 | - Update LICENSE 5 | 6 | v0.1.0: 7 | date: 2015-12-23 8 | changes: 9 | - Initial release. 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # superqs 2 | # https://github.com/chrisenytc/superqs 3 | # 4 | # Copyright (c) 2015, Christopher EnyTC 5 | # Licensed under the MIT license. 6 | 7 | test: 8 | 9 | @NODE_ENV=test ./node_modules/mocha/bin/mocha -R spec --ui bdd --colors --recursive -t 8000 ./test/*.spec.js 10 | 11 | .PHONY: test 12 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true, 14 | "globals": { 15 | "require": true, 16 | "module": true, 17 | "describe": true, 18 | "it": true, 19 | "define": true, 20 | "before": true, 21 | "after": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "superqs", 3 | "description": "A powerful querystring parser to use with multidimensional arrays and objects", 4 | "version": "0.1.1", 5 | "homepage": "https://github.com/chrisenytc/superqs", 6 | "author": { 7 | "name": "Christopher EnyTC", 8 | "email": "chris@enytc.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/chrisenytc/superqs.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/chrisenytc/superqs/issues" 16 | }, 17 | "license": "MIT", 18 | "main": "lib/superqs", 19 | "engines": { 20 | "node": ">= 0.8.0" 21 | }, 22 | "scripts": { 23 | "test": "make test" 24 | }, 25 | "dependencies": { 26 | "sugar": "1.4.1" 27 | }, 28 | "devDependencies": { 29 | "chai": "~2.1.2", 30 | "mocha": "~2.2.1" 31 | }, 32 | "keywords": [ 33 | "querystring", 34 | "qs", 35 | "parser", 36 | "stringify", 37 | "arrays", 38 | "objects", 39 | "multidimensional", 40 | "tool", 41 | "utils" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright: (c) 2015-2016, Christopher EnyTC 4 | (c) 2014, Halász Ádám 5 | 6 | 7 | Permission is hereby granted, free of charge, to any person 8 | obtaining a copy of this software and associated documentation 9 | files (the "Software"), to deal in the Software without 10 | restriction, including without limitation the rights to use, 11 | copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the 13 | Software is furnished to do so, subject to the following 14 | conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | OTHER DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /test/superqs.spec.js: -------------------------------------------------------------------------------- 1 | /* 2 | * superqs 3 | * https://github.com/chrisenytc/superqs 4 | * 5 | * Copyright (c) 2015, Christopher EnyTC 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | var chai = require('chai'); 12 | var expect = chai.expect; 13 | 14 | var qs = require('../lib/superqs.js'); 15 | 16 | describe('SuperQS module', function() { 17 | var parsed; 18 | var querystring = 'string=value&date=2015-12-23T23:42:09.248Z&yes=true&no=false&array=1&array=2&object[a]=hello&object[b]=world&object[c][a]=3&object[c][a]=4'; 19 | 20 | describe('.parse()', function() { 21 | before(function() { 22 | parsed = qs.parse(querystring); 23 | }); 24 | 25 | it("should have property 'string' as 'value'", function() { 26 | expect(parsed).to.have.property('string').and.eql('value'); 27 | }); 28 | 29 | it("should have property 'date' and be a date", function() { 30 | expect(parsed).to.have.property('date').and.instanceof(Date); 31 | }); 32 | 33 | it("should have property 'yes' as true", function() { 34 | expect(parsed).to.have.property('yes').and.eql(true); 35 | }); 36 | 37 | it("should have property 'no' as false", function() { 38 | expect(parsed).to.have.property('no').and.eql(false); 39 | }); 40 | 41 | it("should have property 'array' as [1,2]", function() { 42 | expect(parsed).to.have.property('array').and.eql([1,2]); 43 | }); 44 | 45 | it("should have property 'object' and be a multidimensional object", function() { 46 | expect(parsed).to.have.property('object'); 47 | expect(parsed.object).to.have.property('a').and.eql('hello'); 48 | expect(parsed.object).to.have.property('b').and.eql('world'); 49 | expect(parsed.object).to.have.property('c'); 50 | expect(parsed.object.c).to.have.property('a').and.eql([3,4]); 51 | }); 52 | }); 53 | 54 | describe('.stringify()', function() { 55 | it('should have the same querystring from parsed body', function() { 56 | expect(qs.stringify(parsed)).to.eql(querystring); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SuperQS [![Build Status](https://img.shields.io/travis/chrisenytc/superqs/master.svg)](http://travis-ci.org/chrisenytc/superqs) [![NPM version](https://img.shields.io/npm/v/superqs.svg)](https://www.npmjs.com/package/superqs) [![NPM Downloads](https://img.shields.io/npm/dt/superqs.svg)](https://www.npmjs.com/package/superqs) 2 | 3 | > A powerful querystring parser to use with multidimensional arrays and objects 4 | 5 | ## Getting Started 6 | Install the module with: `npm install superqs` 7 | 8 | ```javascript 9 | var qs = require('superqs'); 10 | 11 | qs.stringify({ 12 | name: 'Christopher', 13 | born_at: new Date(), 14 | metadata: { 15 | username: 'chrisenytc' 16 | } 17 | }); // "name=Christopher&born_at=2015-12-23T20:25:25.782Z&metadata[username]=chrisenytc" 18 | 19 | ``` 20 | 21 | ## Features 22 | - Supports multi dimensional arrays and objects 23 | - Converts values into their correct data types. 24 | - Supports all data types: `strings`, `integers`, `booleans`, `arrays` & `objects`. 25 | 26 | ## Documentation 27 | 28 | #### .parse(body) 29 | 30 | How to use this method 31 | 32 | ```javascript 33 | let qs = require('superqs'); 34 | 35 | // parse 36 | qs.parse('string=value&date=2015-12-23T23:42:09.248Z&yes=true&no=false&array=1&array=2&object[a]=hello&object[b]=world&object[c][a]=3&object[c][a]=4') 37 | 38 | // becomes -> 39 | { 40 | string: 'value', 41 | date: Wed Dec 23 2015 21:42:09 GMT-0200 (BRST), 42 | yes: true, 43 | no: false, 44 | array: [1,2], 45 | object: { 46 | a: 'hello', 47 | b: 'world', 48 | c: { 49 | a: [3,4] 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | #### .stringify(query) 56 | 57 | How to use this method 58 | 59 | ```javascript 60 | let qs = require('superqs'); 61 | 62 | // stringify 63 | let result = qs.stringify({ 64 | string: 'value', 65 | date: new Date(), 66 | yes: true, 67 | no: false, 68 | array: [1,2], 69 | object: { 70 | a: 'hello', 71 | b: 'world', 72 | c: { 73 | a: [3,4] 74 | } 75 | } 76 | }); 77 | 78 | console.log(result) 79 | // --> string=value&date=2015-12-23T23:42:09.248Z&yes=true&no=false&array=1&array=2&object[a]=hello&object[b]=world&object[c][a]=3&object[c][a]=4 80 | ``` 81 | 82 | ## Contributing 83 | 84 | Bug reports and pull requests are welcome on GitHub at [https://github.com/chrisenytc/superqs](https://github.com/chrisenytc/superqs). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 85 | 86 | 1. Fork it [chrisenytc/superqs](https://github.com/chrisenytc/superqs/fork) 87 | 2. Create your feature branch (`git checkout -b my-new-feature`) 88 | 3. Commit your changes (`git commit -am "Add some feature"`) 89 | 4. Push to the branch (`git push origin my-new-feature`) 90 | 5. Create new Pull Request 91 | 92 | ## Support 93 | If you have any problem or suggestion please open an issue [here](https://github.com/chrisenytc/superqs/issues). 94 | 95 | ## Credits 96 | This is a fork of the project [diet-qs](https://github.com/adamhalasz/diet-qs). Give some respect to him. 97 | 98 | ## License 99 | 100 | Check [here](LICENSE). 101 | -------------------------------------------------------------------------------- /lib/superqs.js: -------------------------------------------------------------------------------- 1 | /* 2 | * superqs 3 | * https://github.com/chrisenytc/superqs 4 | * 5 | * Copyright (c) 2015, Christopher EnyTC 6 | * Licensed under the MIT license. 7 | */ 8 | 9 | 'use strict'; 10 | 11 | /** 12 | * Module Dependencies 13 | */ 14 | 15 | var sugar = require('sugar'); 16 | 17 | /** 18 | @class SuperQS 19 | */ 20 | 21 | /** 22 | * Private Methods 23 | */ 24 | 25 | function isset(object){ 26 | return (object != 'undefined' && object != undefined && object != null && object != "" && typeof(object) != 'undefined') ? true : false ; 27 | } 28 | 29 | function isDate(date) { 30 | return ( (new Date(date) !== 'Invalid Date' && !isNaN(new Date(date)) )); 31 | } 32 | 33 | function stringifyTraverse(subject, level, key) { 34 | var result = ''; 35 | for (var prop in subject) { 36 | var parent_appendix = key ? key : ''; 37 | var parent_appendix = level > 1 && level < 2 ? '['+key+']' : parent_appendix; 38 | var child_appendix = level > 0 ? '['+prop+']' : prop ; 39 | var appendix = parent_appendix + child_appendix; 40 | var value = subject[prop]; 41 | if (Object.isObject(value)) { 42 | result += stringifyTraverse(value, level + 1, appendix); 43 | } else if (Array.isArray(value)) { 44 | for(var i = 0; i < value.length; i++){ 45 | result += appendix+'='+stringifyValue(value[i])+'&'; 46 | } 47 | } else { 48 | result += appendix +'='+ stringifyValue(value) + '&'; 49 | } 50 | } 51 | return result; 52 | } 53 | 54 | function toValue(value) { 55 | if(value == 'true'){ 56 | value = true; // boolean true 57 | } else if (value == 'false') { 58 | value = false; // boolean false 59 | } else if (isset(value) && !isNaN(value)) { 60 | value = +value; // number 61 | } else if (isDate(value)) { 62 | value = new Date(value); 63 | } 64 | return value; 65 | } 66 | 67 | function stringifyValue(value) { 68 | if(value === true){ 69 | value = 'true'; // boolean true 70 | } else if (value === false) { 71 | value = 'false'; // boolean false 72 | } else if (value instanceof Date) { 73 | value = value.toISOString(); // iso date 74 | } else if (isset(value) && !isNaN(value)) { 75 | value = +value; // number 76 | } 77 | return value; 78 | } 79 | 80 | function traverse(subject, key, value) { 81 | 82 | if(key.indexOf('[') != -1){ 83 | var split = key.split('['); 84 | var INT_SUBJECT = subject; 85 | if(isNaN(split[1].split(']')[0])){ 86 | for(var i = 0; i < split.length; i++){ 87 | var section = split[i].indexOf(']') ? split[i].split(']')[0] : split[i] ; 88 | 89 | if(i < split.length-1){ 90 | if(!INT_SUBJECT[section]) INT_SUBJECT[section] = {}; 91 | } else { 92 | if(INT_SUBJECT[section]) { 93 | INT_SUBJECT[section] = [INT_SUBJECT[section]]; 94 | INT_SUBJECT[section].push(toValue(value)) 95 | } else { 96 | INT_SUBJECT[section] = toValue(value); 97 | } 98 | } 99 | INT_SUBJECT = INT_SUBJECT[section]; 100 | } 101 | subject = INT_SUBJECT; 102 | } else { 103 | var parent = split[0]; 104 | var section = split[1].indexOf(']') ? split[1].split(']')[0] : split[1] ; 105 | if(typeof INT_SUBJECT[parent] != 'object') INT_SUBJECT[parent] = []; 106 | INT_SUBJECT[parent].push(toValue(value)); 107 | subject = INT_SUBJECT; 108 | } 109 | } else if (subject[key]) { 110 | if(typeof subject[key] != 'object') subject[key] = [subject[key]]; 111 | subject[key].push(toValue(value)); 112 | } else { 113 | subject[key] = toValue(value); 114 | } 115 | return subject; 116 | } 117 | 118 | /* 119 | * Public Methods 120 | */ 121 | 122 | /** 123 | * Method responsible for parse a querystring 124 | * 125 | * @example 126 | * 127 | * superqs.parse('name=Christopher&username=chrisenytc'); 128 | * 129 | * @method parse 130 | * @param {String} body A querystring 131 | * @return {Mixed} Returns a object or array 132 | */ 133 | 134 | exports.parse = function(body) { 135 | var result = {}; 136 | body = body.toString().replace(/\+/gi,' '); 137 | var split = body.split(/\&/gi); 138 | split.forEach(function(string){ 139 | var split = string.split('='); 140 | var key = decodeURIComponent(split[0]); 141 | var value = decodeURIComponent(split[1]); 142 | traverse(result, key, value, split.length); 143 | }); 144 | return result; 145 | }; 146 | 147 | /** 148 | * Method responsible for stringify a array or object 149 | * 150 | * @example 151 | * 152 | * superqs.stringify({ name: 'Christopher', username: 'chrisenytc' }); 153 | * 154 | * @method parse 155 | * @param {Mixed} query A array or object 156 | * @return {Mixed} Returns a object or array 157 | */ 158 | 159 | exports.stringify = function(query) { 160 | var result = stringifyTraverse(query, 0); 161 | result = result.substr(0, result.length-1); 162 | return result; 163 | }; 164 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to SuperQS 2 | 3 | Please take a moment to review this document in order to make the contribution 4 | process easy and effective for everyone involved. 5 | 6 | Following these guidelines helps to communicate that you respect the time of 7 | the developers managing and developing this open source project. In return, 8 | they should reciprocate that respect in addressing your issue or assessing 9 | patches and features. 10 | 11 | 12 | ## Using the issue tracker 13 | 14 | The issue tracker is the preferred channel for [bug reports](#bug-reports), 15 | [features requests](#feature-requests) and [submitting pull 16 | requests](#pull-requests), but please respect the following restrictions: 17 | 18 | * Please **do not** use the issue tracker for personal support requests (use 19 | [Stack Overflow](http://stackoverflow.com) or IRC). 20 | 21 | * Please **do not** derail or troll issues. Keep the discussion on topic and 22 | respect the opinions of others. 23 | 24 | 25 | ## Bug reports 26 | 27 | A bug is a _demonstrable problem_ that is caused by the code in the repository. 28 | Good bug reports are extremely helpful - thank you! 29 | 30 | Guidelines for bug reports: 31 | 32 | 1. **Use the GitHub issue search** — check if the issue has already been 33 | reported. 34 | 35 | 2. **Check if the issue has been fixed** — try to reproduce it using the 36 | latest `master` or development branch in the repository. 37 | 38 | 3. **Isolate the problem** — create a [reduced test 39 | case](http://css-tricks.com/6263-reduced-test-cases/) and a live example. 40 | 41 | A good bug report shouldn't leave others needing to chase you up for more 42 | information. Please try to be as detailed as possible in your report. What is 43 | your environment? What steps will reproduce the issue? What browser(s) and OS 44 | experience the problem? What would you expect to be the outcome? All these 45 | details will help people to fix any potential bugs. 46 | 47 | Example: 48 | 49 | > Short and descriptive example bug report title 50 | > 51 | > A summary of the issue and the browser/OS environment in which it occurs. If 52 | > suitable, include the steps required to reproduce the bug. 53 | > 54 | > 1. This is the first step 55 | > 2. This is the second step 56 | > 3. Further steps, etc. 57 | > 58 | > `` - a link to the reduced test case 59 | > 60 | > Any other information you want to share that is relevant to the issue being 61 | > reported. This might include the lines of code that you have identified as 62 | > causing the bug, and potential solutions (and your opinions on their 63 | > merits). 64 | 65 | 66 | ## Feature requests 67 | 68 | Feature requests are welcome. But take a moment to find out whether your idea 69 | fits with the scope and aims of the project. It's up to *you* to make a strong 70 | case to convince the project's developers of the merits of this feature. Please 71 | provide as much detail and context as possible. 72 | 73 | 74 | ## Pull requests 75 | 76 | Good pull requests - patches, improvements, new features - are a fantastic 77 | help. They should remain focused in scope and avoid containing unrelated 78 | commits. 79 | 80 | **Please ask first** before embarking on any significant pull request (e.g. 81 | implementing features, refactoring code, porting to a different language), 82 | otherwise you risk spending a lot of time working on something that the 83 | project's developers might not want to merge into the project. 84 | 85 | Please adhere to the coding conventions used throughout a project (indentation, 86 | accurate comments, etc.) and any other requirements (such as test coverage). 87 | 88 | Follow this process if you'd like your work considered for inclusion in the 89 | project: 90 | 91 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, 92 | and configure the remotes: 93 | 94 | ```bash 95 | # Clone your fork of the repo into the current directory 96 | git clone https://github.com//superqs 97 | # Navigate to the newly cloned directory 98 | cd superqs 99 | # Assign the original repo to a remote called "upstream" 100 | git remote add upstream https://github.com/chrisenytc/superqs 101 | ``` 102 | 103 | 2. If you cloned a while ago, get the latest changes from upstream: 104 | 105 | ```bash 106 | git checkout 107 | git pull upstream 108 | ``` 109 | 110 | 3. Create a new topic branch (off the main project development branch) to 111 | contain your feature, change, or fix: 112 | 113 | ```bash 114 | git checkout -b 115 | ``` 116 | 117 | 4. Commit your changes in logical chunks. Please adhere to these [git commit 118 | message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 119 | or your code is unlikely be merged into the main project. Use Git's 120 | [interactive rebase](https://help.github.com/articles/interactive-rebase) 121 | feature to tidy up your commits before making them public. 122 | 123 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 124 | 125 | ```bash 126 | git pull [--rebase] upstream 127 | ``` 128 | 129 | 6. Push your topic branch up to your fork: 130 | 131 | ```bash 132 | git push origin 133 | ``` 134 | 135 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) 136 | with a clear title and description. 137 | 138 | ## Conventions of commit messages 139 | 140 | Addding files on repo 141 | 142 | ```bash 143 | git commit -m "Add filename" 144 | ``` 145 | 146 | Updating files on repo 147 | 148 | ```bash 149 | git commit -m "Update filename, filename2, filename3" 150 | ``` 151 | 152 | Removing files on repo 153 | 154 | ```bash 155 | git commit -m "Remove filename" 156 | ``` 157 | 158 | Renaming files on repo 159 | 160 | ```bash 161 | git commit -m "Rename filename" 162 | ``` 163 | 164 | Fixing errors and issues on repo 165 | 166 | ```bash 167 | git commit -m "Fixed #issuenumber Message about this fix" 168 | ``` 169 | 170 | Adding features on repo 171 | 172 | ```bash 173 | git commit -m "Add Feature: nameoffeature Message about this feature" 174 | ``` 175 | 176 | Updating features on repo 177 | 178 | ```bash 179 | git commit -m "Update Feature: nameoffeature Message about this update" 180 | ``` 181 | 182 | Removing features on repo 183 | 184 | ```bash 185 | git commit -m "Remove Feature: nameoffeature Message about this" 186 | ``` 187 | 188 | Ignoring Travis CI build on repo 189 | 190 | ```bash 191 | git commit -m "Commit message here [ci-skip]" 192 | ``` 193 | 194 | **IMPORTANT**: By submitting a patch, you agree to allow the project owner to 195 | license your work under the same license as that used by the project. 196 | --------------------------------------------------------------------------------