Skip to content

Commit

Permalink
Upgrade to Typescript 5 decorators
Browse files Browse the repository at this point in the history
  • Loading branch information
evert committed Jan 15, 2024
1 parent 3247d11 commit 56dee21
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 176 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Changelog
ESM is the future, so we're dropping CommonJS.
* Now requires Node 18.
* Upgraded to Typescript 5.3.
* Using Typescript 5 decorators, which means experimentalDecorators (the
old-style decorators) are no longer needed.


0.5.0 (2023-02-14)
Expand Down
155 changes: 27 additions & 128 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,18 @@
"@curveball/kernel": "^1"
},
"devDependencies": {
"@curveball/core": "^1.0.0",
"@curveball/kernel": "^1.0.0",
"@types/chai": "^4.2.15",
"@types/mocha": "^10.0.1",
"@types/node": "^18.19.6",
"@types/sinon": "^17.0.3",
"@types/ws": "^7.4.0",
"@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "^6.18.1",
"chai": "^5.0.0",
"eslint": "^8.23.0",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
"sinon": "^17.0.1",
"ts-node": "^10.9.1",
"typescript": "^5.3.3"
},
Expand Down
17 changes: 9 additions & 8 deletions src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ export default class Controller {
routeTable!: RouteTable;

constructor() {

this.autoAnnotateHttpMethods();
this.createRouteTable();

}

/**
Expand All @@ -38,7 +35,7 @@ export default class Controller {
/**
* Handle Websocket requests
*/
webSocket(ctx: WsContext): void | Promise<void> {
webSocket(_ctx: WsContext): void | Promise<void> {

throw new BadRequest('Websocket connections are not supported at this endpoint');

Expand All @@ -65,6 +62,9 @@ export default class Controller {
*/
dispatch(ctx: Context): Promise<void> | void {

if (!this.routeTable) {
this.rebuildRouteTable();
}
const method = ctx.request.method;
if (!http.METHODS.includes(method)) {
throw new NotImplemented(method + ' is not implemented');
Expand Down Expand Up @@ -130,10 +130,10 @@ export default class Controller {
}

/**
* This method uses the information from annotations to create
* routes
* This method uses the information from annotations and class methods to
* create an optimized route table.
*/
private createRouteTable(): void {
private rebuildRouteTable(): void {

this.routeTable = new Map();
for (const [controllerMethod, annotations] of this.annotations) {
Expand All @@ -153,7 +153,8 @@ export default class Controller {
}

if (method === null) {
throw new Error('Controller method ' + controllerMethod + ' was annotated, but it needs a @method annotation to actually do anything');
console.error(`[ERROR] Controller method "${controllerMethod}" was annotated, but it needs a @method annotation to actually do anything`);
continue;
}

if (!this.routeTable.has(method)) {
Expand Down
30 changes: 18 additions & 12 deletions src/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,24 @@ export function accept(mimeType: string) {
*/
export function controllerDecorator(annotationName: string, ...args: any[]) {

return (target: Controller, propertyKey: string) => {

if (!target.annotations) {
target.annotations = new Map();
}

if (!target.annotations.has(propertyKey)) {
target.annotations.set(propertyKey, []);
}
target.annotations.get(propertyKey)!.push({
name: annotationName,
args: args
return function actualDecorator(_originalMethod: any, context: ClassMethodDecoratorContext<Controller>) {

context.addInitializer(function() {

const methodName = String(context.name);

if (!this.annotations) {
this.annotations = new Map();
}

if (!this.annotations.has(methodName)) {
this.annotations.set(methodName, []);
}
this.annotations.get(methodName)!.push({
name: annotationName,
args: args
});

});

};
Expand Down
10 changes: 1 addition & 9 deletions test/decorated-controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Application } from '@curveball/kernel';
import { expect } from 'chai';
import FancyTestController from './fancy-test-controller.js';
import BrokenTestController from './test-controller-broken.js';

describe('Controller Decorators', () => {

Expand All @@ -21,7 +20,7 @@ describe('Controller Decorators', () => {
app.use(new FancyTestController());
const response = await app.subRequest('OPTIONS', '/');
expect(response.status).to.equal(200);
expect(response.headers.get('Allow')).to.equal('GET, POST, PUT, REPORT, OPTIONS');
expect(response.headers.get('Allow')).to.equal('OPTIONS, PUT, REPORT, GET, POST');

});

Expand Down Expand Up @@ -81,12 +80,5 @@ describe('Controller Decorators', () => {
expect(response.status).to.equal(406);

});
it('should throw an error when instantiating a controller with an unreacheable method', async() => {

expect(() => {
new BrokenTestController();
}).to.throw(Error);

});

});
Loading

0 comments on commit 56dee21

Please sign in to comment.