Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: loose escaping, null support, updated deps #30

Merged
merged 1 commit into from
Nov 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,33 @@ It allows you to outsource working with a url (mapping, parsing, stringifying) a
### Example

```js
import React from 'react';
import ReactDOM from 'react-dom';
import Mapper from 'url-mapper';
import { CoreApp, ComponentA, ComponentB, Component404 } from './components';
import React from 'react'
import ReactDOM from 'react-dom'
import Mapper from 'url-mapper'
import { CoreApp, ComponentA, ComponentB, Component404 } from './components'

const urlMapper = Mapper();
const urlMapper = Mapper()

var matchedRoute = urlMapper.map('/bar/baz/:42', { // routable part of url
'/foo/:id': ComponentA,
'/bar/:list/:itemId': ComponentB,
'*': Component404
});
})

if (matchedRoute) {
const Component = matchedRoute.match; // ComponentB
const props = matchedRoute.values; // { list: 'baz', itemId: 42 }
const Component = matchedRoute.match // ComponentB
const props = matchedRoute.values // { list: 'baz', itemId: 42 }

ReactDOM.render(
<CoreApp>
<Component {...props} />
</CoreApp>
);
)
}
```

See [`cerebral-router`](https://github.com/cerebral/cerebral-router) as an example of building your own router solution on top of `url-mapper`.
Also see [example at Tonic Sandbox](https://tonicdev.com/npm/url-mapper) to try it right in your browser.
See [`@cerebral/router`](https://github.com/cerebral/cerebral/blob/next/packages/node_modules/%40cerebral/router) as an example of building your own router solution on top of `url-mapper`.
Also see [example at Runkit Sandbox](https://npm.runkit.com/url-mapper) to try it right in your browser.

## API

Expand All @@ -65,8 +65,8 @@ At top level the `url-mapper` module exports a factory which returns default imp
##### Usage

```js
var urlMapper = require('url-mapper');
var mapper = urlMapper(options);
var urlMapper = require('url-mapper')
var mapper = urlMapper(options)
```

##### Arguments
Expand Down Expand Up @@ -116,7 +116,7 @@ You still can manage your routes in `location.hash` but don't provide `#` symbol

##### Usage

`mapper.parse(route, url)`;
`mapper.parse(route, url)`

##### Arguments

Expand All @@ -136,7 +136,7 @@ Query part parsed with `URLON` module if { query: true } option was passed to fa

##### Usage

`mapper.stringify(route, values)`;
`mapper.stringify(route, values)`

##### Arguments

Expand All @@ -156,7 +156,7 @@ Properties not defined in route are stringified to query part using `URLON` modu

##### Usage

`mapper.map(url, routes)`;
`mapper.map(url, routes)`

##### Arguments

Expand Down Expand Up @@ -184,8 +184,8 @@ If you don't like default route definition format or converting algorithms, feel
##### Usage

```js
var urlMapper = require('url-mapper/mapper');
var mapper = urlMapper(compileFn, options);
var urlMapper = require('url-mapper/mapper')
var mapper = urlMapper(compileFn, options)
```

##### Arguments
Expand Down
39 changes: 27 additions & 12 deletions compileRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,26 @@
var URLON = require('urlon')
var pathToRegexp = require('path-to-regexp')

function getKeyName (key) {
return key.name.toString()
}

// loose escaping for segment part
// see: https://github.com/pillarjs/path-to-regexp/pull/75
function encodeSegment (str) {
return encodeURI(str).replace(/[/?#'"]/g, function (c) {
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
})
}

function compileRoute (route, options) {
var re
var compiled
var keys = []
var querySeparator = options.querySeparator || '?'

re = pathToRegexp(route, keys)
keys = keys.map(function (key) { return key.name.toString() })
keys = keys.map(getKeyName)
compiled = pathToRegexp.compile(route)

return {
Expand All @@ -23,7 +35,7 @@ function compileRoute (route, options) {

if (~path.indexOf(querySeparator)) {
if (options.query) {
var queryString = '_' + path.slice(path.indexOf(querySeparator) + querySeparator.length)
var queryString = '$' + path.slice(path.indexOf(querySeparator) + querySeparator.length)
result = URLON.parse(queryString)
}
path = path.split(querySeparator)[0]
Expand All @@ -35,11 +47,9 @@ function compileRoute (route, options) {
for (var i = 1; i < match.length; ++i) {
var key = keys[i - 1]
var value = match[i] && decodeURIComponent(match[i])
if (value && value[0] === ':') {
result[key] = URLON.parse(value)
} else {
result[key] = value
}
result[key] = (value && value[0] === ':')
? URLON.parse(value)
: value
}

return result
Expand All @@ -58,26 +68,31 @@ function compileRoute (route, options) {
break

case 'object':
throw new Error('URL Mapper - objects are not allowed to be stringified as part of path')
if (values[key]) {
throw new Error('URL Mapper - objects are not allowed to be stringified as part of path')
} else { // null
pathParams[key] = URLON.stringify(values[key])
}
break

default:
pathParams[key] = values[key]
}
} else {
if (typeof values[key] !== 'undefined') queryParams[key] = values[key]
queryParams[key] = values[key]
}
})

var path = compiled(pathParams)
var path = compiled(pathParams, { encode: encodeSegment })
var queryString = ''

if (options.query) {
if (Object.keys(queryParams).length) {
queryString = querySeparator + URLON.stringify(queryParams).slice(1)
queryString = URLON.stringify(queryParams).slice(1)
}
}

return path + queryString
return path + (queryString ? querySeparator + queryString : '')
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ var object = {
foo: 'bar',
bar: true,
baz: {
foo: true,
foo: false,
bar: 2,
baz: ['foo', 'bar', 'baz'],
e: ''
baz: ['foo', 'bar', 'baz', true, false, undefined, null],
qux: '',
quux: null,
garply: undefined
}
}

Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@
"url": "https://github.com/cerebral/url-mapper/issues"
},
"homepage": "https://github.com/cerebral/url-mapper#readme",
"tonicExampleFilename": "example.js",
"runkitExampleFilename": "example.js",
"devDependencies": {
"commitizen": "^2.5.0",
"coveralls": "^2.11.4",
"coveralls": "^3.0.0",
"cz-customizable": "^2.7.0",
"ghooks": "^1.0.3",
"istanbul": "^0.4.0",
"nodeunit": "^0.9.1",
"nodeunit": "^0.11.2",
"semantic-release": "^4.3.5",
"standard": "^6.0.7",
"standard": "^10.0.3",
"validate-commit-msg": "^2.3.1"
},
"dependencies": {
"urlon": "^2.0.0",
"path-to-regexp": "^1.2.1"
"urlon": "^3.0.1",
"path-to-regexp": "^2.1.0"
},
"config": {
"commitizen": {
Expand Down
23 changes: 19 additions & 4 deletions tests/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,28 @@ module.exports = {
var object = {
foo: true,
bar: false,
baz: 42
baz: 42,
qux: null
}
// URLON-like notation
var url = '/%3Atrue/%3Afalse/%3A42'
var url = '/:true/:false/:42/:null'

test.equal(mapper.stringify('/:foo/:bar/:baz', object), url)
test.deepEqual(mapper.parse('/:foo/:bar/:baz', url), object)
test.equal(mapper.stringify('/:foo/:bar/:baz/:qux', object), url)
test.deepEqual(mapper.parse('/:foo/:bar/:baz/:qux', url), object)

test.done()
},

'should properly escape unsafe symbols in segments': function (test) {
var mapper = urlMapper()
var object = {
foo: 'foo/?#\'"bar'
}
// URLON-like notation
var url = '/foo%2F%3F%23%27%22bar'

test.equal(mapper.stringify('/:foo', object), url)
test.deepEqual(mapper.parse('/:foo', url), object)

test.done()
},
Expand Down