Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: delvedor/find-my-way
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v8.1.0
Choose a base ref
...
head repository: delvedor/find-my-way
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v8.2.0
Choose a head ref
  • 12 commits
  • 16 files changed
  • 7 contributors

Commits on Jan 17, 2024

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f3170bd View commit details

Commits on Feb 16, 2024

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    c4ffd9e View commit details

Commits on Mar 5, 2024

  1. add dependabot.yml (#350)

    * add dependabot.yml
    
    * add automerge bot
    
    * improve
    
    * fix
    Uzlopak authored Mar 5, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    51a47ca View commit details
  2. chore: bump actions/setup-node from 3 to 4 (#351)

    Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4.
    - [Release notes](https://github.com/actions/setup-node/releases)
    - [Commits](actions/setup-node@v3...v4)
    
    ---
    updated-dependencies:
    - dependency-name: actions/setup-node
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Mar 5, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    de27d87 View commit details
  3. chore: bump actions/checkout from 3 to 4 (#352)

    Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
    - [Release notes](https://github.com/actions/checkout/releases)
    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
    - [Commits](actions/checkout@v3...v4)
    
    ---
    updated-dependencies:
    - dependency-name: actions/checkout
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Mar 5, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    9731ad7 View commit details
  4. Achieve 100% test coverage (#349)

    * test: Router module integration
    
    test: findMyWay.findRoute should also trows an error when wildcard is not the last character
    
    test: does not find the route if maxParamLength is exceeded
    
    refactor: make integration test more compliant with the existing code base
    
    test: cover uncovered constrainer.js test cases
    
    test: safeDecodeURIComponent should replace %3x to null for every x that is not a valid lowchar
    
    test: SemVerStore version should be a string
    
    test: httpMethodStrategy storage handles set and get operations correctly
    
    test: case insensitive static routes of level 1 for FindMyWay.findRoute
    
    test: findRoute normalizes wildcard patterns to require leading slash
    
    refactor: make tests more consistants with the existing
    
    test: should return null if no wildchar child
    
    Date:      Tue Feb 20 14:10:18 2024 +0100
    Achieves 100% test coverage
    
    * fix: add proxyquire to dev dependencies
    
    * test: cover uncovered branches in index.js
    
    * fix: revert 'if (nextCharCode === 58)' stmt to one line
    
    * fix: remove useless parametric node kind check
    
    * fix: if it is a wildchar node, it has a child
    
    * fix: a wildcard route created via the router api necessarily has a pattern with a leading slash
    
    * fix: non-custom strategy error only happen when user dont use the appropriate api
    
    * fix: there is no way found route params is not an array, expect if user break internals
    
    * test: Constrainer.noteUsage
    
    * Cannot derive constraints without active strategies.
    
    * test: should derive multiple async constraints
    
    * test: Major version must be a numeric value
    
    * test: SemVerStore.maxMajor should increase automatically
    
    * test: SemVerStore.maxPatches should increase automatically
    
    * refactor: httpMethods module should be a source of truth
    
    * refactor: make consistent use of fmw.on
    
    * fix: istanbul should ignore the complete function
    
    * test: remove 90 min limit for code coverage
    
    * fix: when no args is passed, undefined is default value
    
    * fix: add new line at the end of .taprc
    
    * fix: readd removed comment indicating static route
    jean-michelet authored Mar 5, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    e117960 View commit details
  5. chore: bump the dependencies-major group with 1 update (#353)

    Bumps the dependencies-major group with 1 update: [safe-regex2](https://github.com/fastify/safe-regex).
    
    
    Updates `safe-regex2` from 2.0.0 to 3.1.0
    - [Release notes](https://github.com/fastify/safe-regex/releases)
    - [Commits](https://github.com/fastify/safe-regex/commits/v3.1.0)
    
    ---
    updated-dependencies:
    - dependency-name: safe-regex2
      dependency-type: direct:production
      update-type: version-update:semver-major
      dependency-group: dependencies-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Mar 5, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    8c7983c View commit details
  6. Fix header in README (#345)

    selimb authored Mar 5, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    a9d1ee1 View commit details

Commits on Apr 29, 2024

  1. Exclude Node v14 and v16 on macos (#364)

    Signed-off-by: Matteo Collina <hello@matteocollina.com>
    mcollina authored Apr 29, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    20e7b1c View commit details
  2. add node v22. Skip old nodes on mac (#363)

    Signed-off-by: Matteo Collina <hello@matteocollina.com>
    mcollina authored Apr 29, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    984ff20 View commit details

Commits on Apr 30, 2024

  1. Support optional params on root (#367)

    Signed-off-by: Matteo Collina <hello@matteocollina.com>
    mcollina authored Apr 30, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    cce5437 View commit details
  2. Bumped v8.2.0

    Signed-off-by: Matteo Collina <hello@matteocollina.com>
    mcollina committed Apr 30, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    mcollina Matteo Collina
    Copy the full SHA
    ea27fa2 View commit details
34 changes: 34 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
commit-message:
# Prefix all commit messages with "chore: "
prefix: "chore"
schedule:
interval: "monthly"
open-pull-requests-limit: 10

- package-ecosystem: "npm"
directory: "/"
commit-message:
# Prefix all commit messages with "chore: "
prefix: "chore"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
# Production dependencies without breaking changes
dependencies:
dependency-type: "production"
update-types:
- "minor"
- "patch"
# Production dependencies with breaking changes
dependencies-major:
dependency-type: "production"
update-types:
- "major"
# Development dependencies
dev-dependencies:
dependency-type: "development"
46 changes: 40 additions & 6 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: Node CI

on: [push, pull_request]
on:
push:
branches:
- main
- next
pull_request:

permissions:
contents: read
@@ -12,17 +17,32 @@ jobs:

strategy:
matrix:
node-version: [14.x, 16.x, 18.x, 20.x]
os: [ubuntu-latest, windows-latest, macOS-latest]
node-version:
- 14
- 16
- 18
- 20
- 21
- 22
os:
- ubuntu-latest
- windows-latest
- macOS-latest
exclude:
- os: windows-latest
node-version: 14.x
node-version: 14
- os: macos-latest
node-version: 14
- os: macos-latest
node-version: 16
- os: windows-latest
node-version: 22

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

@@ -41,3 +61,17 @@ jobs:
- name: Type Definitions
run: |
npm run test:typescript
automerge:
if: >
github.event_name == 'pull_request' && github.event.pull_request.user.login == 'dependabot[bot]'
needs: test
runs-on: ubuntu-latest
permissions:
actions: write
pull-requests: write
contents: write
steps:
- uses: fastify/github-action-merge-dependabot@9e7bfb249c69139d7bdcd8d984f9665edd49020b # v3.10.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
4 changes: 0 additions & 4 deletions .taprc
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
ts: false
jsx: false
flow: false
branches: 90
functions: 90
lines: 90
statements: 90
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -443,8 +443,8 @@ router.hasRoute('GET', '/:file(^\\D+).jpg')
// => false
```

```js
#### lookup(request, response, [context], [done])

Start a new search, `request` and `response` are the server req/res objects.<br>
If a route is found it will automatically call the handler, otherwise the default route will be called.<br>
The url is sanitized internally, all the parameters and wildcards are decoded automatically.
64 changes: 27 additions & 37 deletions index.js
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
'~': 126 - ~
*/

const assert = require('assert')
const assert = require('node:assert')
const querystring = require('fast-querystring')
const isRegexSafe = require('safe-regex2')
const deepEqual = require('fast-deep-equal')
@@ -115,7 +115,7 @@ Router.prototype.on = function on (method, path, opts, handler, store) {
assert(path.length === optionalParamMatch.index + optionalParamMatch[0].length, 'Optional Parameter needs to be the last parameter of the path')

const pathFull = path.replace(OPTIONAL_PARAM_REGEXP, '$1$2')
const pathOptional = path.replace(OPTIONAL_PARAM_REGEXP, '$2')
const pathOptional = path.replace(OPTIONAL_PARAM_REGEXP, '$2') || '/'

this.on(method, pathFull, opts, handler, store)
this.on(method, pathOptional, opts, handler, store)
@@ -344,7 +344,6 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
const isRegexParam = charCode === 40
const isStaticPart = charCode === 45 || charCode === 46
const isEndOfNode = charCode === 47 || j === pattern.length

if (isRegexParam || isStaticPart || isEndOfNode) {
const paramName = pattern.slice(lastParamStartIndex, j)
params.push(paramName)
@@ -407,9 +406,7 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
// add the wildcard parameter
params.push('*')
currentNode = currentNode.getWildcardChild()
if (currentNode === null) {
return null
}

parentNodePathIndex = i + 1

if (i !== pattern.length - 1) {
@@ -422,10 +419,6 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
pattern = pattern.toLowerCase()
}

if (pattern === '*') {
pattern = '/*'
}

for (const existRoute of this.routes) {
const routeConstraints = existRoute.opts.constraints || {}
if (
@@ -436,7 +429,7 @@ Router.prototype.findRoute = function findNode (method, path, constraints = {})
return {
handler: existRoute.handler,
store: existRoute.store,
params: existRoute.params || []
params: existRoute.params
}
}
}
@@ -642,37 +635,36 @@ Router.prototype.find = function find (method, path, derivedConstraints) {
continue
}

if (currentNode.kind === NODE_TYPES.PARAMETRIC) {
let paramEndIndex = originPath.indexOf('/', pathIndex)
if (paramEndIndex === -1) {
paramEndIndex = pathLen
}
// parametric node
let paramEndIndex = originPath.indexOf('/', pathIndex)
if (paramEndIndex === -1) {
paramEndIndex = pathLen
}

let param = originPath.slice(pathIndex, paramEndIndex)
if (shouldDecodeParam) {
param = safeDecodeURIComponent(param)
}
let param = originPath.slice(pathIndex, paramEndIndex)
if (shouldDecodeParam) {
param = safeDecodeURIComponent(param)
}

if (currentNode.isRegex) {
const matchedParameters = currentNode.regex.exec(param)
if (matchedParameters === null) continue
if (currentNode.isRegex) {
const matchedParameters = currentNode.regex.exec(param)
if (matchedParameters === null) continue

for (let i = 1; i < matchedParameters.length; i++) {
const matchedParam = matchedParameters[i]
if (matchedParam.length > maxParamLength) {
return null
}
params.push(matchedParam)
}
} else {
if (param.length > maxParamLength) {
for (let i = 1; i < matchedParameters.length; i++) {
const matchedParam = matchedParameters[i]
if (matchedParam.length > maxParamLength) {
return null
}
params.push(param)
params.push(matchedParam)
}

pathIndex = paramEndIndex
} else {
if (param.length > maxParamLength) {
return null
}
params.push(param)
}

pathIndex = paramEndIndex
}
}

@@ -742,8 +734,6 @@ for (const i in httpMethods) {
const m = httpMethods[i]
const methodName = m.toLowerCase()

if (Router.prototype[methodName]) throw new Error('Method already exists: ' + methodName)

Router.prototype[methodName] = function (path, handler, store) {
return this.on(m, path, handler, store)
}
6 changes: 2 additions & 4 deletions lib/constrainer.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

const acceptVersionStrategy = require('./strategies/accept-version')
const acceptHostStrategy = require('./strategies/accept-host')
const assert = require('assert')
const assert = require('node:assert')

class Constrainer {
constructor (customStrategies) {
@@ -153,10 +153,8 @@ class Constrainer {
if (!strategy.isCustom) {
if (key === 'version') {
lines.push(' version: req.headers[\'accept-version\'],')
} else if (key === 'host') {
lines.push(' host: req.headers.host || req.headers[\':authority\'],')
} else {
throw new Error('unknown non-custom strategy for compiling constraint derivation function')
lines.push(' host: req.headers.host || req.headers[\':authority\'],')
}
} else {
lines.push(` ${strategy.name}: this.strategies.${key}.deriveConstraint(req, ctx),`)
4 changes: 2 additions & 2 deletions lib/handler-storage.js
Original file line number Diff line number Diff line change
@@ -47,8 +47,8 @@ class HandlerStorage {
}

const isMergedTree = constraintsNames.includes(httpMethodStrategy.name)
if (!isMergedTree && this.handlers.length >= 32) {
throw new Error('find-my-way supports a maximum of 32 route handlers per node when there are constraints, limit reached')
if (!isMergedTree && this.handlers.length >= 31) {
throw new Error('find-my-way supports a maximum of 31 route handlers per node when there are constraints, limit reached')
}

this.handlers.push(handlerObject)
5 changes: 1 addition & 4 deletions lib/node.js
Original file line number Diff line number Diff line change
@@ -129,10 +129,7 @@ class StaticNode extends ParentNode {
}

getWildcardChild () {
if (this.wildcardChild) {
return this.wildcardChild
}
return null
return this.wildcardChild
}

createWildcardChild () {
2 changes: 1 addition & 1 deletion lib/strategies/accept-host.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use strict'
const assert = require('assert')
const assert = require('node:assert')

function HostStorage () {
const hosts = {}
10 changes: 7 additions & 3 deletions lib/strategies/accept-version.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const assert = require('assert')
const assert = require('node:assert')

function SemVerStore () {
if (!(this instanceof SemVerStore)) {
@@ -20,7 +20,11 @@ SemVerStore.prototype.set = function (version, store) {
}
let [major, minor, patch] = version.split('.')

major = Number(major) || 0
if (isNaN(major)) {
throw new TypeError('Major version must be a numeric value')
}

major = Number(major)
minor = Number(minor) || 0
patch = Number(patch) || 0

@@ -38,7 +42,7 @@ SemVerStore.prototype.set = function (version, store) {
this.store[`${major}.x.x`] = store
}

if (patch >= (this.store[`${major}.${minor}`] || 0)) {
if (patch >= (this.maxPatches[`${major}.${minor}`] || 0)) {
this.maxPatches[`${major}.${minor}`] = patch
this.store[`${major}.${minor}.x`] = store
}
5 changes: 1 addition & 4 deletions lib/strategies/http-method.js
Original file line number Diff line number Diff line change
@@ -9,9 +9,6 @@ module.exports = {
set: (type, store) => { handlers[type] = store }
}
},
deriveConstraint: (req) => {
/* istanbul ignore next */
return req.method
},
deriveConstraint: /* istanbul ignore next */ (req) => req.method,
mustMatchWhenDerived: true
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "find-my-way",
"version": "8.1.0",
"version": "8.2.0",
"description": "Crazy fast http radix based router",
"main": "index.js",
"types": "index.d.ts",
@@ -40,6 +40,7 @@
"chalk": "^4.1.2",
"inquirer": "^8.2.4",
"pre-commit": "^1.2.2",
"proxyquire": "^2.1.3",
"rfdc": "^1.3.0",
"simple-git": "^3.7.1",
"standard": "^14.3.4",
@@ -50,7 +51,7 @@
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-querystring": "^1.0.0",
"safe-regex2": "^2.0.0"
"safe-regex2": "^3.1.0"
},
"tsd": {
"directory": "test/types"
10 changes: 7 additions & 3 deletions test/constraint.custom.async.test.js
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
const t = require('tap')
const test = t.test
const FindMyWay = require('..')
const rfdc = require('rfdc')({ proto: true })

const customHeaderConstraint = {
name: 'requestedBy',
@@ -23,11 +24,14 @@ const customHeaderConstraint = {
}
}

test('should derive async constraint', t => {
test('should derive multiple async constraints', t => {
t.plan(2)

const router = FindMyWay({ constraints: { requestedBy: customHeaderConstraint } })
router.on('GET', '/', { constraints: { requestedBy: 'node' } }, () => 'asyncHandler')
const customHeaderConstraint2 = rfdc(customHeaderConstraint)
customHeaderConstraint2.name = 'requestedBy2'

const router = FindMyWay({ constraints: { requestedBy: customHeaderConstraint, requestedBy2: customHeaderConstraint2 } })
router.on('GET', '/', { constraints: { requestedBy: 'node', requestedBy2: 'node' } }, () => 'asyncHandler')

router.lookup(
{
Loading