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

Upgrade packages, move to GitHub Actions, use fast-glob #10

Merged
merged 4 commits into from Feb 15, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions .eslintrc.cjs
@@ -0,0 +1,28 @@
/* eslint-env node */
module.exports = {
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
root: true,
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
rules: {
// Only disabling this because this code is very old but also battle-tested,
// and coming up with clever typings may break for consumers.
'@typescript-eslint/no-explicit-any': 'off',
// We need to support `Function` and `Constructor` types.
'@typescript-eslint/ban-types': 'off',
},
overrides: [
{
files: ['**/__tests__/*.test.ts'],
rules: {
// The tests may use an untyped library which requires (no pun intended) `require`.
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-unused-vars': 'off',
},
},
],
}
65 changes: 65 additions & 0 deletions .github/workflows/ci.yml
@@ -0,0 +1,65 @@
# Name of the pipeline
name: CI

# Allow the token to create releases and read pull requests.
# Needed for semantic-release.
permissions:
contents: write
pull-requests: read

# When pushing to `master` or when there is a PR for the branch.
on:
pull_request:
push:
branches:
- 'master'

jobs:
ci:
name: Lint, Test & Release (Node ${{ matrix.version }})
runs-on: ubuntu-22.04
strategy:
fail-fast: true
matrix:
version:
- 16
- 18
- 20
- current
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.version }}
cache: 'npm'

- name: Install Packages
run: npm ci

- name: Build
run: npm run build

- name: Lint
run: npm run lint

- name: Test
run: npm run cover

- if: ${{ matrix.version == 'current' }}
name: Coveralls
uses: coverallsapp/github-action@v2

- if: ${{ matrix.version == 'current' }}
name: Semantic Release
run: npm run semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

# Cancel running workflows for the same branch when a new one is started.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
30 changes: 0 additions & 30 deletions .travis.yml

This file was deleted.

2 changes: 2 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,7 @@
# Changelog

