|
1 |
| -import type { ArgumentMetadata, ArgumentsHost, CanActivate, ExceptionFilter, ExecutionContext, NestMiddleware, NestModule, PipeTransform } from '@nestjs/common' |
| 1 | +import type { ArgumentMetadata, ArgumentsHost, CanActivate, ExceptionFilter, ExecutionContext, PipeTransform } from '@nestjs/common' |
2 | 2 | import type { IArgument, IClassWrapper, IPluginContext } from '@unioc/core'
|
3 | 3 | import type { IClass } from '@unioc/shared'
|
4 |
| -import type { IHttpParam, IRestfulConnect, IRestfulScanner } from '@unioc/web' |
5 |
| -import type { IMiddlewareApplyData, MiddlewareType } from '../middleware/middleware-customer' |
| 4 | +import type { IHttpMethod, IHttpParam, IRestfulConnect, IRestfulScanner } from '@unioc/web' |
| 5 | +import type { ExcludeMiddlewareRoute, IncludeMiddlewareRoute } from '../middleware/middleware-customer' |
6 | 6 | import type { NestJSMethodOperator } from './method-operator'
|
7 |
| -import type { NestJSMethodWrapper } from './method-wrapper' |
| 7 | +import { RequestMethod } from '@nestjs/common' |
8 | 8 | import { CONTROLLER_WATERMARK, FILTER_CATCH_EXCEPTIONS } from '@nestjs/common/constants.js'
|
9 |
| -import { isClass } from '@unioc/shared' |
10 |
| -import { RestfulScanner } from '@unioc/web' |
11 |
| -import { MiddlewareCustomerBuilder } from '../middleware/middleware-customer' |
| 9 | +import { HttpMethod, RestfulScanner } from '@unioc/web' |
| 10 | +import { match } from 'path-to-regexp' |
| 11 | +import { MiddlewareResolver } from '../middleware/middleware-resolver' |
12 | 12 | import { NestJSControllerWrapper } from './controller-wrapper'
|
13 | 13 | import { NestJSRestfulHandler } from './restful-handler'
|
14 | 14 |
|
@@ -142,71 +142,68 @@ export class NestJSRestfulScanner extends RestfulScanner implements IRestfulScan
|
142 | 142 | return true
|
143 | 143 | }
|
144 | 144 |
|
145 |
| - private _middlewareCustomerMap: Map<MiddlewareType, IMiddlewareApplyData> = new Map<MiddlewareType, IMiddlewareApplyData>() |
| 145 | + private _middlewareResolver: MiddlewareResolver = new MiddlewareResolver(this, this._modules) |
146 | 146 |
|
147 |
| - async resolveMiddlewares(): Promise<void> { |
148 |
| - for (const moduleWrapper of this._modules) { |
149 |
| - const resolveInstance: NestModule = await moduleWrapper.resolve() |
150 |
| - if (!('configure' in resolveInstance) || typeof resolveInstance.configure !== 'function') |
151 |
| - continue |
152 |
| - |
153 |
| - const middlewareCustomer = new MiddlewareCustomerBuilder(this.getPluginContext()) |
154 |
| - await resolveInstance.configure(middlewareCustomer) |
155 |
| - this._middlewareCustomerMap = middlewareCustomer.merge(this._middlewareCustomerMap) |
156 |
| - } |
| 147 | + getMiddlewareResolver(): MiddlewareResolver { |
| 148 | + return this._middlewareResolver |
157 | 149 | }
|
158 | 150 |
|
159 |
| - async executeMiddlewares(methodWrapper: NestJSMethodWrapper, ctx: IRestfulConnect.WebContext): Promise<void> { |
160 |
| - const fullPaths = methodWrapper.findAll().map(o => o.getFullPath()) |
161 |
| - const classTarget = methodWrapper.getControllerOperator().getControllerWrapper().getClassWrapper().getTarget() |
162 |
| - const matchedMiddlewares: MiddlewareType[] = [] |
163 |
| - |
164 |
| - for (const [middleware, data] of this._middlewareCustomerMap.entries()) { |
165 |
| - for (const route of data.includedRoutes) { |
166 |
| - if (isClass(route)) { |
167 |
| - if (classTarget === route) { |
168 |
| - matchedMiddlewares.push(middleware) |
169 |
| - } |
170 |
| - } |
171 |
| - else if (typeof route === 'string') { |
172 |
| - if (fullPaths.includes(route)) { |
173 |
| - matchedMiddlewares.push(middleware) |
174 |
| - } |
175 |
| - } |
176 |
| - else { |
177 |
| - if (fullPaths.includes(route.path)) { |
178 |
| - matchedMiddlewares.push(middleware) |
179 |
| - } |
180 |
| - } |
181 |
| - } |
| 151 | + override async resolveAll(): Promise<this> { |
| 152 | + await super.resolveAll() |
| 153 | + await this.getMiddlewareResolver().resolveAll() |
| 154 | + return this |
| 155 | + } |
182 | 156 |
|
183 |
| - for (const route of data.excludedRoutes) { |
184 |
| - if (isClass(route)) { |
185 |
| - if (classTarget === route) { |
186 |
| - matchedMiddlewares.splice(matchedMiddlewares.indexOf(middleware), 1) |
187 |
| - } |
188 |
| - } |
189 |
| - else if (typeof route === 'string') { |
190 |
| - if (fullPaths.includes(route)) { |
191 |
| - matchedMiddlewares.splice(matchedMiddlewares.indexOf(middleware), 1) |
192 |
| - } |
193 |
| - } |
194 |
| - else { |
195 |
| - if (fullPaths.includes(route.path)) { |
196 |
| - matchedMiddlewares.splice(matchedMiddlewares.indexOf(middleware), 1) |
197 |
| - } |
198 |
| - } |
199 |
| - } |
| 157 | + /** |
| 158 | + * ### 🔄 Convert the `RequestMethod` to unioc `IHttpMethod`. |
| 159 | + * |
| 160 | + * @param method - The `RequestMethod` to convert. |
| 161 | + * @returns The converted `IHttpMethod`. |
| 162 | + */ |
| 163 | + toHttpMethod(method: RequestMethod): IHttpMethod { |
| 164 | + switch (method) { |
| 165 | + case RequestMethod.GET: |
| 166 | + return HttpMethod.GET |
| 167 | + case RequestMethod.POST: |
| 168 | + return HttpMethod.POST |
| 169 | + case RequestMethod.PUT: |
| 170 | + return HttpMethod.PUT |
| 171 | + case RequestMethod.DELETE: |
| 172 | + return HttpMethod.DELETE |
| 173 | + case RequestMethod.PATCH: |
| 174 | + return HttpMethod.PATCH |
| 175 | + case RequestMethod.OPTIONS: |
| 176 | + return HttpMethod.OPTIONS |
| 177 | + case RequestMethod.HEAD: |
| 178 | + return HttpMethod.HEAD |
| 179 | + case RequestMethod.ALL: |
| 180 | + return HttpMethod.ALL |
| 181 | + default: |
| 182 | + return HttpMethod.GET |
200 | 183 | }
|
| 184 | + } |
201 | 185 |
|
202 |
| - for (const middleware of matchedMiddlewares) { |
203 |
| - if (isClass(middleware)) { |
204 |
| - const middlewareInstance = await this.getPluginContext().createClass<IClass<NestMiddleware>>(middleware).resolve() |
205 |
| - await middlewareInstance.use(ctx.request, ctx.response, ctx.next) |
206 |
| - } |
207 |
| - else { |
208 |
| - await middleware(ctx.request, ctx.response, ctx.next) |
209 |
| - } |
| 186 | + isMatch(url: string, fullPath: string): boolean { |
| 187 | + return match(fullPath)(url) !== false |
| 188 | + } |
| 189 | + |
| 190 | + isMatchRoute(methodOperator: NestJSMethodOperator, url: string, route: IncludeMiddlewareRoute | ExcludeMiddlewareRoute): boolean { |
| 191 | + const methodWrapper = methodOperator.getMethodWrapper() |
| 192 | + const classTarget = methodWrapper |
| 193 | + .getControllerOperator() |
| 194 | + .getControllerWrapper() |
| 195 | + .getClassWrapper() |
| 196 | + .getTarget() |
| 197 | + |
| 198 | + switch (typeof route) { |
| 199 | + case 'string': |
| 200 | + return this.isMatch(url, route) |
| 201 | + case 'object': |
| 202 | + return this.isMatch(url, route.path) && methodOperator.getHttpMethod() === this.toHttpMethod(route.method) |
| 203 | + case 'function': |
| 204 | + return route === classTarget |
| 205 | + default: |
| 206 | + return false |
210 | 207 | }
|
211 | 208 | }
|
212 | 209 |
|
|
0 commit comments