Skip to content

Commit 72aadd8

Browse files
feat(core): update BootApplication and core services
Co-authored-by: Junie <junie@jetbrains.com>
1 parent 5d04bea commit 72aadd8

17 files changed

Lines changed: 160 additions & 84 deletions

src/controller/BootApplication.ts

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { isEmpty, isString, normalize } from "apps-script-utils";
22
import {
33
ApplicationConfig,
4+
ApplicationProperties,
45
AppsScriptMenuProxy,
56
HttpHeaders,
67
HttpRequest,
@@ -18,14 +19,54 @@ import { isControllerAdvice } from "../shared/utils";
1819
* Main application class for bootstrapping and handling Google Apps Script events.
1920
*/
2021
export class BootApplication {
22+
/**
23+
* Application controller map, mapping their constructors to instances.
24+
*/
2125
private readonly _controllers: Map<Newable, unknown> = new Map<Newable, unknown>();
26+
27+
/**
28+
* Application provider map used for dependency injection.
29+
*/
2230
private readonly _providers: Map<InjectionToken, unknown> = new Map<InjectionToken, unknown>();
23-
private readonly _config: Record<string, any>;
31+
32+
/**
33+
* Application configuration properties.
34+
*/
35+
private readonly _config: ApplicationProperties;
36+
37+
/**
38+
* Global prefix for all API routes.
39+
*/
40+
private readonly _apiPrefix: string | undefined;
41+
42+
/**
43+
* List of tokens for controller advices (e.g., exception handlers).
44+
*/
2445
private readonly _advices: InjectionToken[] = [];
46+
47+
/**
48+
* Resolver for resolving dependencies and obtaining class instances.
49+
*/
2550
private readonly _resolver: Resolver;
51+
52+
/**
53+
* Router for managing request routing.
54+
*/
2655
private readonly _router: Router;
56+
57+
/**
58+
* Factory for creating HTTP request objects from Google Apps Script events.
59+
*/
2760
private readonly _requestFactory: RequestFactory;
61+
62+
/**
63+
* HTTP response builder for sending responses to the client.
64+
*/
2865
private readonly _responseBuilder: ResponseBuilder;
66+
67+
/**
68+
* Event dispatcher for handling and distributing internal application events.
69+
*/
2970
private readonly _eventDispatcher: EventDispatcher;
3071

3172
/**
@@ -34,31 +75,31 @@ export class BootApplication {
3475
* @param {ApplicationConfig} config - The application configuration.
3576
*/
3677
constructor(config?: ApplicationConfig) {
37-
this._config = config?.config || {};
78+
this._config = config?.config ?? {};
3879

3980
(config?.controllers || []).forEach(
4081
(c: Newable): Map<Newable, unknown> => this._controllers.set(c, null)
4182
);
4283

43-
(config?.providers || []).forEach((p: Provider): void => {
84+
(config?.providers || []).forEach((provider: Provider): void => {
4485
let token: InjectionToken;
4586

46-
if ("provide" in p) {
47-
token = p.provide;
48-
if ("useValue" in p) {
49-
this._providers.set(p.provide, p.useValue);
50-
} else if ("useClass" in p) {
51-
this._providers.set(p.provide, null); // Will be resolved later
52-
} else if ("useFactory" in p) {
87+
if ("provide" in provider) {
88+
token = provider.provide;
89+
if ("useValue" in provider) {
90+
this._providers.set(provider.provide, provider.useValue);
91+
} else if ("useClass" in provider) {
92+
this._providers.set(provider.provide, null); // Will be resolved later
93+
} else if ("useFactory" in provider) {
5394
// TODO: implement factory providers
54-
this._providers.set(p.provide, null);
55-
} else if ("useExisting" in p) {
95+
this._providers.set(provider.provide, null);
96+
} else if ("useExisting" in provider) {
5697
// TODO: implement existing providers
57-
this._providers.set(p.provide, null);
98+
this._providers.set(provider.provide, null);
5899
}
59100
} else {
60-
token = p;
61-
this._providers.set(p, null);
101+
token = provider;
102+
this._providers.set(provider, null);
62103
}
63104

64105
if (isControllerAdvice(token)) {
@@ -70,18 +111,20 @@ export class BootApplication {
70111

71112
this._requestFactory = new RequestFactory();
72113

73-
const apiPrefix: string | null =
74-
isString(config?.apiPrefix) && !isEmpty(config.apiPrefix)
75-
? normalize(`/${config.apiPrefix}`)
76-
: null;
114+
const apiPrefix: string =
115+
isString(config?.config?.apiPrefix) && !isEmpty(config.config.apiPrefix)
116+
? normalize(`/${config.config.apiPrefix}/`)
117+
: "/api";
118+
119+
this._apiPrefix = apiPrefix;
77120

78121
this._responseBuilder = new ResponseBuilder(apiPrefix);
79122

80123
const explorer: RouterExplorer = new RouterExplorer();
81124

82-
const routes: RouteMetadata[] = explorer.explore(this._controllers, apiPrefix);
125+
const routes: RouteMetadata[] = explorer.explore(this._controllers);
83126

84-
this._router = new Router(this._resolver, routes, this._advices, this._config);
127+
this._router = new Router(this._resolver, routes, this._advices, this._config, apiPrefix);
85128

86129
this._eventDispatcher = new EventDispatcher(this._resolver, this._controllers);
87130
}
@@ -95,7 +138,7 @@ export class BootApplication {
95138
const handler: () => AppsScriptMenuProxy = (): AppsScriptMenuProxy => proxy;
96139

97140
const proxy: AppsScriptMenuProxy = new Proxy(handler, {
98-
get: (target, prop, receiver) => {
141+
get: (target, prop, receiver: any): any => {
99142
if (!isString(prop)) {
100143
return Reflect.get(target, prop, receiver);
101144
}
@@ -108,11 +151,11 @@ export class BootApplication {
108151
return Reflect.get(target, prop, receiver);
109152
}
110153

111-
return (event: GoogleAppsScript.Events.AppsScriptEvent) => {
154+
return (event: GoogleAppsScript.Events.AppsScriptEvent): void => {
112155
return this._eventDispatcher.dispatchByName(prop, event);
113156
};
114157
},
115-
apply: (target, thisArg, argArray) => {
158+
apply: (target, thisArg: any, argArray): any => {
116159
return Reflect.apply(target, thisArg, argArray);
117160
}
118161
}) as unknown as AppsScriptMenuProxy;

src/controller/decorators/Controller.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import "reflect-metadata";
2-
import { CONTROLLER_OPTIONS_METADATA, CONTROLLER_TYPE_METADATA, CONTROLLER_WATERMARK } from "../../domain/constants";
2+
import {
3+
CONTROLLER_OPTIONS_METADATA,
4+
CONTROLLER_TYPE_METADATA,
5+
CONTROLLER_WATERMARK
6+
} from "../../domain/constants";
37

48
/**
59
* Interface representing controller options.

src/controller/decorators/ResponseStatus.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { RESPONSE_STATUS_METADATA } from "../../domain/constants";
2+
import { HttpStatus } from "src/domain";
23

34
/**
45
* Decorator that sets the HTTP status code for the response.
@@ -8,16 +9,16 @@ import { RESPONSE_STATUS_METADATA } from "../../domain/constants";
89
*
910
* @example
1011
* ```TypeScript
11-
* import { Post, ResponseStatus } from "bootgs";
12+
* import { Post, ResponseStatus, HttpStatus } from "bootgs";
1213
*
1314
* @Post("/users")
14-
* @ResponseStatus(201)
15+
* @ResponseStatus(HttpStatus.CREATED)
1516
* create() {
1617
* return { created: true };
1718
* }
1819
* ```
1920
*/
20-
export function ResponseStatus(status: number): MethodDecorator {
21+
export function ResponseStatus(status: HttpStatus): MethodDecorator {
2122
return (
2223
_target: object,
2324
_propertyKey: string | symbol,

src/controller/decorators/params/Param.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import { createParamDecorator } from "../../../repository";
99
*
1010
* @example
1111
* ```TypeScript
12-
* import { Get, Param, ParseIntPipe, RestController } from "bootgs";
12+
* import { Get, Param, ParseNumberPipe, RestController } from "bootgs";
1313
*
1414
* @RestController("/users")
1515
* class UsersController {
1616
* @Get("/{id}")
17-
* getUser(@Param("id", ParseIntPipe) id: number) {
17+
* getUser(@Param("id", ParseNumberPipe) id: number) {
1818
* return { id };
1919
* }
2020
* }

src/controller/decorators/params/PathVariable.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import { Param } from "../../../controller/decorators/params";
1010
*
1111
* @example
1212
* ```TypeScript
13-
* import { Get, Param, ParseIntPipe, RestController } from "bootgs";
13+
* import { Get, Param, ParseNumberPipe, RestController } from "bootgs";
1414
*
1515
* @RestController("/users")
1616
* class UsersController {
1717
* @Get("/{id}")
18-
* getUser(@Param("id", ParseIntPipe) id: number) {
18+
* getUser(@Param("id", ParseNumberPipe) id: number) {
1919
* return { id };
2020
* }
2121
* }

src/controller/decorators/params/Query.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import { createParamDecorator } from "../../../repository";
99
*
1010
* @example
1111
* ```TypeScript
12-
* import { Get, Query, ParseIntPipe, RestController } from "bootgs";
12+
* import { Get, Query, ParseNumberPipe, RestController } from "bootgs";
1313
*
1414
* @RestController("/users")
1515
* class UsersController {
1616
* @Get()
17-
* findAll(@Query("page", ParseIntPipe) page: number) {
17+
* findAll(@Query("page", ParseNumberPipe) page: number) {
1818
* return { page };
1919
* }
2020
* }

src/controller/decorators/params/RequestParam.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import { Query } from "../../../controller/decorators/params";
1010
*
1111
* @example
1212
* ```TypeScript
13-
* import { Get, RequestParam, ParseIntPipe, RestController } from "bootgs";
13+
* import { Get, RequestParam, ParseNumberPipe, RestController } from "bootgs";
1414
*
1515
* @RestController("/users")
1616
* class UsersController {
1717
* @Get()
18-
* findAll(@RequestParam("page", ParseIntPipe) page: number) {
18+
* findAll(@RequestParam("page", ParseNumberPipe) page: number) {
1919
* return { page };
2020
* }
2121
* }

src/controller/decorators/routing/RequestMapping.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { CONTROLLER_OPTIONS_METADATA, METHOD_METADATA, PATH_METADATA } from "../../../domain/constants";
1+
import {
2+
CONTROLLER_OPTIONS_METADATA,
3+
METHOD_METADATA,
4+
PATH_METADATA
5+
} from "../../../domain/constants";
26
import { RequestMethod } from "../../../domain/enums";
37

48
/**

src/exceptions/AppException.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { HttpStatus } from "../domain";
2+
13
/**
24
* Base exception class for all exceptions in the application.
35
*
@@ -7,7 +9,7 @@
79
export class AppException extends Error {
810
constructor(
911
public readonly message: string,
10-
public readonly status: number = 500
12+
public readonly status: number = HttpStatus.INTERNAL_SERVER_ERROR
1113
) {
1214
super(message);
1315

src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import "reflect-metadata";
22
import { BootApplication, BootApplicationFactory } from "./controller";
33

44
export * from "./controller";
5+
export * from "./service";
6+
export * from "./exceptions";
7+
export * from "./domain";
58
export * from "./shared/utils";
6-
export * from "./domain/types";
7-
export * from "./domain/enums";
89

910
export { BootApplication as App };
11+
1012
export const createApp = BootApplicationFactory.create;

0 commit comments

Comments
 (0)