@valkyrjaio/sindri 26.0.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 +21 -0
- package/README.md +111 -0
- package/package.json +63 -0
- package/src/Sindri/Ast/Abstract/AstReader.ts +710 -0
- package/src/Sindri/Ast/Abstract/RouteAttributeReader.ts +50 -0
- package/src/Sindri/Ast/CliRouteAttributeReader.ts +219 -0
- package/src/Sindri/Ast/CliRouteParameterReader.ts +204 -0
- package/src/Sindri/Ast/ComponentProviderReader.ts +41 -0
- package/src/Sindri/Ast/ConfigReader.ts +213 -0
- package/src/Sindri/Ast/Contract/CliRouteAttributeReaderContract.ts +14 -0
- package/src/Sindri/Ast/Contract/CliRouteParameterReaderContract.ts +34 -0
- package/src/Sindri/Ast/Contract/ComponentProviderReaderContract.ts +14 -0
- package/src/Sindri/Ast/Contract/ConfigReaderContract.ts +14 -0
- package/src/Sindri/Ast/Contract/HttpRouteAttributeReaderContract.ts +14 -0
- package/src/Sindri/Ast/Contract/HttpRouteMiddlewareReaderContract.ts +61 -0
- package/src/Sindri/Ast/Contract/HttpRouteParameterReaderContract.ts +26 -0
- package/src/Sindri/Ast/Contract/ListenerAttributeReaderContract.ts +14 -0
- package/src/Sindri/Ast/Contract/ListenerProviderReaderContract.ts +14 -0
- package/src/Sindri/Ast/Contract/RouteProviderReaderContract.ts +14 -0
- package/src/Sindri/Ast/Contract/ServiceProviderReaderContract.ts +14 -0
- package/src/Sindri/Ast/Data/CliArgumentParameterData.ts +20 -0
- package/src/Sindri/Ast/Data/CliOptionParameterData.ts +24 -0
- package/src/Sindri/Ast/Data/CliRouteData.ts +32 -0
- package/src/Sindri/Ast/Data/ConfigData.ts +20 -0
- package/src/Sindri/Ast/Data/Contract/CliArgumentParameterDataContract.ts +18 -0
- package/src/Sindri/Ast/Data/Contract/CliOptionParameterDataContract.ts +22 -0
- package/src/Sindri/Ast/Data/Contract/CliRouteDataContract.ts +25 -0
- package/src/Sindri/Ast/Data/Contract/ConfigDataContract.ts +16 -0
- package/src/Sindri/Ast/Data/Contract/HandlerDataContract.ts +13 -0
- package/src/Sindri/Ast/Data/Contract/HttpParameterDataContract.ts +17 -0
- package/src/Sindri/Ast/Data/Contract/HttpRouteDataContract.ts +28 -0
- package/src/Sindri/Ast/Data/Contract/ListenerDataContract.ts +16 -0
- package/src/Sindri/Ast/Data/HandlerData.ts +20 -0
- package/src/Sindri/Ast/Data/HttpParameterData.ts +20 -0
- package/src/Sindri/Ast/Data/HttpRouteData.ts +30 -0
- package/src/Sindri/Ast/Data/ListenerData.ts +19 -0
- package/src/Sindri/Ast/Data/Result/CliRouteAttributeResult.ts +14 -0
- package/src/Sindri/Ast/Data/Result/ComponentProviderResult.ts +28 -0
- package/src/Sindri/Ast/Data/Result/ConfigResult.ts +18 -0
- package/src/Sindri/Ast/Data/Result/HttpRouteAttributeResult.ts +19 -0
- package/src/Sindri/Ast/Data/Result/ListenerAttributeResult.ts +14 -0
- package/src/Sindri/Ast/Data/Result/ListenerProviderResult.ts +24 -0
- package/src/Sindri/Ast/Data/Result/RouteProviderResult.ts +24 -0
- package/src/Sindri/Ast/Data/Result/ServiceProviderResult.ts +22 -0
- package/src/Sindri/Ast/HttpRouteAttributeReader.ts +315 -0
- package/src/Sindri/Ast/HttpRouteMiddlewareReader.ts +214 -0
- package/src/Sindri/Ast/HttpRouteParameterReader.ts +193 -0
- package/src/Sindri/Ast/ListenerAttributeReader.ts +131 -0
- package/src/Sindri/Ast/ListenerProviderReader.ts +45 -0
- package/src/Sindri/Ast/RouteProviderReader.ts +45 -0
- package/src/Sindri/Ast/ServiceProviderReader.ts +124 -0
- package/src/Sindri/Ast/Throwable/Contract/AstThrowable.ts +12 -0
- package/src/Sindri/Ast/Throwable/Exception/Abstract/AstInvalidArgumentException.ts +14 -0
- package/src/Sindri/Ast/Throwable/Exception/Abstract/AstRuntimeException.ts +14 -0
- package/src/Sindri/Ast/Throwable/Exception/AstFileReadException.ts +12 -0
- package/src/Sindri/Cli/Command/GenerateDataFromConfigCommand.ts +83 -0
- package/src/Sindri/Constant/CommandName.ts +12 -0
- package/src/Sindri/Constant/SindriInfo.ts +20 -0
- package/src/Sindri/Constant/SindriServiceId.ts +32 -0
- package/src/Sindri/Generate/Abstract/GenerateDataFromAst.ts +391 -0
- package/src/Sindri/Generator/Abstract/AstFileGenerator.ts +54 -0
- package/src/Sindri/Generator/Abstract/FileGenerator.ts +59 -0
- package/src/Sindri/Generator/Ast/Cli/AstCliDataFileGenerator.ts +88 -0
- package/src/Sindri/Generator/Ast/Container/AstContainerDataFileGenerator.ts +86 -0
- package/src/Sindri/Generator/Ast/Event/AstEventDataFileGenerator.ts +79 -0
- package/src/Sindri/Generator/Ast/Http/AstHttpDataFileGenerator.ts +306 -0
- package/src/Sindri/Generator/Cli/Contract/CliDataFileGeneratorContract.ts +23 -0
- package/src/Sindri/Generator/Container/Contract/ContainerDataFileGeneratorContract.ts +21 -0
- package/src/Sindri/Generator/Contract/FileGeneratorContract.ts +15 -0
- package/src/Sindri/Generator/Enum/GenerateStatus.ts +14 -0
- package/src/Sindri/Generator/Event/Contract/EventDataFileGeneratorContract.ts +23 -0
- package/src/Sindri/Generator/Http/Contract/HttpDataFileGeneratorContract.ts +25 -0
- package/src/Sindri/Generator/Throwable/Contract/GeneratorThrowable.ts +12 -0
- package/src/Sindri/Generator/Throwable/Exception/Abstract/GeneratorInvalidArgumentException.ts +16 -0
- package/src/Sindri/Generator/Throwable/Exception/Abstract/GeneratorRuntimeException.ts +14 -0
- package/src/Sindri/Generator/Throwable/Exception/GeneratorUnreachableException.ts +12 -0
- package/src/Sindri/Provider/SindriAstServiceProvider.ts +182 -0
- package/src/Sindri/Provider/SindriCliRouteProvider.ts +32 -0
- package/src/Sindri/Provider/SindriCommandServiceProvider.ts +71 -0
- package/src/Sindri/Provider/SindriComponentProvider.ts +41 -0
- package/src/Sindri/Throwable/Contract/SindriThrowable.ts +12 -0
- package/src/Sindri/Throwable/Exception/Abstract/SindriInvalidArgumentException.ts +16 -0
- package/src/Sindri/Throwable/Exception/Abstract/SindriRuntimeException.ts +14 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { HandlerDataContract } from './HandlerDataContract.ts';
|
|
11
|
+
import type { HttpParameterDataContract } from './HttpParameterDataContract.ts';
|
|
12
|
+
|
|
13
|
+
export interface HttpRouteDataContract {
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly handler: HandlerDataContract | null;
|
|
17
|
+
/** "FQN::CASE" strings for RequestMethod enum values */
|
|
18
|
+
readonly requestMethods: readonly string[];
|
|
19
|
+
readonly routeMatchedMiddleware: readonly string[];
|
|
20
|
+
readonly routeDispatchedMiddleware: readonly string[];
|
|
21
|
+
readonly throwableCaughtMiddleware: readonly string[];
|
|
22
|
+
readonly sendingResponseMiddleware: readonly string[];
|
|
23
|
+
readonly terminatedMiddleware: readonly string[];
|
|
24
|
+
readonly requestStruct: string | null;
|
|
25
|
+
readonly responseStruct: string | null;
|
|
26
|
+
readonly isDynamic: boolean;
|
|
27
|
+
readonly parameters: readonly HttpParameterDataContract[];
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { HandlerDataContract } from './HandlerDataContract.ts';
|
|
11
|
+
|
|
12
|
+
export interface ListenerDataContract {
|
|
13
|
+
readonly eventId: string;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly handler: HandlerDataContract | null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { HandlerDataContract } from './Contract/HandlerDataContract.ts';
|
|
11
|
+
|
|
12
|
+
export class HandlerData implements HandlerDataContract {
|
|
13
|
+
readonly class: string;
|
|
14
|
+
readonly method: string;
|
|
15
|
+
|
|
16
|
+
constructor(className: string, method: string) {
|
|
17
|
+
this.class = className;
|
|
18
|
+
this.method = method;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { HttpParameterDataContract } from './Contract/HttpParameterDataContract.ts';
|
|
11
|
+
|
|
12
|
+
export class HttpParameterData implements HttpParameterDataContract {
|
|
13
|
+
constructor(
|
|
14
|
+
readonly name: string,
|
|
15
|
+
readonly regex: string,
|
|
16
|
+
readonly cast: string | null = null,
|
|
17
|
+
readonly isOptional: boolean = false,
|
|
18
|
+
readonly shouldCapture: boolean = true,
|
|
19
|
+
) {}
|
|
20
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { HttpRouteDataContract } from './Contract/HttpRouteDataContract.ts';
|
|
11
|
+
import type { HandlerData } from './HandlerData.ts';
|
|
12
|
+
import type { HttpParameterData } from './HttpParameterData.ts';
|
|
13
|
+
|
|
14
|
+
export class HttpRouteData implements HttpRouteDataContract {
|
|
15
|
+
constructor(
|
|
16
|
+
readonly path: string,
|
|
17
|
+
readonly name: string,
|
|
18
|
+
readonly handler: HandlerData | null = null,
|
|
19
|
+
readonly requestMethods: readonly string[] = [],
|
|
20
|
+
readonly routeMatchedMiddleware: readonly string[] = [],
|
|
21
|
+
readonly routeDispatchedMiddleware: readonly string[] = [],
|
|
22
|
+
readonly throwableCaughtMiddleware: readonly string[] = [],
|
|
23
|
+
readonly sendingResponseMiddleware: readonly string[] = [],
|
|
24
|
+
readonly terminatedMiddleware: readonly string[] = [],
|
|
25
|
+
readonly requestStruct: string | null = null,
|
|
26
|
+
readonly responseStruct: string | null = null,
|
|
27
|
+
readonly isDynamic: boolean = false,
|
|
28
|
+
readonly parameters: readonly HttpParameterData[] = [],
|
|
29
|
+
) {}
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ListenerDataContract } from './Contract/ListenerDataContract.ts';
|
|
11
|
+
import type { HandlerData } from './HandlerData.ts';
|
|
12
|
+
|
|
13
|
+
export class ListenerData implements ListenerDataContract {
|
|
14
|
+
constructor(
|
|
15
|
+
readonly eventId: string,
|
|
16
|
+
readonly name: string,
|
|
17
|
+
readonly handler: HandlerData | null = null,
|
|
18
|
+
) {}
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ts } from 'ts-morph';
|
|
11
|
+
|
|
12
|
+
export class CliRouteAttributeResult {
|
|
13
|
+
constructor(readonly routes: Record<string, ts.Expression> = {}) {}
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export class ComponentProviderResult {
|
|
11
|
+
constructor(
|
|
12
|
+
readonly componentProviders: readonly string[] = [],
|
|
13
|
+
readonly serviceProviders: readonly string[] = [],
|
|
14
|
+
readonly listenerProviders: readonly string[] = [],
|
|
15
|
+
readonly cliRouteProviders: readonly string[] = [],
|
|
16
|
+
readonly httpRouteProviders: readonly string[] = [],
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
merge(other: ComponentProviderResult): ComponentProviderResult {
|
|
20
|
+
return new ComponentProviderResult(
|
|
21
|
+
[...new Set([...this.componentProviders, ...other.componentProviders])],
|
|
22
|
+
[...new Set([...this.serviceProviders, ...other.serviceProviders])],
|
|
23
|
+
[...new Set([...this.listenerProviders, ...other.listenerProviders])],
|
|
24
|
+
[...new Set([...this.cliRouteProviders, ...other.cliRouteProviders])],
|
|
25
|
+
[...new Set([...this.httpRouteProviders, ...other.httpRouteProviders])],
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export class ConfigResult {
|
|
11
|
+
constructor(
|
|
12
|
+
readonly namespace: string = '',
|
|
13
|
+
readonly dir: string = '',
|
|
14
|
+
readonly dataPath: string = '',
|
|
15
|
+
readonly dataNamespace: string = '',
|
|
16
|
+
readonly providers: readonly string[] = [],
|
|
17
|
+
) {}
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ts } from 'ts-morph';
|
|
11
|
+
|
|
12
|
+
import type { HttpRouteData } from '../HttpRouteData.ts';
|
|
13
|
+
|
|
14
|
+
export class HttpRouteAttributeResult {
|
|
15
|
+
constructor(
|
|
16
|
+
readonly routes: Record<string, ts.Expression> = {},
|
|
17
|
+
readonly routeData: Record<string, HttpRouteData> = {},
|
|
18
|
+
) {}
|
|
19
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ts } from 'ts-morph';
|
|
11
|
+
|
|
12
|
+
export class ListenerAttributeResult {
|
|
13
|
+
constructor(readonly listeners: Record<string, ts.Expression> = {}) {}
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ts } from 'ts-morph';
|
|
11
|
+
|
|
12
|
+
export class ListenerProviderResult {
|
|
13
|
+
constructor(
|
|
14
|
+
readonly listenerClasses: readonly string[] = [],
|
|
15
|
+
readonly listeners: readonly ts.Expression[] = [],
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
merge(other: ListenerProviderResult): ListenerProviderResult {
|
|
19
|
+
return new ListenerProviderResult(
|
|
20
|
+
[...new Set([...this.listenerClasses, ...other.listenerClasses])],
|
|
21
|
+
[...this.listeners, ...other.listeners],
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ts } from 'ts-morph';
|
|
11
|
+
|
|
12
|
+
export class RouteProviderResult {
|
|
13
|
+
constructor(
|
|
14
|
+
readonly controllerClasses: readonly string[] = [],
|
|
15
|
+
readonly routes: readonly ts.Expression[] = [],
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
merge(other: RouteProviderResult): RouteProviderResult {
|
|
19
|
+
return new RouteProviderResult(
|
|
20
|
+
[...new Set([...this.controllerClasses, ...other.controllerClasses])],
|
|
21
|
+
[...this.routes, ...other.routes],
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export class ServiceProviderResult {
|
|
11
|
+
constructor(
|
|
12
|
+
readonly serviceClasses: readonly string[] = [],
|
|
13
|
+
readonly publishers: Readonly<Record<string, readonly [string, string]>> = {},
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
merge(other: ServiceProviderResult): ServiceProviderResult {
|
|
17
|
+
return new ServiceProviderResult([...new Set([...this.serviceClasses, ...other.serviceClasses])], {
|
|
18
|
+
...this.publishers,
|
|
19
|
+
...other.publishers,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of the Sindri package.
|
|
3
|
+
*
|
|
4
|
+
* (c) Melech Mizrachi <melechmizrachi@gmail.com>
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { ts } from 'ts-morph';
|
|
11
|
+
|
|
12
|
+
import { RouteAttributeReader } from './Abstract/RouteAttributeReader.ts';
|
|
13
|
+
import { HttpRouteData } from './Data/HttpRouteData.ts';
|
|
14
|
+
import { HttpRouteAttributeResult } from './Data/Result/HttpRouteAttributeResult.ts';
|
|
15
|
+
import { HttpRouteMiddlewareReader } from './HttpRouteMiddlewareReader.ts';
|
|
16
|
+
import { HttpRouteParameterReader } from './HttpRouteParameterReader.ts';
|
|
17
|
+
|
|
18
|
+
import type { ClassDeclaration, Decorator, MethodDeclaration, Node } from 'ts-morph';
|
|
19
|
+
|
|
20
|
+
import type { HttpRouteAttributeReaderContract } from './Contract/HttpRouteAttributeReaderContract.ts';
|
|
21
|
+
import type { HttpRouteMiddlewareReaderContract } from './Contract/HttpRouteMiddlewareReaderContract.ts';
|
|
22
|
+
import type { HttpRouteParameterReaderContract } from './Contract/HttpRouteParameterReaderContract.ts';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Scans an HTTP controller class file for @Route / @DynamicRoute and related
|
|
26
|
+
* sub-decorators and returns TypeScript compiler API Expr nodes ready for the data cache generator.
|
|
27
|
+
*
|
|
28
|
+
* Mirrors the logic of the framework's runtime AttributeRouteCollector but operates
|
|
29
|
+
* entirely on AST without executing any TypeScript code.
|
|
30
|
+
*/
|
|
31
|
+
export class HttpRouteAttributeReader extends RouteAttributeReader implements HttpRouteAttributeReaderContract {
|
|
32
|
+
constructor(
|
|
33
|
+
protected readonly parameterReader: HttpRouteParameterReaderContract = new HttpRouteParameterReader(),
|
|
34
|
+
protected readonly middlewareReader: HttpRouteMiddlewareReaderContract = new HttpRouteMiddlewareReader(),
|
|
35
|
+
) {
|
|
36
|
+
super();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
readFile(filePath: string): HttpRouteAttributeResult {
|
|
40
|
+
const context = this.parseClassFile(filePath);
|
|
41
|
+
|
|
42
|
+
if (context === undefined) {
|
|
43
|
+
return new HttpRouteAttributeResult();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { classDecl, useMap, currentClass } = context;
|
|
47
|
+
|
|
48
|
+
const classPathPrefix = this.extractClassPathPrefix(classDecl, useMap, filePath, currentClass);
|
|
49
|
+
const classNamePrefix = this.extractClassNamePrefix(classDecl, useMap, filePath, currentClass);
|
|
50
|
+
|
|
51
|
+
return this.buildRouteResult(classDecl, useMap, filePath, currentClass, classPathPrefix, classNamePrefix);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected getRouteHandlerDecoratorName(): string {
|
|
55
|
+
return 'RouteHandler';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
protected extractClassPathPrefix(
|
|
59
|
+
classDecl: ClassDeclaration,
|
|
60
|
+
useMap: Record<string, string>,
|
|
61
|
+
currentFilePath: string,
|
|
62
|
+
currentClass: string,
|
|
63
|
+
): string {
|
|
64
|
+
for (const decorator of this.findDecoratorsOnNode(classDecl, 'Path', useMap, currentFilePath)) {
|
|
65
|
+
const value = this.extractExprValue(
|
|
66
|
+
this.getDecoratorArg(decorator, 0),
|
|
67
|
+
useMap,
|
|
68
|
+
currentFilePath,
|
|
69
|
+
currentClass,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (typeof value === 'string' && value !== '') {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return '';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
protected extractClassNamePrefix(
|
|
81
|
+
classDecl: ClassDeclaration,
|
|
82
|
+
useMap: Record<string, string>,
|
|
83
|
+
currentFilePath: string,
|
|
84
|
+
currentClass: string,
|
|
85
|
+
): string {
|
|
86
|
+
for (const decorator of this.findDecoratorsOnNode(classDecl, 'Name', useMap, currentFilePath)) {
|
|
87
|
+
const value = this.extractExprValue(
|
|
88
|
+
this.getDecoratorArg(decorator, 0),
|
|
89
|
+
useMap,
|
|
90
|
+
currentFilePath,
|
|
91
|
+
currentClass,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (typeof value === 'string' && value !== '') {
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
protected buildRouteResult(
|
|
103
|
+
classDecl: ClassDeclaration,
|
|
104
|
+
useMap: Record<string, string>,
|
|
105
|
+
currentFilePath: string,
|
|
106
|
+
currentClass: string,
|
|
107
|
+
classPathPrefix: string,
|
|
108
|
+
classNamePrefix: string,
|
|
109
|
+
): HttpRouteAttributeResult {
|
|
110
|
+
const routes: Record<string, ts.Expression> = {};
|
|
111
|
+
const routeData: Record<string, HttpRouteData> = {};
|
|
112
|
+
|
|
113
|
+
for (const method of classDecl.getMethods()) {
|
|
114
|
+
for (const decorator of this.findDecoratorsOnNode(method, 'Route', useMap, currentFilePath)) {
|
|
115
|
+
const data = this.buildRouteData(
|
|
116
|
+
decorator,
|
|
117
|
+
method,
|
|
118
|
+
useMap,
|
|
119
|
+
currentFilePath,
|
|
120
|
+
currentClass,
|
|
121
|
+
classPathPrefix,
|
|
122
|
+
classNamePrefix,
|
|
123
|
+
false,
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
if (data !== null) {
|
|
127
|
+
routes[data.name] = this.buildRouteExpr(data);
|
|
128
|
+
routeData[data.name] = data;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const decorator of this.findDecoratorsOnNode(method, 'DynamicRoute', useMap, currentFilePath)) {
|
|
133
|
+
const data = this.buildRouteData(
|
|
134
|
+
decorator,
|
|
135
|
+
method,
|
|
136
|
+
useMap,
|
|
137
|
+
currentFilePath,
|
|
138
|
+
currentClass,
|
|
139
|
+
classPathPrefix,
|
|
140
|
+
classNamePrefix,
|
|
141
|
+
true,
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
if (data !== null) {
|
|
145
|
+
routes[data.name] = this.buildRouteExpr(data);
|
|
146
|
+
routeData[data.name] = data;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return new HttpRouteAttributeResult(routes, routeData);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
protected buildRouteData(
|
|
155
|
+
decorator: Decorator,
|
|
156
|
+
method: MethodDeclaration,
|
|
157
|
+
useMap: Record<string, string>,
|
|
158
|
+
currentFilePath: string,
|
|
159
|
+
currentClass: string,
|
|
160
|
+
classPathPrefix: string,
|
|
161
|
+
classNamePrefix: string,
|
|
162
|
+
isDynamic: boolean,
|
|
163
|
+
): HttpRouteData | null {
|
|
164
|
+
const path = this.extractStringArg(decorator, 0, useMap, currentFilePath, currentClass);
|
|
165
|
+
const name = this.extractStringArg(decorator, 1, useMap, currentFilePath, currentClass);
|
|
166
|
+
|
|
167
|
+
if (path === '' || name === '') {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const updatedPath = this.updatePath(path, classPathPrefix, method, useMap, currentFilePath, currentClass);
|
|
172
|
+
const updatedName = this.updateName(name, classNamePrefix, method, useMap, currentFilePath, currentClass);
|
|
173
|
+
|
|
174
|
+
const resolvedIsDynamic = isDynamic || updatedPath.includes('{');
|
|
175
|
+
|
|
176
|
+
const decoratorArgs = decorator.getArguments().map((a: Node) => a.compilerNode as ts.Expression);
|
|
177
|
+
|
|
178
|
+
const requestMethods = this.middlewareReader.updateRequestMethods(
|
|
179
|
+
this.middlewareReader.extractInlineRequestMethods(decoratorArgs, useMap, currentFilePath, currentClass),
|
|
180
|
+
method,
|
|
181
|
+
useMap,
|
|
182
|
+
currentFilePath,
|
|
183
|
+
currentClass,
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const [
|
|
187
|
+
routeMatchedMiddleware,
|
|
188
|
+
routeDispatchedMiddleware,
|
|
189
|
+
throwableCaughtMiddleware,
|
|
190
|
+
sendingResponseMiddleware,
|
|
191
|
+
terminatedMiddleware,
|
|
192
|
+
] = this.middlewareReader.updateMiddleware(
|
|
193
|
+
method,
|
|
194
|
+
useMap,
|
|
195
|
+
currentFilePath,
|
|
196
|
+
currentClass,
|
|
197
|
+
this.extractClassListArgFromDecorator(decorator, 5, useMap, currentFilePath, currentClass),
|
|
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),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
return new HttpRouteData(
|
|
205
|
+
updatedPath,
|
|
206
|
+
updatedName,
|
|
207
|
+
this.updateHandler(method, useMap, currentFilePath, currentClass),
|
|
208
|
+
requestMethods,
|
|
209
|
+
routeMatchedMiddleware,
|
|
210
|
+
routeDispatchedMiddleware,
|
|
211
|
+
throwableCaughtMiddleware,
|
|
212
|
+
sendingResponseMiddleware,
|
|
213
|
+
terminatedMiddleware,
|
|
214
|
+
this.middlewareReader.updateRequestStruct(method, useMap, currentFilePath, currentClass),
|
|
215
|
+
this.middlewareReader.updateResponseStruct(method, useMap, currentFilePath, currentClass),
|
|
216
|
+
resolvedIsDynamic,
|
|
217
|
+
resolvedIsDynamic
|
|
218
|
+
? this.updateParameters(decoratorArgs, method, useMap, currentFilePath, currentClass)
|
|
219
|
+
: [],
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
protected updatePath(
|
|
224
|
+
path: string,
|
|
225
|
+
classPathPrefix: string,
|
|
226
|
+
method: MethodDeclaration,
|
|
227
|
+
useMap: Record<string, string>,
|
|
228
|
+
currentFilePath: string,
|
|
229
|
+
currentClass: string,
|
|
230
|
+
): string {
|
|
231
|
+
if (classPathPrefix !== '') {
|
|
232
|
+
path = classPathPrefix.replace(/\/$/, '') + '/' + path.replace(/^\//, '');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
for (const decorator of this.findDecoratorsOnNode(method, 'Path', useMap, currentFilePath)) {
|
|
236
|
+
const suffix = this.extractExprValue(
|
|
237
|
+
this.getDecoratorArg(decorator, 0),
|
|
238
|
+
useMap,
|
|
239
|
+
currentFilePath,
|
|
240
|
+
currentClass,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (typeof suffix === 'string' && suffix !== '') {
|
|
244
|
+
path = path.replace(/\/$/, '') + '/' + suffix.replace(/^\//, '');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return path;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
protected updateName(
|
|
252
|
+
name: string,
|
|
253
|
+
classNamePrefix: string,
|
|
254
|
+
method: MethodDeclaration,
|
|
255
|
+
useMap: Record<string, string>,
|
|
256
|
+
currentFilePath: string,
|
|
257
|
+
currentClass: string,
|
|
258
|
+
): string {
|
|
259
|
+
if (classNamePrefix !== '') {
|
|
260
|
+
name = classNamePrefix + '.' + name;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
for (const decorator of this.findDecoratorsOnNode(method, 'Name', useMap, currentFilePath)) {
|
|
264
|
+
const suffix = this.extractExprValue(
|
|
265
|
+
this.getDecoratorArg(decorator, 0),
|
|
266
|
+
useMap,
|
|
267
|
+
currentFilePath,
|
|
268
|
+
currentClass,
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
if (typeof suffix === 'string' && suffix !== '') {
|
|
272
|
+
name = name + '.' + suffix;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return name;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
protected buildRouteExpr(data: HttpRouteData): ts.Expression {
|
|
280
|
+
const args: ts.Expression[] = [this.buildEnumCaseExpr(data.path), this.buildEnumCaseExpr(data.name)];
|
|
281
|
+
|
|
282
|
+
if (data.isDynamic && data.parameters.length > 0) {
|
|
283
|
+
args.push(this.parameterReader.buildParameterListExpr([...data.parameters]));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (data.handler !== null) {
|
|
287
|
+
args.push(this.buildHandlerExpr(data.handler));
|
|
288
|
+
} else {
|
|
289
|
+
args.push(this.buildNullExpr());
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (data.requestMethods.length > 0) {
|
|
293
|
+
args.push(this.buildEnumCaseArrayExpr(data.requestMethods));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
args.push(...this.middlewareReader.buildRouteMiddlewareArgs(data));
|
|
297
|
+
args.push(...this.middlewareReader.buildRouteStructArgs(data));
|
|
298
|
+
|
|
299
|
+
const targetClass = data.isDynamic
|
|
300
|
+
? 'Valkyrja\\Http\\Routing\\Data\\DynamicRoute'
|
|
301
|
+
: 'Valkyrja\\Http\\Routing\\Data\\Route';
|
|
302
|
+
|
|
303
|
+
return this.buildNewExpr(targetClass, args);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
protected updateParameters(
|
|
307
|
+
decoratorArgs: ts.Expression[],
|
|
308
|
+
method: MethodDeclaration,
|
|
309
|
+
useMap: Record<string, string>,
|
|
310
|
+
currentFilePath: string,
|
|
311
|
+
currentClass: string,
|
|
312
|
+
): import('./Data/HttpParameterData.ts').HttpParameterData[] {
|
|
313
|
+
return this.parameterReader.updateParameters(decoratorArgs, method, useMap, currentFilePath, currentClass);
|
|
314
|
+
}
|
|
315
|
+
}
|