Skip to content

Commit

Permalink
feat: loose escaping, null support, updated deps
Browse files Browse the repository at this point in the history
URLON updated to 3.0.1, which introduces improved readability by loose escaping,
better safety by fixing undefined and compatibility with utm tracking links.
See https://github.com/cerebral/urlon/releases/tag/3.0.0 for details.

path-to-regex update allows avoid unnecessary of colons used to preserve types.
See pillarjs/path-to-regexp#75 for details.

`null` values is now supprted in path parts.

BREAKING CHANGE:
Stringify format changed. Parsing values generated by previous version isn't possible anymore.

fixes #27, fixes #28
  • Loading branch information
Guria committed Nov 21, 2017
1 parent e59295c commit 0332986
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 43 deletions.
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
9 changes: 5 additions & 4 deletions tests/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,14 @@ 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()
},
Expand Down

0 comments on commit 0332986

Please sign in to comment.