Skip to content

Commit dce1000

Browse files
committed
Use regexparam as default pattern compiler
1 parent 4bea66a commit dce1000

File tree

7 files changed

+443
-626
lines changed

7 files changed

+443
-626
lines changed

lib/path.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ function compilePattern (pattern, compiler) {
1414
return _compiledPatterns[pattern]
1515
}
1616

17+
export function clearPatternCompilerCache () {
18+
for (const x in _compiledPatterns) {
19+
delete _compiledPatterns[x]
20+
}
21+
}
22+
1723
/**
1824
* Returns an array of the names of all parameters in the given pattern.
1925
*/

lib/patternCompiler.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
import { pathToRegexp } from 'path-to-regexp'
1+
import { parse } from 'regexparam'
2+
3+
const splatRegex = /:(\w+)\*/
24

35
export function patternCompiler (pattern) {
4-
const paramNames = []
5-
const re = pathToRegexp(pattern, paramNames)
6+
// hack to add (partial) named splat support
7+
const splatMatch = splatRegex.exec(pattern)
8+
const normalizedPattern = splatMatch ? pattern.replace(splatRegex, '*') : pattern
9+
10+
const { pattern: matcher, keys } = parse(normalizedPattern)
11+
12+
const paramNames = splatMatch ? keys.map(key => key === 'wild' ? splatMatch[1] : key) : keys
613

714
return {
8-
matcher: re,
9-
paramNames: paramNames.map(p => p.name)
15+
matcher,
16+
paramNames
1017
}
1118
}

package.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"url": "https://github.com/blikblum/slick-router/issues"
2424
},
2525
"dependencies": {
26-
"path-to-regexp": "^5.0.0"
26+
"regexparam": "^2.0.0"
2727
},
2828
"keywords": [
2929
"router",
@@ -34,16 +34,18 @@
3434
"nested"
3535
],
3636
"devDependencies": {
37-
"@open-wc/testing": "^2.5.33",
38-
"@web/dev-server": "^0.1.17",
39-
"@web/dev-server-import-maps": "^0.0.5",
40-
"@web/test-runner": "^0.13.13",
37+
"@open-wc/testing": "^3.0.2",
38+
"@web/dev-server": "^0.1.25",
39+
"@web/dev-server-import-maps": "^0.0.6",
40+
"@web/test-runner": "^0.13.20",
41+
"chai": "^4.3.4",
4142
"del": "^6.0.0",
4243
"jquery": "^3.6.0",
4344
"lit-element": "^2.5.1",
45+
"path-to-regexp": "5.0.0",
4446
"rollup": "^2.52.4",
4547
"rollup-plugin-cpy": "^2.0.1",
46-
"sinon": "^11.1.1",
48+
"sinon": "^11.1.2",
4749
"snazzy": "^9.0.0",
4850
"standard": "^16.0.3"
4951
},

tests/unit/pathTest.js

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,49 @@
11
import qs from '../../lib/qs'
22
import * as Path from '../../lib/path'
33
import 'chai/chai.js'
4-
import { patternCompiler } from '../../lib/patternCompiler.js'
4+
import { patternCompiler as defaultPatternCompiler } from '../../lib/patternCompiler.js'
5+
import { patternCompiler as pathToRegexPatternCompiler } from './pathToRegexPatternCompiler.js'
56

67
const { assert } = window.chai
78
const { describe, it } = window
89

