Verified Commit 3820fcd9 authored by Aral Balkan's avatar Aral Balkan
Browse files

Add parameter support to routes (breaking change)

  - Also add unit tests.
parent 581305cd
......@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.0.0] - 2020-08-31
### Added
- Support for parameters defined in route callback file names. Note that this might break behaviour if your route callback file names had underscores in them, hence the major version bump.
## [2.0.0] - 2020-04-16
### Changed
......
function route (request, response, next) {
response.end(`person/${request.params.personId}/book/${request.params.bookId}`)
}
module.exports = route
function route (request, response, next) {
response.end(`rabbit/${rabbitName}`)
}
module.exports = route
......@@ -30,9 +30,22 @@ function routes (directory, directoryRoot = null) {
// File.
//
let routeCallbackFilePath = path.resolve(path.join(directory, file.name))
let routeUrlPath = path.join(directory.replace(directoryRoot, ''), file.name.replace('.js', ''))
routeUrlPath = routeUrlPath.replace(/index$/, '')
let routeUrlPath = path.join(directory.replace(directoryRoot, ''), file.name)
routeUrlPath = routeUrlPath.replace(/\/?index(.*?)\.js$/, '$1')
routeUrlPath = routeUrlPath.replace('.js', '')
routeUrlPath = routeUrlPath.replace(/\/$/, '')
// Handle parameter formatting:
//
// _ : parameter delimeter (/:)
// __ : static path fragment delimeter (/)
//
// e.g., /person/index_personId__book__bookId becomes:
// /person/:personId/book/:bookId
routeUrlPath = routeUrlPath.replace(/__/g, '/')
routeUrlPath = routeUrlPath.replace(/_/g, '/:')
// On Windows, the file path slashes are backwards so we have to reverse them.
if (process.platform === 'win32') {
// Since the code replacing the forward slash at the end will not have caught a backslash at the end
......
This diff is collapsed.
{
"name": "@small-tech/web-routes-from-files",
"version": "2.0.0",
"version": "3.0.0",
"description": "Recursively traverses a given directory structure and uses convention to create a list of web route objects that map url paths to JavaScript callback files.",
"keywords": [
"files",
......@@ -27,7 +27,7 @@
"example": "example"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "tape test/*.js | tap-spec"
},
"author": {
"name": "Aral Balkan",
......@@ -36,6 +36,8 @@
},
"license": "AGPL-3.0-or-later",
"devDependencies": {
"express": "^4.16.4"
"express": "^4.16.4",
"tap-spec": "^5.0.0",
"tape": "^5.0.1"
}
}
# Web routes from files
Recursively traverses a given directory structure and uses convention to create a list of web route objects that map url paths to JavaScript callback files.
Recursively traverses a given directory structure and uses convention to create a list of web route objects that map Express-style URL paths to JavaScript callback files.
## Installation
......@@ -30,6 +30,9 @@ Given the following directory structure:
├─── my-folder
│ ├── index.js
│ └── other.js
├─── person
│ └── index_personId__book_bookId.js
├─── rabbit_rabbitName.js
└─── neat.js
```
......@@ -44,10 +47,12 @@ You will get the following data structure:
```js
[
{ path: '/', file: '.routes/index.js' },
{ path: '/my-folder', file: '.routes/my-folder/index.js' },
{ path: '/my-folder/other', file: '.routes/my-folder/other.js' },
{ path: '/neat', file: '.routes/neat.js' }
{ path: '/', callback: '.routes/index.js' },
{ path: '/my-folder', callback: '.routes/my-folder/index.js' },
{ path: '/my-folder/other', callback: '.routes/my-folder/other.js' },
{ path: '/person/:personId/book/:bookId', callback: '.routes/person/index_personId__book_bookId.js' },
{ path: '/rabbit/:rabbitName', callback: '.routes/rabbit_rabbitName.js' },
{ path: '/neat', callback: '.routes/neat.js' }
]
```
......@@ -79,6 +84,15 @@ function route (request, response, next) {
module.exports = route
```
Routes that take parameters (introduced in version 3.0.0) can access them from the `request.params` object. e.g., in the `.routes/person/index_personId__book_bookId.js` callback file:
```js
function route (request, response, next) {
response.end(`person/${request.params.personId}/book/${request.params.bookId}`)
}
module.exports = route
```
This example is included in the source code. Run it with:
```sh
......
const path = require('path')
const getRoutes = require ('..')
const test = require('tape')
test('routes', t => {
t.plan(12)
const actualRoutes = getRoutes(path.join('example', '.routes'))
const expectedRoutes = [
{
path: '/',
callback: '/home/aral/small-tech/site.js/lib/web-routes-from-files/example/.routes/index.js'
},
{
path: '/my-folder',
callback: '/home/aral/small-tech/site.js/lib/web-routes-from-files/example/.routes/my-folder/index.js'
},
{
path: '/my-folder/other',
callback: '/home/aral/small-tech/site.js/lib/web-routes-from-files/example/.routes/my-folder/other.js'
},
{
path: '/neat',
callback: '/home/aral/small-tech/site.js/lib/web-routes-from-files/example/.routes/neat.js'
},
{
path: '/person/:personId/book/:bookId',
callback: '/home/aral/small-tech/site.js/lib/web-routes-from-files/example/.routes/person/index_personId__book_bookId.js'
},
{
path: '/rabbit/:rabbitName',
callback: '/home/aral/small-tech/site.js/lib/web-routes-from-files/example/.routes/rabbit_rabbitName.js'
}
]
expectedRoutes.forEach((expectedRoute, index) => {
const actualRoute = actualRoutes[index]
t.strictEquals(actualRoute.path, expectedRoute.path, `Route #${index}: route is correct.`)
t.strictEquals(actualRoute.callback, expectedRoute.callback, `Route #${index}: callback path is correct.`)
})
t.end()
})
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment