initial commit (work in progress)
This commit is contained in:
parent
13fdb60f66
commit
559369016d
83 changed files with 10461 additions and 0 deletions
25
querystring/build.js
Normal file
25
querystring/build.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
"use strict"
|
||||
|
||||
module.exports = function buildQueryString(object) {
|
||||
if (Object.prototype.toString.call(object) !== "[object Object]") return ""
|
||||
|
||||
var args = []
|
||||
for (var key in object) {
|
||||
destructure(key, object[key])
|
||||
}
|
||||
return args.join("&")
|
||||
|
||||
function destructure(key, value) {
|
||||
if (value instanceof Array) {
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
destructure(key + "[" + i + "]", value[i])
|
||||
}
|
||||
}
|
||||
else if (Object.prototype.toString.call(value) === "[object Object]") {
|
||||
for (var i in value) {
|
||||
destructure(key + "[" + i + "]", value[i])
|
||||
}
|
||||
}
|
||||
else args.push(encodeURIComponent(key) + "=" + (value != null ? encodeURIComponent(value) : ""))
|
||||
}
|
||||
}
|
||||
42
querystring/parse.js
Normal file
42
querystring/parse.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
"use strict"
|
||||
|
||||
module.exports = function parseQueryString(string) {
|
||||
if (string === "" || string == null) return {}
|
||||
if (string.charAt(0) === "?") string = string.slice(1)
|
||||
|
||||
var entries = string.split("&"), data = {}, counters = {}
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
var entry = entries[i].split("=")
|
||||
var key = decodeURIComponent(entry[0])
|
||||
var value = decodeURIComponent(entry[1])
|
||||
|
||||
//TODO refactor out
|
||||
var number = Number(value)
|
||||
if (value !== "" && !isNaN(number) || value === "NaN") value = number
|
||||
else if (value === "true") value = true
|
||||
else if (value === "false") value = false
|
||||
else {
|
||||
var date = new Date(value)
|
||||
if (!isNaN(date.getTime())) value = date
|
||||
}
|
||||
|
||||
var levels = key.split(/\]\[?|\[/)
|
||||
var cursor = data
|
||||
if (key.indexOf("[") > -1) levels.pop()
|
||||
for (var j = 0; j < levels.length; j++) {
|
||||
var level = levels[j], nextLevel = levels[j + 1]
|
||||
var isNumber = nextLevel == "" || !isNaN(parseInt(nextLevel))
|
||||
var isValue = j === levels.length - 1
|
||||
if (level === "") {
|
||||
var key = levels.slice(0, j).join()
|
||||
if (counters[key] == null) counters[key] = 0
|
||||
level = counters[key]++
|
||||
}
|
||||
if (cursor[level] == null) {
|
||||
cursor[level] = isValue ? value : isNumber ? [] : {}
|
||||
}
|
||||
cursor = cursor[level]
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
17
querystring/tests/index.html
Normal file
17
querystring/tests/index.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script src="../../module/module.js"></script>
|
||||
<script src="../../ospec/ospec.js"></script>
|
||||
|
||||
<script src="../../querystring/parse.js"></script>
|
||||
<script src="../../querystring/build.js"></script>
|
||||
<script src="test-parseQueryString.js"></script>
|
||||
<script src="test-buildQueryString.js"></script>
|
||||
|
||||
<script>require("../../ospec/ospec").run()</script>
|
||||
</body>
|
||||
</html>
|
||||
67
querystring/tests/test-buildQueryString.js
Normal file
67
querystring/tests/test-buildQueryString.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
"use strict"
|
||||
|
||||
var o = require("../../ospec/ospec")
|
||||
var buildQueryString = require("../../querystring/build")
|
||||
|
||||
o.spec("buildQueryString", function() {
|
||||
o("builds from flat object", function() {
|
||||
var string = buildQueryString({a: "b", c: 1})
|
||||
|
||||
o(string).equals("a=b&c=1")
|
||||
})
|
||||
o("builds from nested object", function() {
|
||||
var string = buildQueryString({a: {b: 1, c: 2}})
|
||||
|
||||
o(string).equals("a%5Bb%5D=1&a%5Bc%5D=2")
|
||||
})
|
||||
o("builds from deep nested object", function() {
|
||||
var string = buildQueryString({a: {b: {c: 1, d: 2}}})
|
||||
|
||||
o(string).equals("a%5Bb%5D%5Bc%5D=1&a%5Bb%5D%5Bd%5D=2")
|
||||
})
|
||||
o("builds from nested array", function() {
|
||||
var string = buildQueryString({a: ["x", "y"]})
|
||||
|
||||
o(string).equals("a%5B0%5D=x&a%5B1%5D=y")
|
||||
})
|
||||
o("builds from deep nested array", function() {
|
||||
var string = buildQueryString({a: [["x", "y"]]})
|
||||
|
||||
o(string).equals("a%5B0%5D%5B0%5D=x&a%5B0%5D%5B1%5D=y")
|
||||
})
|
||||
o("builds from deep nested array in object", function() {
|
||||
var string = buildQueryString({a: {b: ["x", "y"]}})
|
||||
|
||||
o(string).equals("a%5Bb%5D%5B0%5D=x&a%5Bb%5D%5B1%5D=y")
|
||||
})
|
||||
o("builds from deep nested object in array", function() {
|
||||
var string = buildQueryString({a: [{b: 1, c: 2}]})
|
||||
|
||||
o(string).equals("a%5B0%5D%5Bb%5D=1&a%5B0%5D%5Bc%5D=2")
|
||||
})
|
||||
o("builds date", function() {
|
||||
var string = buildQueryString({a: new Date(0)})
|
||||
|
||||
o(string).equals("a=" + encodeURIComponent(new Date(0).toString()))
|
||||
})
|
||||
o("builds null into empty string (like jQuery)", function() {
|
||||
var string = buildQueryString({a: null})
|
||||
|
||||
o(string).equals("a=")
|
||||
})
|
||||
o("builds undefined into empty string (like jQuery)", function() {
|
||||
var string = buildQueryString({a: undefined})
|
||||
|
||||
o(string).equals("a=")
|
||||
})
|
||||
o("builds zero", function() {
|
||||
var string = buildQueryString({a: 0})
|
||||
|
||||
o(string).equals("a=0")
|
||||
})
|
||||
o("builds false", function() {
|
||||
var string = buildQueryString({a: false})
|
||||
|
||||
o(string).equals("a=false")
|
||||
})
|
||||
})
|
||||
74
querystring/tests/test-parseQueryString.js
Normal file
74
querystring/tests/test-parseQueryString.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
"use strict"
|
||||
|
||||
var o = require("../../ospec/ospec")
|
||||
var parseQueryString = require("../../querystring/parse")
|
||||
|
||||
o.spec("parseQueryString", function() {
|
||||
o("works", function() {
|
||||
var data = parseQueryString("?aaa=bbb")
|
||||
o(data).deepEquals({aaa: "bbb"})
|
||||
})
|
||||
o("parses flat object", function() {
|
||||
var data = parseQueryString("?a=b&c=d")
|
||||
o(data).deepEquals({a: "b", c: "d"})
|
||||
})
|
||||
o("parses without question mark", function() {
|
||||
var data = parseQueryString("a=b&c=d")
|
||||
o(data).deepEquals({a: "b", c: "d"})
|
||||
})
|
||||
o("parses nested object", function() {
|
||||
var data = parseQueryString("a[b]=x&a[c]=y")
|
||||
o(data).deepEquals({a: {b: "x", c: "y"}})
|
||||
})
|
||||
o("parses deep nested object", function() {
|
||||
var data = parseQueryString("a[b][c]=x&a[b][d]=y")
|
||||
o(data).deepEquals({a: {b: {c: "x", d: "y"}}})
|
||||
})
|
||||
o("parses nested array", function() {
|
||||
var data = parseQueryString("a[0]=x&a[1]=y")
|
||||
o(data).deepEquals({a: ["x", "y"]})
|
||||
})
|
||||
o("parses deep nested array", function() {
|
||||
var data = parseQueryString("a[0][0]=x&a[0][1]=y")
|
||||
o(data).deepEquals({a: [["x", "y"]]})
|
||||
})
|
||||
o("parses deep nested object in array", function() {
|
||||
var data = parseQueryString("a[0][c]=x&a[0][d]=y")
|
||||
o(data).deepEquals({a: [{c: "x", d: "y"}]})
|
||||
})
|
||||
o("parses deep nested array in object", function() {
|
||||
var data = parseQueryString("a[b][0]=x&a[b][1]=y")
|
||||
o(data).deepEquals({a: {b: ["x", "y"]}})
|
||||
})
|
||||
o("parses array without index", function() {
|
||||
var data = parseQueryString("a[]=x&a[]=y&b[]=w&b[]=z")
|
||||
o(data).deepEquals({a: ["x", "y"], b: ["w", "z"]})
|
||||
})
|
||||
/*TODO remove since build generates a[0]=b syntax
|
||||
o("generates array for duplicate items", function() {
|
||||
var data = parseQueryString("a=b&a=c&a=d")
|
||||
o(data).deepEquals({a: ["b", "c", "d"]})
|
||||
})
|
||||
*/
|
||||
o("casts booleans", function() {
|
||||
var data = parseQueryString("a=true&b=false")
|
||||
o(data).deepEquals({a: true, b: false})
|
||||
})
|
||||
o("casts numbers", function() {
|
||||
var data = parseQueryString("a=1&b=-2.3&c=0x10&d=1e2&e=Infinity")
|
||||
o(data).deepEquals({a: 1, b: -2.3, c: 16, d: 100, e: Infinity})
|
||||
})
|
||||
o("casts NaN", function() {
|
||||
var data = parseQueryString("a=NaN")
|
||||
o(isNaN(data.a)).equals(true)
|
||||
})
|
||||
o("casts Date", function() {
|
||||
var data = parseQueryString("a=" + new Date(0))
|
||||
o(data.a instanceof Date).equals(true)
|
||||
o(data.a.getTime()).equals(0)
|
||||
})
|
||||
o("does not cast empty string to number", function() {
|
||||
var data = parseQueryString("a=")
|
||||
o(data).deepEquals({a: ""})
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue