document querystring apis

This commit is contained in:
Leo Horie 2016-10-18 10:16:20 -04:00
parent 66aa9ce818
commit 6514a38162
6 changed files with 107 additions and 10 deletions

40
docs/buildQueryString.md Normal file
View file

@ -0,0 +1,40 @@
# buildQueryString(object)
- [API](#api)
- [How it works](#how-it-works)
---
### API
`querystring = m.buildQueryString(object)`
Argument | Type | Required | Description
------------ | ------------------------------------------ | -------- | ---
`object` | `Object` | Yes | A key-value map to be converted into a string
**returns** | `String` | | A string representing the input object
[How to read signatures](signatures.md)
---
### How it works
The `m.buildQueryString` creates a querystring from an object. It's useful for manipulating URLs
```javascript
var querystring = m.buildQueryString({a: 1, b: 2})
// querystring is "a=1&b=2"
```
#### Deep data structures
Deep data structures are serialized in a way that is understood by popular web application servers such as PHP, Rails and ExpressJS
```javascript
var querystring = m.buildQueryString({a: ["hello", "world"]})
// querystring is "a[0]=hello&a[1]=world"
```

59
docs/parseQueryString.md Normal file
View file

@ -0,0 +1,59 @@
# parseQueryString(string)
- [API](#api)
- [How it works](#how-it-works)
---
### API
`object = m.parseQueryString(string)`
Argument | Type | Required | Description
------------ | ------------------------------------------ | -------- | ---
`string` | `String` | Yes | A querystring
**returns** | `Object` | | A key-value map
[How to read signatures](signatures.md)
---
### How it works
The `m.parseQueryString` method creates an object from a querystring. It is useful for handling data from URL
```javascript
var data = m.parseQueryString("a=hello&b=world")
// data is {a: "hello", b: "world"}
```
#### Boolean type casting
This method attempts to cast boolean values if possible. This helps prevents bugs related to loose truthiness and unintended type casts.
```javascript
var data = m.parseQueryString("a=true&b=false")
// data is {a: true, b: false}
```
#### Leading question mark tolerance
For convenience, the `m.parseQueryString` method ignores a leading question mark, if present:
```javascript
var data = m.parseQueryString("?a=hello&b=world")
// data is {a: "hello", b: "world"}
```
#### Deep data structures
Querystrings that contain bracket notation are correctly parsed into deep data structures
```javascript
m.parseQueryString("a[0]=hello&a[1]=world")
// data is {a: ["hello", "world"]}
```

View file

@ -32,7 +32,7 @@ Argument | Type | Required | Descript
`options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function). `options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function).
`options.serialize` | `string = Function(any)` | No | A serialization method to be applied to `data`. Defaults to `JSON.stringify`, or if `options.data` is an instance of [`FormData`](https://developer.mozilla.org/en/docs/Web/API/FormData), defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function) (i.e. `function(value) {return value}`). `options.serialize` | `string = Function(any)` | No | A serialization method to be applied to `data`. Defaults to `JSON.stringify`, or if `options.data` is an instance of [`FormData`](https://developer.mozilla.org/en/docs/Web/API/FormData), defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function) (i.e. `function(value) {return value}`).
`options.deserialize` | `any = Function(string)` | No | A deserialization method to be applied to the response. Defaults to a small wrapper around `JSON.parse` that returns `null` for empty responses. `options.deserialize` | `any = Function(string)` | No | A deserialization method to be applied to the response. Defaults to a small wrapper around `JSON.parse` that returns `null` for empty responses.
`options.extract` | `string = Function(xhr, options)` | No | A hook to specify how the XMLHttpRequest response should be read. Useful for reading response headers and cookies. Defaults to a function that returns `xhr.responseText`. If defined, `options.deserialize` is ignored. `options.extract` | `string = Function(xhr, options)` | No | A hook to specify how the XMLHttpRequest response should be read. Useful for reading response headers and cookies. Defaults to a function that returns `xhr.responseText`. If defined, the `xhr` parameter is the XMLHttpRequest instance used for the request, and `options` is the object that was passed to the `m.request` call. If a custom `extract` callback is set, `options.deserialize` is ignored.
`options.initialValue` | `any` | No | A value to populate the returned stream before the request completes `options.initialValue` | `any` | No | A value to populate the returned stream before the request completes
`options.useBody` | `Boolean` | No | Force the use of the HTTP body section for `data` in `GET` requests when set to `true`, or the use of querystring for other HTTP methods when set to `false`. Defaults to `false` for `GET` requests and `true` for other methods. `options.useBody` | `Boolean` | No | Force the use of the HTTP body section for `data` in `GET` requests when set to `true`, or the use of querystring for other HTTP methods when set to `false`. Defaults to `false` for `GET` requests and `true` for other methods.
**returns** | `Stream` | | A stream that resolves to the response data, after it has been piped through the `extract`, `deserialize` and `type` methods **returns** | `Stream` | | A stream that resolves to the response data, after it has been piped through the `extract`, `deserialize` and `type` methods

View file

@ -10,10 +10,7 @@ module.exports = function(string) {
var key = decodeURIComponent(entry[0]) var key = decodeURIComponent(entry[0])
var value = entry.length === 2 ? decodeURIComponent(entry[1]) : "" var value = entry.length === 2 ? decodeURIComponent(entry[1]) : ""
//TODO refactor out if (value === "true") value = true
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 if (value === "false") value = false
var levels = key.split(/\]\[?|\[/) var levels = key.split(/\]\[?|\[/)

View file

@ -72,13 +72,13 @@ o.spec("parseQueryString", function() {
var data = parseQueryString("a=true&b=false") var data = parseQueryString("a=true&b=false")
o(data).deepEquals({a: true, b: false}) o(data).deepEquals({a: true, b: false})
}) })
o("casts numbers", function() { o("does not cast numbers", function() {
var data = parseQueryString("a=1&b=-2.3&c=0x10&d=1e2&e=Infinity") 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(data).deepEquals({a: "1", b: "-2.3", c: "16", d: "1e2", e: "Infinity"})
}) })
o("casts NaN", function() { o("does not cast NaN", function() {
var data = parseQueryString("a=NaN") var data = parseQueryString("a=NaN")
o(isNaN(data.a)).equals(true) o(data.a).equals("NaN")
}) })
o("does not casts Date", function() { o("does not casts Date", function() {
var data = parseQueryString("a=1970-01-01") var data = parseQueryString("a=1970-01-01")

View file

@ -156,7 +156,8 @@ o.spec("api", function() {
done() done()
}, FRAME_BUDGET) }, FRAME_BUDGET)
}) })
o("m.route.set", function(done) { o("m.route.set", function(done, timeout) {
timeout(100)
var root = window.document.createElement("div") var root = window.document.createElement("div")
m.route(root, "/a", { m.route(root, "/a", {
"/:id": {view: function() {return m("div")}} "/:id": {view: function() {return m("div")}}