11import { isEmpty , isString , normalize } from "apps-script-utils" ;
22import {
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 */
2021export 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 ;
0 commit comments