9-
describe('Path', () => {
10-
it('Path.extractParamNames', () => {
11-
assert.deepEqual(Path.extractParamNames('a/b/c', patternCompiler), [])
12-
assert.deepEqual(Path.extractParamNames('/comments/:a/:b/edit', patternCompiler), ['a', 'b'])
13-
assert.deepEqual(Path.extractParamNames('/files/:path*.jpg', patternCompiler), ['path'])
14-
})
10+
function testExtractParamNames (patternCompiler) {
11+
assert.deepEqual(Path.extractParamNames('a/b/c', patternCompiler), [])
12+
assert.deepEqual(Path.extractParamNames('/comments/:a/:b/edit', patternCompiler), ['a', 'b'])
13+
assert.deepEqual(Path.extractParamNames('/files/:path*.jpg', patternCompiler), ['path'])
14+
}
15+
16+
function testExtractParams (patternCompiler, edgeCases) {
17+
assert.deepEqual(Path.extractParams('/a/b/c', '/a/b/c', patternCompiler), {})
18+
assert.deepEqual(Path.extractParams('/a/b/c', '/d/e/f', patternCompiler), null)
1519

16-
it('Path.extractParams', () => {
17-
assert.deepEqual(Path.extractParams('a/b/c', 'a/b/c', patternCompiler), {})
18-
assert.deepEqual(Path.extractParams('a/b/c', 'd/e/f', patternCompiler), null)
20+
assert.deepEqual(Path.extractParams('/comments/:id?/edit', '/comments/123/edit', patternCompiler), { id: '123' })
21+
assert.deepEqual(Path.extractParams('/comments/:id?/edit', '/comments/the%2Fid/edit', patternCompiler), { id: 'the/id' })
22+
assert.deepEqual(Path.extractParams('/comments/:id?/edit', '/comments//edit', patternCompiler), null)
23+
assert.deepEqual(Path.extractParams('/comments/:id?/edit', '/users/123', patternCompiler), null)
1924

20-
assert.deepEqual(Path.extractParams('comments/:id.:ext/edit', 'comments/abc.js/edit', patternCompiler), { id: 'abc', ext: 'js' })
25+
assert.deepEqual(Path.extractParams('/one, two', '/one, two', patternCompiler), {})
26+
assert.deepEqual(Path.extractParams('/one, two', '/one two', patternCompiler), null)
2127

22-
assert.deepEqual(Path.extractParams('comments/:id?/edit', 'comments/123/edit', patternCompiler), { id: '123' })
23-
assert.deepEqual(Path.extractParams('comments/:id?/edit', 'comments/the%2Fid/edit', patternCompiler), { id: 'the/id' })
24-
assert.deepEqual(Path.extractParams('comments/:id?/edit', 'comments//edit', patternCompiler), null)
25-
assert.deepEqual(Path.extractParams('comments/:id?/edit', 'users/123', patternCompiler), null)
28+
assert.deepEqual(Path.extractParams('/comments/:id/edit now', '/comments/abc/edit now', patternCompiler), { id: 'abc' })
29+
assert.deepEqual(Path.extractParams('/comments/:id/edit now', '/users/123', patternCompiler), null)
2630

27-
assert.deepEqual(Path.extractParams('one, two', 'one, two', patternCompiler), {})
28-
assert.deepEqual(Path.extractParams('one, two', 'one two', patternCompiler), null)
31+
assert.deepEqual(Path.extractParams('/files/:path*', '/files/my/photo.jpg', patternCompiler), { path: 'my/photo.jpg' })
32+
assert.deepEqual(Path.extractParams('/files/:path*', '/files/my/photo.jpg.zip', patternCompiler), { path: 'my/photo.jpg.zip' })
2933

30-
assert.deepEqual(Path.extractParams('/comments/:id/edit now', '/comments/abc/edit now', patternCompiler), { id: 'abc' })
31-
assert.deepEqual(Path.extractParams('/comments/:id/edit now', '/users/123', patternCompiler), null)
34+
assert.deepEqual(Path.extractParams('/archive/:name?', '/archive', patternCompiler), { name: undefined })
35+
assert.deepEqual(Path.extractParams('/archive/:name?', '/archive/', patternCompiler), { name: undefined })
36+
assert.deepEqual(Path.extractParams('/archive/:name?', '/archive/foo', patternCompiler), { name: 'foo' })
37+
assert.deepEqual(Path.extractParams('/archive/:name?', '/archivefoo', patternCompiler), null)
38+
assert.deepEqual(Path.extractParams('/archive/:name?', '/archiv', patternCompiler), null)
3239

33-
assert.deepEqual(Path.extractParams('/files/:path*', '/files/my/photo.jpg', patternCompiler), { path: 'my/photo.jpg' })
34-
assert.deepEqual(Path.extractParams('/files/:path*', '/files/my/photo.jpg.zip', patternCompiler), { path: 'my/photo.jpg.zip' })
40+
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo/with/foo.app', patternCompiler), { query: 'foo', domain: 'foo.app' })
41+
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo.ap/with/foo', patternCompiler), { query: 'foo.ap', domain: 'foo' })
42+
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo.ap/with/foo.app', patternCompiler), { query: 'foo.ap', domain: 'foo.app' })
43+
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo.ap', patternCompiler), null)
44+
45+
if (edgeCases) {
46+
assert.deepEqual(Path.extractParams('/comments/:id.:ext/edit', '/comments/abc.js/edit', patternCompiler), { id: 'abc', ext: 'js' })
3547
assert.deepEqual(Path.extractParams('/files/:path*.jpg', '/files/my%2Fphoto.jpg', patternCompiler), { path: 'my/photo' })
3648
assert.deepEqual(Path.extractParams('/files/:path*', '/files', patternCompiler), { path: undefined })
3749
assert.deepEqual(Path.extractParams('/files/:path*', '/files/', patternCompiler), { path: undefined })
@@ -51,22 +63,37 @@ describe('Path', () => {
5163
assert.deepEqual(Path.extractParams('/files/:path+', '/files/', patternCompiler), null)
5264
assert.deepEqual(Path.extractParams('/files/:path+.jpg', '/files/my/photo.png', patternCompiler), null)
5365

54-
assert.deepEqual(Path.extractParams('/archive/:name?', '/archive', patternCompiler), { name: undefined })
55-
assert.deepEqual(Path.extractParams('/archive/:name?', '/archive/', patternCompiler), { name: undefined })
56-
assert.deepEqual(Path.extractParams('/archive/:name?', '/archive/foo', patternCompiler), { name: 'foo' })
57-
assert.deepEqual(Path.extractParams('/archive/:name?', '/archivefoo', patternCompiler), null)
58-
assert.deepEqual(Path.extractParams('/archive/:name?', '/archiv', patternCompiler), null)
59-
60-
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo/with/foo.app', patternCompiler), { query: 'foo', domain: 'foo.app' })
61-
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo.ap/with/foo', patternCompiler), { query: 'foo.ap', domain: 'foo' })
62-
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo.ap/with/foo.app', patternCompiler), { query: 'foo.ap', domain: 'foo.app' })
63-
assert.deepEqual(Path.extractParams('/:query/with/:domain', '/foo.ap', patternCompiler), null)
64-
6566
// advanced use case of making params in the middle of the url optional
6667
assert.deepEqual(Path.extractParams('/comments/:id(.*/?edit)', '/comments/123/edit', patternCompiler), { id: '123/edit' })
6768
assert.deepEqual(Path.extractParams('/comments/:id(.*/?edit)', '/comments/edit', patternCompiler), { id: 'edit' })
6869
assert.deepEqual(Path.extractParams('/comments/:id(.*/?edit)', '/comments/editor', patternCompiler), null)
6970
assert.deepEqual(Path.extractParams('/comments/:id(.*/?edit)', '/comments/123', patternCompiler), null)
71+
}
72+
}
73+
74+
describe('Path', () => {
75+
describe('Path.extractParamNames', () => {
76+
it('with default patternCompiler', () => {
77+
Path.clearPatternCompilerCache()
78+
testExtractParamNames(defaultPatternCompiler, false)
79+
})
80+
81+
it('with pathToRegex patternCompiler', () => {
82+
Path.clearPatternCompilerCache()
83+
testExtractParamNames(pathToRegexPatternCompiler, true)
84+
})
85+
})
86+
87+
describe('Path.extractParams', () => {
88+
it('with default patternCompiler', () => {
89+
Path.clearPatternCompilerCache()
90+
testExtractParams(defaultPatternCompiler, false)
91+
})
92+
93+
it('with pathToRegex patternCompiler', () => {
94+
Path.clearPatternCompilerCache()
95+
testExtractParams(pathToRegexPatternCompiler, true)
96+
})
7097
})
7198

7299
it('Path.injectParams', () => {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { pathToRegexp } from 'path-to-regexp'
2+
3+
export function patternCompiler (pattern) {
4+
const paramNames = []
5+
const re = pathToRegexp(pattern, paramNames)
6+
7+
return {
8+
matcher: re,
9+
paramNames: paramNames.map(p => p.name)
10+
}
11+
}

web-dev-server.config.mjs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { importMapsPlugin } from '@web/dev-server-import-maps';
1+
import { importMapsPlugin } from '@web/dev-server-import-maps'
22

33
export default {
4-
plugins: [importMapsPlugin()],
5-
};
4+
plugins: [importMapsPlugin()]
5+
}

0 commit comments

Comments
 (0)