@valkyrjaio/sindri 26.5.1 → 26.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/dist/bin/sindri.cjs +574 -268
- package/package.json +2 -2
- package/src/Sindri/Ast/Abstract/AstReader.ts +187 -5
- package/src/Sindri/Ast/Abstract/RouteAttributeReader.ts +2 -3
- package/src/Sindri/Ast/CliRouteAttributeReader.ts +102 -17
- package/src/Sindri/Ast/CliRouteParameterReader.ts +44 -26
- package/src/Sindri/Ast/ComponentProviderReader.ts +2 -3
- package/src/Sindri/Ast/ConfigReader.ts +2 -3
- package/src/Sindri/Ast/ConfigSourceReader.ts +2 -3
- package/src/Sindri/Ast/Contract/CliRouteAttributeReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/CliRouteParameterReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/ComponentProviderReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/ConfigReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/ConfigSourceReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/HttpRouteAttributeReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/HttpRouteMiddlewareReaderContract.ts +5 -10
- package/src/Sindri/Ast/Contract/HttpRouteParameterReaderContract.ts +3 -7
- package/src/Sindri/Ast/Contract/ListenerAttributeReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/ListenerProviderReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/RouteProviderReaderContract.ts +2 -3
- package/src/Sindri/Ast/Contract/ServiceProviderReaderContract.ts +2 -3
- package/src/Sindri/Ast/Data/CliArgumentParameterData.ts +2 -3
- package/src/Sindri/Ast/Data/CliOptionParameterData.ts +2 -3
- package/src/Sindri/Ast/Data/CliRouteData.ts +2 -3
- package/src/Sindri/Ast/Data/ConfigData.ts +2 -3
- package/src/Sindri/Ast/Data/ConfigImport.ts +2 -3
- package/src/Sindri/Ast/Data/Contract/CliArgumentParameterDataContract.ts +2 -3
- package/src/Sindri/Ast/Data/Contract/CliOptionParameterDataContract.ts +2 -3
- package/src/Sindri/Ast/Data/Contract/CliRouteDataContract.ts +2 -3
- package/src/Sindri/Ast/Data/Contract/ConfigDataContract.ts +2 -3
- package/src/Sindri/Ast/Data/Contract/HandlerDataContract.ts +2 -3
- package/src/Sindri/Ast/Data/Contract/HttpParameterDataContract.ts +4 -3
- package/src/Sindri/Ast/Data/Contract/HttpRouteDataContract.ts +2 -3
- package/src/Sindri/Ast/Data/Contract/ListenerDataContract.ts +2 -3
- package/src/Sindri/Ast/Data/HandlerData.ts +2 -3
- package/src/Sindri/Ast/Data/HttpParameterData.ts +3 -3
- package/src/Sindri/Ast/Data/HttpRouteData.ts +2 -3
- package/src/Sindri/Ast/Data/ListenerData.ts +2 -3
- package/src/Sindri/Ast/Data/Result/CliRouteAttributeResult.ts +7 -4
- package/src/Sindri/Ast/Data/Result/ComponentProviderResult.ts +2 -3
- package/src/Sindri/Ast/Data/Result/ConfigResult.ts +2 -3
- package/src/Sindri/Ast/Data/Result/ConfigSourceResult.ts +2 -3
- package/src/Sindri/Ast/Data/Result/HttpRouteAttributeResult.ts +4 -3
- package/src/Sindri/Ast/Data/Result/ListenerAttributeResult.ts +2 -3
- package/src/Sindri/Ast/Data/Result/ListenerProviderResult.ts +2 -3
- package/src/Sindri/Ast/Data/Result/RouteProviderResult.ts +2 -3
- package/src/Sindri/Ast/Data/Result/ServiceProviderResult.ts +2 -3
- package/src/Sindri/Ast/HttpRouteAttributeReader.ts +180 -51
- package/src/Sindri/Ast/HttpRouteMiddlewareReader.ts +38 -18
- package/src/Sindri/Ast/HttpRouteParameterReader.ts +50 -109
- package/src/Sindri/Ast/ListenerAttributeReader.ts +2 -3
- package/src/Sindri/Ast/ListenerProviderReader.ts +2 -3
- package/src/Sindri/Ast/RouteProviderReader.ts +2 -3
- package/src/Sindri/Ast/ServiceProviderReader.ts +2 -3
- package/src/Sindri/Ast/Throwable/Contract/AstThrowable.ts +2 -3
- package/src/Sindri/Ast/Throwable/Exception/Abstract/AstInvalidArgumentException.ts +2 -3
- package/src/Sindri/Ast/Throwable/Exception/Abstract/AstRuntimeException.ts +2 -3
- package/src/Sindri/Ast/Throwable/Exception/AstFileReadException.ts +2 -3
- package/src/Sindri/Cli/Command/GenerateCachedConfigCommand.ts +2 -3
- package/src/Sindri/Cli/Command/GenerateDataFromConfigCommand.ts +2 -3
- package/src/Sindri/Constant/CommandName.ts +2 -3
- package/src/Sindri/Constant/SindriInfo.ts +4 -5
- package/src/Sindri/Constant/SindriServiceId.ts +2 -3
- package/src/Sindri/Generate/Abstract/GenerateCachedConfigFromAst.ts +2 -3
- package/src/Sindri/Generate/Abstract/GenerateDataFromAst.ts +39 -27
- package/src/Sindri/Generate/Abstract/GenerateFromAst.ts +2 -3
- package/src/Sindri/Generator/Abstract/AstFileGenerator.ts +2 -3
- package/src/Sindri/Generator/Abstract/FileGenerator.ts +2 -3
- package/src/Sindri/Generator/Ast/Cli/AstCliDataFileGenerator.ts +21 -6
- package/src/Sindri/Generator/Ast/Config/AstCachedConfigFileGenerator.ts +2 -3
- package/src/Sindri/Generator/Ast/Container/AstContainerDataFileGenerator.ts +2 -3
- package/src/Sindri/Generator/Ast/Event/AstEventDataFileGenerator.ts +2 -3
- package/src/Sindri/Generator/Ast/Http/AstHttpDataFileGenerator.ts +83 -45
- package/src/Sindri/Generator/Cli/Contract/CliDataFileGeneratorContract.ts +10 -3
- package/src/Sindri/Generator/Config/Contract/CachedConfigFileGeneratorContract.ts +2 -3
- package/src/Sindri/Generator/Container/Contract/ContainerDataFileGeneratorContract.ts +2 -3
- package/src/Sindri/Generator/Contract/FileGeneratorContract.ts +2 -3
- package/src/Sindri/Generator/Enum/GenerateStatus.ts +2 -3
- package/src/Sindri/Generator/Event/Contract/EventDataFileGeneratorContract.ts +2 -3
- package/src/Sindri/Generator/Http/Contract/HttpDataFileGeneratorContract.ts +11 -3
- package/src/Sindri/Generator/Throwable/Contract/GeneratorThrowable.ts +2 -3
- package/src/Sindri/Generator/Throwable/Exception/Abstract/GeneratorInvalidArgumentException.ts +2 -3
- package/src/Sindri/Generator/Throwable/Exception/Abstract/GeneratorRuntimeException.ts +2 -3
- package/src/Sindri/Generator/Throwable/Exception/GeneratorUnreachableException.ts +2 -3
- package/src/Sindri/Provider/SindriAstServiceProvider.ts +2 -3
- package/src/Sindri/Provider/SindriCliRouteProvider.ts +2 -3
- package/src/Sindri/Provider/SindriCommandServiceProvider.ts +2 -3
- package/src/Sindri/Provider/SindriComponentProvider.ts +2 -3
- package/src/Sindri/Throwable/Contract/SindriThrowable.ts +2 -3
- package/src/Sindri/Throwable/Exception/Abstract/SindriInvalidArgumentException.ts +2 -3
- package/src/Sindri/Throwable/Exception/Abstract/SindriRuntimeException.ts +2 -3
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* This file is part of the Sindri package.
|
|
3
3
|
*
|
|
4
|
-
* (c) Melech Mizrachi
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* file that was distributed with this source code.
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
import { ts } from 'ts-morph';
|
|
@@ -15,18 +14,22 @@ import { HttpRouteAttributeResult } from './Data/Result/HttpRouteAttributeResult
|
|
|
15
14
|
import { HttpRouteMiddlewareReader } from './HttpRouteMiddlewareReader.ts';
|
|
16
15
|
import { HttpRouteParameterReader } from './HttpRouteParameterReader.ts';
|
|
17
16
|
|
|
18
|
-
import type { ClassDeclaration, Decorator, MethodDeclaration
|
|
17
|
+
import type { ClassDeclaration, Decorator, MethodDeclaration } from 'ts-morph';
|
|
19
18
|
|
|
20
19
|
import type { HttpRouteAttributeReaderContract } from './Contract/HttpRouteAttributeReaderContract.ts';
|
|
21
20
|
import type { HttpRouteMiddlewareReaderContract } from './Contract/HttpRouteMiddlewareReaderContract.ts';
|
|
22
21
|
import type { HttpRouteParameterReaderContract } from './Contract/HttpRouteParameterReaderContract.ts';
|
|
22
|
+
import type { HandlerData } from './Data/HandlerData.ts';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Scans an HTTP controller class file for @Route / @DynamicRoute and related
|
|
26
26
|
* sub-decorators and returns TypeScript compiler API Expr nodes ready for the data cache generator.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* The shipped decorators accept a single options object
|
|
29
|
+
* (`@Route({ path, name, ... })`), so this reader parses object-literal
|
|
30
|
+
* properties rather than positional arguments. It mirrors the logic of the
|
|
31
|
+
* framework's runtime AttributeRouteCollector but operates entirely on AST
|
|
32
|
+
* without executing any TypeScript code.
|
|
30
33
|
*/
|
|
31
34
|
export class HttpRouteAttributeReader extends RouteAttributeReader implements HttpRouteAttributeReaderContract {
|
|
32
35
|
constructor(
|
|
@@ -112,7 +115,7 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
112
115
|
|
|
113
116
|
for (const method of classDecl.getMethods()) {
|
|
114
117
|
for (const decorator of this.findDecoratorsOnNode(method, 'Route', useMap, currentFilePath)) {
|
|
115
|
-
|
|
118
|
+
this.collectRoute(
|
|
116
119
|
decorator,
|
|
117
120
|
method,
|
|
118
121
|
useMap,
|
|
@@ -121,16 +124,13 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
121
124
|
classPathPrefix,
|
|
122
125
|
classNamePrefix,
|
|
123
126
|
false,
|
|
127
|
+
routes,
|
|
128
|
+
routeData,
|
|
124
129
|
);
|
|
125
|
-
|
|
126
|
-
if (data !== null) {
|
|
127
|
-
routes[data.name] = this.buildRouteExpr(data);
|
|
128
|
-
routeData[data.name] = data;
|
|
129
|
-
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
for (const decorator of this.findDecoratorsOnNode(method, 'DynamicRoute', useMap, currentFilePath)) {
|
|
133
|
-
|
|
133
|
+
this.collectRoute(
|
|
134
134
|
decorator,
|
|
135
135
|
method,
|
|
136
136
|
useMap,
|
|
@@ -139,16 +139,44 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
139
139
|
classPathPrefix,
|
|
140
140
|
classNamePrefix,
|
|
141
141
|
true,
|
|
142
|
+
routes,
|
|
143
|
+
routeData,
|
|
142
144
|
);
|
|
143
|
-
|
|
144
|
-
if (data !== null) {
|
|
145
|
-
routes[data.name] = this.buildRouteExpr(data);
|
|
146
|
-
routeData[data.name] = data;
|
|
147
|
-
}
|
|
148
145
|
}
|
|
149
146
|
}
|
|
150
147
|
|
|
151
|
-
|
|
148
|
+
const importMap = this.buildImportMap(routeData, useMap, currentFilePath, currentClass);
|
|
149
|
+
|
|
150
|
+
return new HttpRouteAttributeResult(routes, routeData, importMap);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
protected collectRoute(
|
|
154
|
+
decorator: Decorator,
|
|
155
|
+
method: MethodDeclaration,
|
|
156
|
+
useMap: Record<string, string>,
|
|
157
|
+
currentFilePath: string,
|
|
158
|
+
currentClass: string,
|
|
159
|
+
classPathPrefix: string,
|
|
160
|
+
classNamePrefix: string,
|
|
161
|
+
isDynamic: boolean,
|
|
162
|
+
routes: Record<string, ts.Expression>,
|
|
163
|
+
routeData: Record<string, HttpRouteData>,
|
|
164
|
+
): void {
|
|
165
|
+
const data = this.buildRouteData(
|
|
166
|
+
decorator,
|
|
167
|
+
method,
|
|
168
|
+
useMap,
|
|
169
|
+
currentFilePath,
|
|
170
|
+
currentClass,
|
|
171
|
+
classPathPrefix,
|
|
172
|
+
classNamePrefix,
|
|
173
|
+
isDynamic,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (data !== null) {
|
|
177
|
+
routes[data.name] = this.buildRouteExpr(data);
|
|
178
|
+
routeData[data.name] = data;
|
|
179
|
+
}
|
|
152
180
|
}
|
|
153
181
|
|
|
154
182
|
protected buildRouteData(
|
|
@@ -161,8 +189,14 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
161
189
|
classNamePrefix: string,
|
|
162
190
|
isDynamic: boolean,
|
|
163
191
|
): HttpRouteData | null {
|
|
164
|
-
const
|
|
165
|
-
|
|
192
|
+
const obj = this.getDecoratorObjectArg(decorator);
|
|
193
|
+
|
|
194
|
+
if (obj === undefined) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const path = this.getObjectStringProp(obj, 'path', useMap, currentFilePath, currentClass);
|
|
199
|
+
const name = this.getObjectStringProp(obj, 'name', useMap, currentFilePath, currentClass);
|
|
166
200
|
|
|
167
201
|
if (path === '' || name === '') {
|
|
168
202
|
return null;
|
|
@@ -173,10 +207,8 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
173
207
|
|
|
174
208
|
const resolvedIsDynamic = isDynamic || updatedPath.includes('{');
|
|
175
209
|
|
|
176
|
-
const decoratorArgs = decorator.getArguments().map((a: Node) => a.compilerNode as ts.Expression);
|
|
177
|
-
|
|
178
210
|
const requestMethods = this.middlewareReader.updateRequestMethods(
|
|
179
|
-
this.middlewareReader.
|
|
211
|
+
this.middlewareReader.extractObjectRequestMethods(obj, useMap, currentFilePath, currentClass),
|
|
180
212
|
method,
|
|
181
213
|
useMap,
|
|
182
214
|
currentFilePath,
|
|
@@ -194,32 +226,84 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
194
226
|
useMap,
|
|
195
227
|
currentFilePath,
|
|
196
228
|
currentClass,
|
|
197
|
-
this.
|
|
198
|
-
this.extractClassListArgFromDecorator(decorator, 6, useMap, currentFilePath, currentClass),
|
|
199
|
-
this.extractClassListArgFromDecorator(decorator, 7, useMap, currentFilePath, currentClass),
|
|
200
|
-
this.extractClassListArgFromDecorator(decorator, 8, useMap, currentFilePath, currentClass),
|
|
201
|
-
this.extractClassListArgFromDecorator(decorator, 9, useMap, currentFilePath, currentClass),
|
|
229
|
+
this.getObjectClassListProp(obj, 'middleware', useMap, currentFilePath, currentClass),
|
|
202
230
|
);
|
|
203
231
|
|
|
204
232
|
return new HttpRouteData(
|
|
205
233
|
updatedPath,
|
|
206
234
|
updatedName,
|
|
207
|
-
this.
|
|
235
|
+
this.resolveHandler(obj, method, useMap, currentFilePath, currentClass),
|
|
208
236
|
requestMethods,
|
|
209
237
|
routeMatchedMiddleware,
|
|
210
238
|
routeDispatchedMiddleware,
|
|
211
239
|
throwableCaughtMiddleware,
|
|
212
240
|
sendingResponseMiddleware,
|
|
213
241
|
responseSentMiddleware,
|
|
214
|
-
this.
|
|
215
|
-
this.
|
|
242
|
+
this.resolveRequestStruct(obj, method, useMap, currentFilePath, currentClass),
|
|
243
|
+
this.resolveResponseStruct(obj, method, useMap, currentFilePath, currentClass),
|
|
216
244
|
resolvedIsDynamic,
|
|
217
|
-
resolvedIsDynamic
|
|
218
|
-
? this.updateParameters(decoratorArgs, method, useMap, currentFilePath, currentClass)
|
|
219
|
-
: [],
|
|
245
|
+
resolvedIsDynamic ? this.parameterReader.updateParameters(obj, useMap, currentFilePath, currentClass) : [],
|
|
220
246
|
);
|
|
221
247
|
}
|
|
222
248
|
|
|
249
|
+
protected resolveHandler(
|
|
250
|
+
obj: ts.ObjectLiteralExpression,
|
|
251
|
+
method: MethodDeclaration,
|
|
252
|
+
useMap: Record<string, string>,
|
|
253
|
+
currentFilePath: string,
|
|
254
|
+
currentClass: string,
|
|
255
|
+
): HandlerData {
|
|
256
|
+
const fromObj = this.getObjectHandlerProp(obj, 'handler', useMap, currentFilePath, currentClass);
|
|
257
|
+
|
|
258
|
+
if (fromObj !== undefined) {
|
|
259
|
+
return fromObj;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return this.updateHandler(method, useMap, currentFilePath, currentClass);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
protected resolveRequestStruct(
|
|
266
|
+
obj: ts.ObjectLiteralExpression,
|
|
267
|
+
method: MethodDeclaration,
|
|
268
|
+
useMap: Record<string, string>,
|
|
269
|
+
currentFilePath: string,
|
|
270
|
+
currentClass: string,
|
|
271
|
+
): string | null {
|
|
272
|
+
const value = this.extractExprValue(
|
|
273
|
+
this.getObjectProp(obj, 'requestStruct'),
|
|
274
|
+
useMap,
|
|
275
|
+
currentFilePath,
|
|
276
|
+
currentClass,
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
if (typeof value === 'string' && value !== '') {
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return this.middlewareReader.updateRequestStruct(method, useMap, currentFilePath, currentClass);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
protected resolveResponseStruct(
|
|
287
|
+
obj: ts.ObjectLiteralExpression,
|
|
288
|
+
method: MethodDeclaration,
|
|
289
|
+
useMap: Record<string, string>,
|
|
290
|
+
currentFilePath: string,
|
|
291
|
+
currentClass: string,
|
|
292
|
+
): string | null {
|
|
293
|
+
const value = this.extractExprValue(
|
|
294
|
+
this.getObjectProp(obj, 'responseStruct'),
|
|
295
|
+
useMap,
|
|
296
|
+
currentFilePath,
|
|
297
|
+
currentClass,
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
if (typeof value === 'string' && value !== '') {
|
|
301
|
+
return value;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return this.middlewareReader.updateResponseStruct(method, useMap, currentFilePath, currentClass);
|
|
305
|
+
}
|
|
306
|
+
|
|
223
307
|
protected updatePath(
|
|
224
308
|
path: string,
|
|
225
309
|
classPathPrefix: string,
|
|
@@ -276,23 +360,27 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
276
360
|
return name;
|
|
277
361
|
}
|
|
278
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Emit `new DynamicRoute(path, name, regex, parameters, handler,
|
|
365
|
+
* requestMethods, ...5 middleware, requestStruct, responseStruct)` or
|
|
366
|
+
* `new Route(path, name, handler, requestMethods, ...5 middleware,
|
|
367
|
+
* requestStruct, responseStruct)`, matching the framework constructor order.
|
|
368
|
+
*
|
|
369
|
+
* For dynamic routes the regex slot is emitted as an empty-string
|
|
370
|
+
* placeholder; the generator computes and injects the real regex (it owns
|
|
371
|
+
* the routing `Processor`), and the parameters array is always emitted (`[]`
|
|
372
|
+
* when empty).
|
|
373
|
+
*/
|
|
279
374
|
protected buildRouteExpr(data: HttpRouteData): ts.Expression {
|
|
280
375
|
const args: ts.Expression[] = [this.buildEnumCaseExpr(data.path), this.buildEnumCaseExpr(data.name)];
|
|
281
376
|
|
|
282
|
-
if (data.isDynamic
|
|
377
|
+
if (data.isDynamic) {
|
|
378
|
+
args.push(this.buildStringExpr(''));
|
|
283
379
|
args.push(this.parameterReader.buildParameterListExpr([...data.parameters]));
|
|
284
380
|
}
|
|
285
381
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
} else {
|
|
289
|
-
args.push(this.buildNullExpr());
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (data.requestMethods.length > 0) {
|
|
293
|
-
args.push(this.buildEnumCaseArrayExpr(data.requestMethods));
|
|
294
|
-
}
|
|
295
|
-
|
|
382
|
+
args.push(data.handler !== null ? this.buildHandlerExpr(data.handler) : this.buildNullExpr());
|
|
383
|
+
args.push(this.buildEnumCaseArrayExpr(data.requestMethods));
|
|
296
384
|
args.push(...this.middlewareReader.buildRouteMiddlewareArgs(data));
|
|
297
385
|
args.push(...this.middlewareReader.buildRouteStructArgs(data));
|
|
298
386
|
|
|
@@ -303,13 +391,54 @@ export class HttpRouteAttributeReader extends RouteAttributeReader implements Ht
|
|
|
303
391
|
return this.buildNewExpr(targetClass, args);
|
|
304
392
|
}
|
|
305
393
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Build the class-name → absolute-file-path map for every handler and
|
|
396
|
+
* middleware class the generated data cache references, so the generator can
|
|
397
|
+
* emit the matching import statements.
|
|
398
|
+
*/
|
|
399
|
+
protected buildImportMap(
|
|
400
|
+
routeData: Record<string, HttpRouteData>,
|
|
309
401
|
useMap: Record<string, string>,
|
|
310
402
|
currentFilePath: string,
|
|
311
403
|
currentClass: string,
|
|
312
|
-
):
|
|
313
|
-
|
|
404
|
+
): Record<string, string> {
|
|
405
|
+
const importMap: Record<string, string> = {};
|
|
406
|
+
|
|
407
|
+
for (const data of Object.values(routeData)) {
|
|
408
|
+
if (data.handler !== null) {
|
|
409
|
+
this.addClassImport(importMap, data.handler.class, useMap, currentFilePath, currentClass);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
for (const middleware of [
|
|
413
|
+
...data.routeMatchedMiddleware,
|
|
414
|
+
...data.routeDispatchedMiddleware,
|
|
415
|
+
...data.throwableCaughtMiddleware,
|
|
416
|
+
...data.sendingResponseMiddleware,
|
|
417
|
+
...data.responseSentMiddleware,
|
|
418
|
+
]) {
|
|
419
|
+
this.addClassImport(importMap, middleware, useMap, currentFilePath, currentClass);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return importMap;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
protected addClassImport(
|
|
427
|
+
importMap: Record<string, string>,
|
|
428
|
+
className: string,
|
|
429
|
+
useMap: Record<string, string>,
|
|
430
|
+
currentFilePath: string,
|
|
431
|
+
currentClass: string,
|
|
432
|
+
): void {
|
|
433
|
+
const shortName = className.slice(className.lastIndexOf('\\') + 1);
|
|
434
|
+
|
|
435
|
+
const filePath =
|
|
436
|
+
shortName === currentClass
|
|
437
|
+
? currentFilePath
|
|
438
|
+
: this.resolveImportToFilePath(shortName, useMap, currentFilePath);
|
|
439
|
+
|
|
440
|
+
if (filePath !== '') {
|
|
441
|
+
importMap[shortName] = filePath;
|
|
442
|
+
}
|
|
314
443
|
}
|
|
315
444
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* This file is part of the Sindri package.
|
|
3
3
|
*
|
|
4
|
-
* (c) Melech Mizrachi
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* file that was distributed with this source code.
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
import { ts } from 'ts-morph';
|
|
@@ -24,19 +23,13 @@ import type { HttpRouteMiddlewareReaderContract } from './Contract/HttpRouteMidd
|
|
|
24
23
|
* complexity threshold; injected as a constructor argument.
|
|
25
24
|
*/
|
|
26
25
|
export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMiddlewareReaderContract {
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
extractObjectRequestMethods(
|
|
27
|
+
obj: ts.ObjectLiteralExpression,
|
|
29
28
|
useMap: Record<string, string>,
|
|
30
29
|
namespace: string,
|
|
31
30
|
currentClass: string,
|
|
32
31
|
): string[] {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (requestMethodsArg === undefined || !ts.isArrayLiteralExpression(requestMethodsArg)) {
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return this.extractClassListFromArrayExpr(requestMethodsArg, useMap, namespace, currentClass);
|
|
32
|
+
return this.getObjectClassListProp(obj, 'requestMethods', useMap, namespace, currentClass);
|
|
40
33
|
}
|
|
41
34
|
|
|
42
35
|
updateRequestMethods(
|
|
@@ -71,14 +64,41 @@ export class HttpRouteMiddlewareReader extends AstReader implements HttpRouteMid
|
|
|
71
64
|
useMap: Record<string, string>,
|
|
72
65
|
namespace: string,
|
|
73
66
|
currentClass: string,
|
|
74
|
-
|
|
75
|
-
routeDispatchedMiddleware: string[],
|
|
76
|
-
throwableCaughtMiddleware: string[],
|
|
77
|
-
sendingResponseMiddleware: string[],
|
|
78
|
-
responseSentMiddleware: string[],
|
|
67
|
+
middleware: string[],
|
|
79
68
|
): [string[], string[], string[], string[], string[]] {
|
|
69
|
+
let routeMatchedMiddleware: string[] = [];
|
|
70
|
+
let routeDispatchedMiddleware: string[] = [];
|
|
71
|
+
let throwableCaughtMiddleware: string[] = [];
|
|
72
|
+
let sendingResponseMiddleware: string[] = [];
|
|
73
|
+
let responseSentMiddleware: string[] = [];
|
|
74
|
+
|
|
75
|
+
for (const mwName of middleware) {
|
|
76
|
+
[
|
|
77
|
+
routeMatchedMiddleware,
|
|
78
|
+
routeDispatchedMiddleware,
|
|
79
|
+
throwableCaughtMiddleware,
|
|
80
|
+
sendingResponseMiddleware,
|
|
81
|
+
responseSentMiddleware,
|
|
82
|
+
] = this.classifyMiddleware(
|
|
83
|
+
mwName,
|
|
84
|
+
useMap,
|
|
85
|
+
namespace,
|
|
86
|
+
routeMatchedMiddleware,
|
|
87
|
+
routeDispatchedMiddleware,
|
|
88
|
+
throwableCaughtMiddleware,
|
|
89
|
+
sendingResponseMiddleware,
|
|
90
|
+
responseSentMiddleware,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
80
94
|
for (const decorator of this.findDecoratorsOnNode(method, 'Middleware', useMap, namespace)) {
|
|
81
|
-
|
|
95
|
+
// `@Middleware` takes a thunked class reference (`() => AuthMiddleware`).
|
|
96
|
+
const mwName = this.extractExprValue(
|
|
97
|
+
this.unwrapClassThunk(this.getDecoratorArg(decorator, 0)),
|
|
98
|
+
useMap,
|
|
99
|
+
namespace,
|
|
100
|
+
currentClass,
|
|
101
|
+
);
|
|
82
102
|
|
|
83
103
|
if (typeof mwName !== 'string' || mwName === '') {
|
|
84
104
|
continue;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* This file is part of the Sindri package.
|
|
3
3
|
*
|
|
4
|
-
* (c) Melech Mizrachi
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* file that was distributed with this source code.
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
import { ts } from 'ts-morph';
|
|
@@ -12,75 +11,41 @@ import { ts } from 'ts-morph';
|
|
|
12
11
|
import { AstReader } from './Abstract/AstReader.ts';
|
|
13
12
|
import { HttpParameterData } from './Data/HttpParameterData.ts';
|
|
14
13
|
|
|
15
|
-
import type { Decorator, MethodDeclaration } from 'ts-morph';
|
|
16
|
-
|
|
17
14
|
import type { HttpRouteParameterReaderContract } from './Contract/HttpRouteParameterReaderContract.ts';
|
|
18
15
|
|
|
19
16
|
/**
|
|
20
17
|
* Reads and builds AST expressions for HTTP dynamic route parameters.
|
|
21
18
|
*
|
|
19
|
+
* The shipped `@DynamicRoute` decorator folds parameter definitions into its
|
|
20
|
+
* options object as `parameters: [{ name, regex, cast?, isOptional?,
|
|
21
|
+
* shouldCapture?, default? }]` (TC39 Stage-3 has no parameter decorators), so
|
|
22
|
+
* this reader parses that array of object literals rather than a separate
|
|
23
|
+
* `@Parameter` decorator.
|
|
24
|
+
*
|
|
22
25
|
* Extracted from HttpRouteAttributeReader to keep each class under the
|
|
23
26
|
* complexity threshold; injected as a constructor argument.
|
|
24
27
|
*/
|
|
25
28
|
export class HttpRouteParameterReader extends AstReader implements HttpRouteParameterReaderContract {
|
|
26
29
|
updateParameters(
|
|
27
|
-
|
|
28
|
-
method: MethodDeclaration,
|
|
30
|
+
obj: ts.ObjectLiteralExpression,
|
|
29
31
|
useMap: Record<string, string>,
|
|
30
32
|
namespace: string,
|
|
31
33
|
currentClass: string,
|
|
32
34
|
): HttpParameterData[] {
|
|
33
|
-
|
|
34
|
-
...this.collectInlineParameters(decoratorArgs, useMap, namespace, currentClass),
|
|
35
|
-
...this.collectAttributeParameters(method, useMap, namespace, currentClass),
|
|
36
|
-
...this.collectMethodParamParameters(method, useMap, namespace, currentClass),
|
|
37
|
-
];
|
|
38
|
-
}
|
|
35
|
+
const node = this.getObjectProp(obj, 'parameters');
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
const elements = parameters.map((p) => this.buildParameterExpr(p));
|
|
42
|
-
return ts.factory.createArrayLiteralExpression(elements);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
protected collectInlineParameters(
|
|
46
|
-
decoratorArgs: ts.NodeArray<ts.Expression> | ts.Expression[],
|
|
47
|
-
useMap: Record<string, string>,
|
|
48
|
-
currentFilePath: string,
|
|
49
|
-
currentClass: string,
|
|
50
|
-
): HttpParameterData[] {
|
|
51
|
-
const inlineArg = decoratorArgs[2];
|
|
52
|
-
|
|
53
|
-
if (inlineArg === undefined || !ts.isArrayLiteralExpression(inlineArg)) {
|
|
37
|
+
if (node === undefined || !ts.isArrayLiteralExpression(node)) {
|
|
54
38
|
return [];
|
|
55
39
|
}
|
|
56
40
|
|
|
57
41
|
const parameters: HttpParameterData[] = [];
|
|
58
42
|
|
|
59
|
-
for (const element of
|
|
60
|
-
if (!ts.
|
|
43
|
+
for (const element of node.elements) {
|
|
44
|
+
if (!ts.isObjectLiteralExpression(element)) {
|
|
61
45
|
continue;
|
|
62
46
|
}
|
|
63
47
|
|
|
64
|
-
const param = this.
|
|
65
|
-
|
|
66
|
-
if (param !== null) {
|
|
67
|
-
parameters.push(param);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return parameters;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
protected collectAttributeParameters(
|
|
75
|
-
method: MethodDeclaration,
|
|
76
|
-
useMap: Record<string, string>,
|
|
77
|
-
currentFilePath: string,
|
|
78
|
-
currentClass: string,
|
|
79
|
-
): HttpParameterData[] {
|
|
80
|
-
const parameters: HttpParameterData[] = [];
|
|
81
|
-
|
|
82
|
-
for (const decorator of this.findDecoratorsOnNode(method, 'Parameter', useMap, currentFilePath)) {
|
|
83
|
-
const param = this.buildParameterDataFromDecorator(decorator, useMap, currentFilePath, currentClass);
|
|
48
|
+
const param = this.buildParameterData(element, useMap, namespace, currentClass);
|
|
84
49
|
|
|
85
50
|
if (param !== null) {
|
|
86
51
|
parameters.push(param);
|
|
@@ -90,89 +55,49 @@ export class HttpRouteParameterReader extends AstReader implements HttpRoutePara
|
|
|
90
55
|
return parameters;
|
|
91
56
|
}
|
|
92
57
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
currentFilePath: string,
|
|
97
|
-
currentClass: string,
|
|
98
|
-
): HttpParameterData[] {
|
|
99
|
-
const parameters: HttpParameterData[] = [];
|
|
100
|
-
|
|
101
|
-
for (const methodParam of method.getParameters()) {
|
|
102
|
-
for (const decorator of this.findDecoratorsOnNode(methodParam, 'Parameter', useMap, currentFilePath)) {
|
|
103
|
-
const param = this.buildParameterDataFromDecorator(decorator, useMap, currentFilePath, currentClass);
|
|
104
|
-
|
|
105
|
-
if (param !== null) {
|
|
106
|
-
parameters.push(param);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return parameters;
|
|
58
|
+
buildParameterListExpr(parameters: HttpParameterData[]): ts.ArrayLiteralExpression {
|
|
59
|
+
const elements = parameters.map((p) => this.buildParameterExpr(p));
|
|
60
|
+
return ts.factory.createArrayLiteralExpression(elements);
|
|
112
61
|
}
|
|
113
62
|
|
|
114
|
-
protected
|
|
115
|
-
|
|
63
|
+
protected buildParameterData(
|
|
64
|
+
obj: ts.ObjectLiteralExpression,
|
|
116
65
|
useMap: Record<string, string>,
|
|
117
66
|
currentFilePath: string,
|
|
118
67
|
currentClass: string,
|
|
119
68
|
): HttpParameterData | null {
|
|
120
|
-
const name = this.
|
|
121
|
-
const regex = this.
|
|
69
|
+
const name = this.getObjectStringProp(obj, 'name', useMap, currentFilePath, currentClass);
|
|
70
|
+
const regex = this.getObjectStringProp(obj, 'regex', useMap, currentFilePath, currentClass);
|
|
122
71
|
|
|
123
72
|
if (name === '' || regex === '') {
|
|
124
73
|
return null;
|
|
125
74
|
}
|
|
126
75
|
|
|
76
|
+
const cast = this.getObjectStringProp(obj, 'cast', useMap, currentFilePath, currentClass) || null;
|
|
77
|
+
|
|
127
78
|
return new HttpParameterData(
|
|
128
79
|
name,
|
|
129
80
|
regex,
|
|
130
|
-
|
|
131
|
-
this.
|
|
132
|
-
this.
|
|
81
|
+
cast,
|
|
82
|
+
this.getObjectBoolProp(obj, 'isOptional', useMap, currentFilePath, currentClass, false),
|
|
83
|
+
this.getObjectBoolProp(obj, 'shouldCapture', useMap, currentFilePath, currentClass, true),
|
|
84
|
+
this.extractDefault(obj, useMap, currentFilePath, currentClass),
|
|
133
85
|
);
|
|
134
86
|
}
|
|
135
87
|
|
|
136
|
-
protected
|
|
137
|
-
|
|
88
|
+
protected extractDefault(
|
|
89
|
+
obj: ts.ObjectLiteralExpression,
|
|
138
90
|
useMap: Record<string, string>,
|
|
139
91
|
currentFilePath: string,
|
|
140
92
|
currentClass: string,
|
|
141
|
-
):
|
|
142
|
-
const
|
|
143
|
-
const regexNode = args[1];
|
|
93
|
+
): string | number | boolean | null {
|
|
94
|
+
const value = this.extractExprValue(this.getObjectProp(obj, 'default'), useMap, currentFilePath, currentClass);
|
|
144
95
|
|
|
145
|
-
if (
|
|
146
|
-
return
|
|
96
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
97
|
+
return value;
|
|
147
98
|
}
|
|
148
99
|
|
|
149
|
-
|
|
150
|
-
const regex = this.extractExprValue(regexNode, useMap, currentFilePath, currentClass);
|
|
151
|
-
|
|
152
|
-
if (typeof name !== 'string' || name === '' || typeof regex !== 'string' || regex === '') {
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const castNode = args[2];
|
|
157
|
-
const castRaw =
|
|
158
|
-
castNode !== undefined ? this.extractExprValue(castNode, useMap, currentFilePath, currentClass) : null;
|
|
159
|
-
const cast = typeof castRaw === 'string' && castRaw !== '' ? castRaw : null;
|
|
160
|
-
|
|
161
|
-
const isOptionalNode = args[3];
|
|
162
|
-
const isOptionalRaw =
|
|
163
|
-
isOptionalNode !== undefined
|
|
164
|
-
? this.extractExprValue(isOptionalNode, useMap, currentFilePath, currentClass)
|
|
165
|
-
: false;
|
|
166
|
-
const isOptional = typeof isOptionalRaw === 'boolean' ? isOptionalRaw : false;
|
|
167
|
-
|
|
168
|
-
const shouldCaptureNode = args[4];
|
|
169
|
-
const shouldCaptureRaw =
|
|
170
|
-
shouldCaptureNode !== undefined
|
|
171
|
-
? this.extractExprValue(shouldCaptureNode, useMap, currentFilePath, currentClass)
|
|
172
|
-
: true;
|
|
173
|
-
const shouldCapture = typeof shouldCaptureRaw === 'boolean' ? shouldCaptureRaw : true;
|
|
174
|
-
|
|
175
|
-
return new HttpParameterData(name, regex, cast, isOptional, shouldCapture);
|
|
100
|
+
return null;
|
|
176
101
|
}
|
|
177
102
|
|
|
178
103
|
protected buildParameterExpr(data: HttpParameterData): ts.Expression {
|
|
@@ -188,6 +113,22 @@ export class HttpRouteParameterReader extends AstReader implements HttpRoutePara
|
|
|
188
113
|
this.buildBoolExpr(data.shouldCapture),
|
|
189
114
|
];
|
|
190
115
|
|
|
116
|
+
if (data.defaultValue !== null) {
|
|
117
|
+
args.push(this.buildScalarExpr(data.defaultValue));
|
|
118
|
+
}
|
|
119
|
+
|
|
191
120
|
return this.buildNewExpr('Valkyrja\\Http\\Routing\\Data\\Parameter', args);
|
|
192
121
|
}
|
|
122
|
+
|
|
123
|
+
protected buildScalarExpr(value: string | number | boolean): ts.Expression {
|
|
124
|
+
if (typeof value === 'string') {
|
|
125
|
+
return this.buildStringExpr(value);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (typeof value === 'boolean') {
|
|
129
|
+
return this.buildBoolExpr(value);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return ts.factory.createNumericLiteral(value);
|
|
133
|
+
}
|
|
193
134
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* This file is part of the Sindri package.
|
|
3
3
|
*
|
|
4
|
-
* (c) Melech Mizrachi
|
|
4
|
+
* Copyright (c) 2016-present Melech Mizrachi
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* file that was distributed with this source code.
|
|
6
|
+
* Released under the MIT License. See LICENSE.md for details.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
import { ts } from 'ts-morph';
|