> See the [Releases](https://github.com/jeffijoe/awilix-router-core/releases) page for the changelog going forward.

## 1.6.1

- Handle falsy values in `getState`
Expand Down
101 changes: 55 additions & 46 deletions README.md
Expand Up @@ -12,26 +12,27 @@

# Table of Contents

* [Install](#install)
* [Example](#example)
* [With decorators](#with-decorators)
* [With builder pattern](#with-builder-pattern)
* [For framework adapter authors](#for-framework-adapter-authors)
* [API](#api)
* [Route Declaration](#route-declaration)
* [Builder](#builder)
* [createController(targetClassOrFunction)](#createcontrollertargetclassorfunction)
* [Decorators](#decorators)
* [route(path)](#routepath)
* [before(middlewares) and <code>after(middlewares)</code>](#beforemiddlewares-and-aftermiddlewares)
* [verbs(httpVerbs)](#verbshttpverbs)
* [Verb shorthands](#verb-shorthands)
* [Extracting route config](#extracting-route-config)
* [getStateAndTarget(functionOrClassOrController)](#getstateandtargetfunctionorclassorcontroller)
* [rollUpState(state)](#rollupstatestate)
* [findControllers(pattern, globOptions)](#findcontrollerspattern-globoptions)
* [Author](#author)

- [awilix-router-core](#awilix-router-core)
- [Table of Contents](#table-of-contents)
- [Install](#install)
- [Example](#example)
- [With decorators](#with-decorators)
- [With builder pattern](#with-builder-pattern)
- [For framework adapter authors](#for-framework-adapter-authors)
- [API](#api)
- [Route Declaration](#route-declaration)
- [Builder](#builder)
- [`createController(targetClassOrFunction)`](#createcontrollertargetclassorfunction)
- [Decorators](#decorators)
- [`route(path)`](#routepath)
- [`before(middlewares)` and `after(middlewares)`](#beforemiddlewares-and-aftermiddlewares)
- [`verbs(httpVerbs)`](#verbshttpverbs)
- [Verb shorthands](#verb-shorthands)
- [Extracting route config](#extracting-route-config)
- [`getStateAndTarget(functionOrClassOrController)`](#getstateandtargetfunctionorclassorcontroller)
- [`rollUpState(state)`](#rollupstatestate)
- [`findControllers(pattern, globOptions)`](#findcontrollerspattern-globoptions)
- [Author](#author)

# Install

Expand Down Expand Up @@ -66,12 +67,12 @@ import authenticate from 'your-framework-authentication'
@before(bodyParser())
@route('/news')
export default class NewsController {
constructor ({ service }) {
constructor({ service }) {
this.service = service
}

@GET()
async find (ctx) {
async find(ctx) {
ctx.body = await this.service.doSomethingAsync()
}

Expand All @@ -84,7 +85,7 @@ export default class NewsController {
@route('(/:id)')
@verbs([HttpVerbs.POST, HttpVerbs.PUT])
@before(authenticate())
async save (ctx) {
async save(ctx) {
ctx.body = await this.service.saveNews(ctx.params.id, ctx.request.body)
}
}
Expand All @@ -102,9 +103,11 @@ import authenticate from 'your-framework-authentication'
// Can use a factory function or a class.
const api = ({ service }) => ({
find: async () => (ctx.body = await service.doSomethingAsync()),
get: async (ctx) => (ctx.body = await service.getNewsOrWhateverAsync(ctx.params.id)),
save: async (ctx) => (ctx.body = await service.saveNews(ctx.params.id, ctx.request.body))
})
get: async (ctx) =>
(ctx.body = await service.getNewsOrWhateverAsync(ctx.params.id)),
save: async (ctx) =>
(ctx.body = await service.saveNews(ctx.params.id, ctx.request.body)),
})

export default createController(api)
.before(bodyParser())
Expand All @@ -113,7 +116,7 @@ export default createController(api)
.get('/:id', 'get') // <- "get" is the method on the result from `api`
.verbs([HttpVerbs.POST, HttpVerbs.PUT], '/:id', 'save', {
// "save" is the method on the result from `api`
before: [authenticate()]
before: [authenticate()],
})
```

Expand Down Expand Up @@ -145,18 +148,18 @@ Creates a controller that will invoke methods on an instance of the specified `t

The controller exposes the following builder methods:

* `.get|post|put|patch|delete|head|options|connect|all(path, method, opts)`: shorthands for `.verbs([HttpVerbs.POST], ...)` - see [`HttpVerbs`][http-verbs] for possible values.
* `.verbs(verbs, path, method, opts)`: registers a path mapping for the specified controller method.
* `.prefix(path)`: registers a prefix for the controller. Calling this multiple times adds multiple prefix options.
* `.before(middlewares)`: registers one or more middlewares that runs before any of the routes are processed.
* `.after(middlewares)`: registers one or more middlewares that runs after the routes are processed.
- `.get|post|put|patch|delete|head|options|connect|all(path, method, opts)`: shorthands for `.verbs([HttpVerbs.POST], ...)` - see [`HttpVerbs`][http-verbs] for possible values.
- `.verbs(verbs, path, method, opts)`: registers a path mapping for the specified controller method.
- `.prefix(path)`: registers a prefix for the controller. Calling this multiple times adds multiple prefix options.
- `.before(middlewares)`: registers one or more middlewares that runs before any of the routes are processed.
- `.after(middlewares)`: registers one or more middlewares that runs after the routes are processed.

The optional `opts` object passed to `.verbs` can have the following properties:

* `before`: one or more middleware that runs before the route handler.
* `after`: one or more middleware that runs after the route handler.
- `before`: one or more middleware that runs before the route handler.
- `after`: one or more middleware that runs after the route handler.

**Note**: all builder methods returns a _new builder_ - this means the builder is **immutable**! This allows you to have a common
**Note**: all builder methods returns a _new builder_ - this means the builder is **immutable**! This allows you to have a common
builder setup that you can reuse for multiple controllers.

### Decorators
Expand All @@ -166,10 +169,10 @@ If you have enabled decorator support in your transpiler, you can use the decora
The decorator API exports are:

```js
import {
route,
import {
route,
before,
after,
after,
verbs,
HttpVerbs,

Expand All @@ -182,7 +185,7 @@ import {
CONNECT,
OPTIONS,
PATCH,
ALL
ALL,
} from 'awilix-router-core'
```

Expand Down Expand Up @@ -233,7 +236,7 @@ class Controller {

**Class-level**: not allowed.

**Method-level**: adds HTTP verbs that the route will match.
**Method-level**: adds HTTP verbs that the route will match.

Has no effect if no `route`s are configured.

Expand Down Expand Up @@ -272,12 +275,16 @@ This section is for framework adapter authors. Please see [awilix-koa][awilix-ko

The primary functions needed for this are `getStateAndTarget`, `rollUpState`, and `findControllers`.

> **NOTE**: when referring to "state-target tuple", it means an object containing `state`
> and `target` properties, where `target` is the class/function to build up (using `container.build`)
> **NOTE**: when referring to "state-target tuple", it means an object containing `state`
> and `target` properties, where `target` is the class/function to build up (using `container.build`)
> in order to get an object to call methods on.

```js
import { getStateAndTarget, rollUpState, findControllers } from 'awilix-router-core'
import {
getStateAndTarget,
rollUpState,
findControllers,
} from 'awilix-router-core'
```

### `getStateAndTarget(functionOrClassOrController)`
Expand All @@ -290,13 +297,15 @@ This will return a map where the key is the controller method name and the value

### `findControllers(pattern, globOptions)`

Using `glob`, loads controllers from matched files, with non-applicable files filtered out.
Using `fast-glob`, loads controllers from matched files.

> Note: This uses `require` and so currently is not compatible with ESM.

Returns an array of state-target tuples.

# Author

Jeff Hansen — [@Jeffijoe](https://twitter.com/Jeffijoe)

[http-verbs]: /src/http-verbs.ts
[awilix-koa]: https://github.com/jeffijoe/awilix-koa
[http-verbs]: /src/http-verbs.ts
[awilix-koa]: https://github.com/jeffijoe/awilix-koa