@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.
Files changed (83) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +111 -0
  3. package/package.json +63 -0
  4. package/src/Sindri/Ast/Abstract/AstReader.ts +710 -0
  5. package/src/Sindri/Ast/Abstract/RouteAttributeReader.ts +50 -0
  6. package/src/Sindri/Ast/CliRouteAttributeReader.ts +219 -0
  7. package/src/Sindri/Ast/CliRouteParameterReader.ts +204 -0
  8. package/src/Sindri/Ast/ComponentProviderReader.ts +41 -0
  9. package/src/Sindri/Ast/ConfigReader.ts +213 -0
  10. package/src/Sindri/Ast/Contract/CliRouteAttributeReaderContract.ts +14 -0
  11. package/src/Sindri/Ast/Contract/CliRouteParameterReaderContract.ts +34 -0
  12. package/src/Sindri/Ast/Contract/ComponentProviderReaderContract.ts +14 -0
  13. package/src/Sindri/Ast/Contract/ConfigReaderContract.ts +14 -0
  14. package/src/Sindri/Ast/Contract/HttpRouteAttributeReaderContract.ts +14 -0
  15. package/src/Sindri/Ast/Contract/HttpRouteMiddlewareReaderContract.ts +61 -0
  16. package/src/Sindri/Ast/Contract/HttpRouteParameterReaderContract.ts +26 -0
  17. package/src/Sindri/Ast/Contract/ListenerAttributeReaderContract.ts +14 -0
  18. package/src/Sindri/Ast/Contract/ListenerProviderReaderContract.ts +14 -0
  19. package/src/Sindri/Ast/Contract/RouteProviderReaderContract.ts +14 -0
  20. package/src/Sindri/Ast/Contract/ServiceProviderReaderContract.ts +14 -0
  21. package/src/Sindri/Ast/Data/CliArgumentParameterData.ts +20 -0
  22. package/src/Sindri/Ast/Data/CliOptionParameterData.ts +24 -0
  23. package/src/Sindri/Ast/Data/CliRouteData.ts +32 -0
  24. package/src/Sindri/Ast/Data/ConfigData.ts +20 -0
  25. package/src/Sindri/Ast/Data/Contract/CliArgumentParameterDataContract.ts +18 -0
  26. package/src/Sindri/Ast/Data/Contract/CliOptionParameterDataContract.ts +22 -0
  27. package/src/Sindri/Ast/Data/Contract/CliRouteDataContract.ts +25 -0
  28. package/src/Sindri/Ast/Data/Contract/ConfigDataContract.ts +16 -0
  29. package/src/Sindri/Ast/Data/Contract/HandlerDataContract.ts +13 -0
  30. package/src/Sindri/Ast/Data/Contract/HttpParameterDataContract.ts +17 -0
  31. package/src/Sindri/Ast/Data/Contract/HttpRouteDataContract.ts +28 -0
  32. package/src/Sindri/Ast/Data/Contract/ListenerDataContract.ts +16 -0
  33. package/src/Sindri/Ast/Data/HandlerData.ts +20 -0
  34. package/src/Sindri/Ast/Data/HttpParameterData.ts +20 -0
  35. package/src/Sindri/Ast/Data/HttpRouteData.ts +30 -0
  36. package/src/Sindri/Ast/Data/ListenerData.ts +19 -0
  37. package/src/Sindri/Ast/Data/Result/CliRouteAttributeResult.ts +14 -0
  38. package/src/Sindri/Ast/Data/Result/ComponentProviderResult.ts +28 -0
  39. package/src/Sindri/Ast/Data/Result/ConfigResult.ts +18 -0
  40. package/src/Sindri/Ast/Data/Result/HttpRouteAttributeResult.ts +19 -0
  41. package/src/Sindri/Ast/Data/Result/ListenerAttributeResult.ts +14 -0
  42. package/src/Sindri/Ast/Data/Result/ListenerProviderResult.ts +24 -0
  43. package/src/Sindri/Ast/Data/Result/RouteProviderResult.ts +24 -0
  44. package/src/Sindri/Ast/Data/Result/ServiceProviderResult.ts +22 -0
  45. package/src/Sindri/Ast/HttpRouteAttributeReader.ts +315 -0
  46. package/src/Sindri/Ast/HttpRouteMiddlewareReader.ts +214 -0
  47. package/src/Sindri/Ast/HttpRouteParameterReader.ts +193 -0
  48. package/src/Sindri/Ast/ListenerAttributeReader.ts +131 -0
  49. package/src/Sindri/Ast/ListenerProviderReader.ts +45 -0
  50. package/src/Sindri/Ast/RouteProviderReader.ts +45 -0
  51. package/src/Sindri/Ast/ServiceProviderReader.ts +124 -0
  52. package/src/Sindri/Ast/Throwable/Contract/AstThrowable.ts +12 -0
  53. package/src/Sindri/Ast/Throwable/Exception/Abstract/AstInvalidArgumentException.ts +14 -0
  54. package/src/Sindri/Ast/Throwable/Exception/Abstract/AstRuntimeException.ts +14 -0
  55. package/src/Sindri/Ast/Throwable/Exception/AstFileReadException.ts +12 -0
  56. package/src/Sindri/Cli/Command/GenerateDataFromConfigCommand.ts +83 -0
  57. package/src/Sindri/Constant/CommandName.ts +12 -0
  58. package/src/Sindri/Constant/SindriInfo.ts +20 -0
  59. package/src/Sindri/Constant/SindriServiceId.ts +32 -0
  60. package/src/Sindri/Generate/Abstract/GenerateDataFromAst.ts +391 -0
  61. package/src/Sindri/Generator/Abstract/AstFileGenerator.ts +54 -0
  62. package/src/Sindri/Generator/Abstract/FileGenerator.ts +59 -0
  63. package/src/Sindri/Generator/Ast/Cli/AstCliDataFileGenerator.ts +88 -0
  64. package/src/Sindri/Generator/Ast/Container/AstContainerDataFileGenerator.ts +86 -0
  65. package/src/Sindri/Generator/Ast/Event/AstEventDataFileGenerator.ts +79 -0
  66. package/src/Sindri/Generator/Ast/Http/AstHttpDataFileGenerator.ts +306 -0
  67. package/src/Sindri/Generator/Cli/Contract/CliDataFileGeneratorContract.ts +23 -0
  68. package/src/Sindri/Generator/Container/Contract/ContainerDataFileGeneratorContract.ts +21 -0
  69. package/src/Sindri/Generator/Contract/FileGeneratorContract.ts +15 -0
  70. package/src/Sindri/Generator/Enum/GenerateStatus.ts +14 -0
  71. package/src/Sindri/Generator/Event/Contract/EventDataFileGeneratorContract.ts +23 -0
  72. package/src/Sindri/Generator/Http/Contract/HttpDataFileGeneratorContract.ts +25 -0
  73. package/src/Sindri/Generator/Throwable/Contract/GeneratorThrowable.ts +12 -0
  74. package/src/Sindri/Generator/Throwable/Exception/Abstract/GeneratorInvalidArgumentException.ts +16 -0
  75. package/src/Sindri/Generator/Throwable/Exception/Abstract/GeneratorRuntimeException.ts +14 -0
  76. package/src/Sindri/Generator/Throwable/Exception/GeneratorUnreachableException.ts +12 -0
  77. package/src/Sindri/Provider/SindriAstServiceProvider.ts +182 -0
  78. package/src/Sindri/Provider/SindriCliRouteProvider.ts +32 -0
  79. package/src/Sindri/Provider/SindriCommandServiceProvider.ts +71 -0
  80. package/src/Sindri/Provider/SindriComponentProvider.ts +41 -0
  81. package/src/Sindri/Throwable/Contract/SindriThrowable.ts +12 -0
  82. package/src/Sindri/Throwable/Exception/Abstract/SindriInvalidArgumentException.ts +16 -0
  83. package/src/Sindri/Throwable/Exception/Abstract/SindriRuntimeException.ts +14 -0
@@ -0,0 +1,50 @@
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 { MethodDeclaration } from 'ts-morph';
11
+
12
+ import { AstReader } from './AstReader.ts';
13
+ import { HandlerData } from '../Data/HandlerData.ts';
14
+
15
+ /**
16
+ * Base for route attribute readers — provides shared handler resolution logic.
17
+ *
18
+ * Concrete subclasses supply the decorator name of their specific route handler
19
+ * decorator via getRouteHandlerDecoratorName(), and this class implements the
20
+ * common updateHandler() that uses it.
21
+ */
22
+ export abstract class RouteAttributeReader extends AstReader {
23
+ /**
24
+ * Resolve the handler from a @RouteHandler decorator or fall back to ClassName.methodName.
25
+ */
26
+ protected updateHandler(
27
+ method: MethodDeclaration,
28
+ useMap: Record<string, string>,
29
+ currentFilePath: string,
30
+ currentClass: string,
31
+ ): HandlerData {
32
+ const decoratorName = this.getRouteHandlerDecoratorName();
33
+
34
+ for (const decorator of this.findDecoratorsOnNode(method, decoratorName, useMap, currentFilePath)) {
35
+ const arg = this.getDecoratorArg(decorator, 0);
36
+ const raw = this.extractExprValue(arg, useMap, currentFilePath, currentClass);
37
+
38
+ if (raw instanceof HandlerData) {
39
+ return raw;
40
+ }
41
+ }
42
+
43
+ return new HandlerData(currentClass, method.getName());
44
+ }
45
+
46
+ /**
47
+ * Return the name of the route handler decorator used by this reader.
48
+ */
49
+ protected abstract getRouteHandlerDecoratorName(): string;
50
+ }
@@ -0,0 +1,219 @@
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 { CliRouteData } from './Data/CliRouteData.ts';
14
+ import { CliRouteAttributeResult } from './Data/Result/CliRouteAttributeResult.ts';
15
+ import { CliRouteParameterReader } from './CliRouteParameterReader.ts';
16
+
17
+ import type { Decorator, MethodDeclaration } from 'ts-morph';
18
+
19
+ import type { CliRouteAttributeReaderContract } from './Contract/CliRouteAttributeReaderContract.ts';
20
+ import type { CliRouteParameterReaderContract } from './Contract/CliRouteParameterReaderContract.ts';
21
+
22
+ /**
23
+ * Scans a CLI controller class file for @Route and related sub-decorators and
24
+ * returns TypeScript compiler API Expr nodes ready for the data cache generator.
25
+ *
26
+ * Mirrors the logic of the framework's runtime attribute collector but operates
27
+ * entirely on AST without executing any TypeScript code.
28
+ */
29
+ export class CliRouteAttributeReader extends RouteAttributeReader implements CliRouteAttributeReaderContract {
30
+ constructor(protected readonly parameterReader: CliRouteParameterReaderContract = new CliRouteParameterReader()) {
31
+ super();
32
+ }
33
+
34
+ readFile(filePath: string): CliRouteAttributeResult {
35
+ const context = this.parseClassFile(filePath);
36
+
37
+ if (context === undefined) {
38
+ return new CliRouteAttributeResult();
39
+ }
40
+
41
+ const { classDecl, useMap, currentClass } = context;
42
+ const routes: Record<string, ts.Expression> = {};
43
+
44
+ for (const method of classDecl.getMethods()) {
45
+ for (const decorator of this.findDecoratorsOnNode(method, 'Route', useMap, filePath)) {
46
+ const data = this.buildRouteData(decorator, method, useMap, filePath, currentClass);
47
+
48
+ if (data !== null) {
49
+ routes[data.name] = this.buildRouteExpr(data);
50
+ }
51
+ }
52
+ }
53
+
54
+ return new CliRouteAttributeResult(routes);
55
+ }
56
+
57
+ protected getRouteHandlerDecoratorName(): string {
58
+ return 'RouteHandler';
59
+ }
60
+
61
+ protected buildRouteData(
62
+ decorator: Decorator,
63
+ method: MethodDeclaration,
64
+ useMap: Record<string, string>,
65
+ currentFilePath: string,
66
+ currentClass: string,
67
+ ): CliRouteData | null {
68
+ const name = this.extractStringArg(decorator, 0, useMap, currentFilePath, currentClass);
69
+ const description = this.extractStringArg(decorator, 1, useMap, currentFilePath, currentClass);
70
+
71
+ if (name === '' || description === '') {
72
+ return null;
73
+ }
74
+
75
+ const updatedName = this.updateName(name, method, useMap, currentFilePath, currentClass);
76
+ const [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware] =
77
+ this.updateMiddleware(
78
+ method,
79
+ useMap,
80
+ currentFilePath,
81
+ currentClass,
82
+ this.extractClassListArgFromDecorator(decorator, 4, useMap, currentFilePath, currentClass),
83
+ this.extractClassListArgFromDecorator(decorator, 5, useMap, currentFilePath, currentClass),
84
+ this.extractClassListArgFromDecorator(decorator, 6, useMap, currentFilePath, currentClass),
85
+ this.extractClassListArgFromDecorator(decorator, 7, useMap, currentFilePath, currentClass),
86
+ );
87
+
88
+ return new CliRouteData(
89
+ updatedName,
90
+ description,
91
+ this.updateHandler(method, useMap, currentFilePath, currentClass),
92
+ null,
93
+ routeMatchedMiddleware,
94
+ routeDispatchedMiddleware,
95
+ throwableCaughtMiddleware,
96
+ exitedMiddleware,
97
+ this.parameterReader.updateArguments(method, useMap, currentFilePath, currentClass),
98
+ this.parameterReader.updateOptions(method, useMap, currentFilePath, currentClass),
99
+ );
100
+ }
101
+
102
+ protected updateName(
103
+ name: string,
104
+ method: MethodDeclaration,
105
+ useMap: Record<string, string>,
106
+ currentFilePath: string,
107
+ currentClass: string,
108
+ ): string {
109
+ for (const decorator of this.findDecoratorsOnNode(method, 'Name', useMap, currentFilePath)) {
110
+ const override = this.extractExprValue(
111
+ this.getDecoratorArg(decorator, 0),
112
+ useMap,
113
+ currentFilePath,
114
+ currentClass,
115
+ );
116
+
117
+ if (typeof override === 'string' && override !== '') {
118
+ name = override;
119
+ }
120
+ }
121
+
122
+ return name;
123
+ }
124
+
125
+ protected updateMiddleware(
126
+ method: MethodDeclaration,
127
+ useMap: Record<string, string>,
128
+ currentFilePath: string,
129
+ currentClass: string,
130
+ routeMatchedMiddleware: string[],
131
+ routeDispatchedMiddleware: string[],
132
+ throwableCaughtMiddleware: string[],
133
+ exitedMiddleware: string[],
134
+ ): [string[], string[], string[], string[]] {
135
+ for (const decorator of this.findDecoratorsOnNode(method, 'Middleware', useMap, currentFilePath)) {
136
+ const mwName = this.extractExprValue(
137
+ this.getDecoratorArg(decorator, 0),
138
+ useMap,
139
+ currentFilePath,
140
+ currentClass,
141
+ );
142
+
143
+ if (typeof mwName !== 'string' || mwName === '') {
144
+ continue;
145
+ }
146
+
147
+ [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware] =
148
+ this.classifyMiddleware(
149
+ mwName,
150
+ useMap,
151
+ currentFilePath,
152
+ routeMatchedMiddleware,
153
+ routeDispatchedMiddleware,
154
+ throwableCaughtMiddleware,
155
+ exitedMiddleware,
156
+ );
157
+ }
158
+
159
+ return [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware];
160
+ }
161
+
162
+ protected classifyMiddleware(
163
+ mwName: string,
164
+ useMap: Record<string, string>,
165
+ currentFilePath: string,
166
+ routeMatchedMiddleware: string[],
167
+ routeDispatchedMiddleware: string[],
168
+ throwableCaughtMiddleware: string[],
169
+ exitedMiddleware: string[],
170
+ ): [string[], string[], string[], string[]] {
171
+ if (this.classImplementsInterface(mwName, 'RouteMatchedMiddlewareContract', useMap, currentFilePath)) {
172
+ routeMatchedMiddleware = [...routeMatchedMiddleware, mwName];
173
+ }
174
+
175
+ if (this.classImplementsInterface(mwName, 'RouteDispatchedMiddlewareContract', useMap, currentFilePath)) {
176
+ routeDispatchedMiddleware = [...routeDispatchedMiddleware, mwName];
177
+ }
178
+
179
+ if (this.classImplementsInterface(mwName, 'ThrowableCaughtMiddlewareContract', useMap, currentFilePath)) {
180
+ throwableCaughtMiddleware = [...throwableCaughtMiddleware, mwName];
181
+ }
182
+
183
+ if (this.classImplementsInterface(mwName, 'ExitedMiddlewareContract', useMap, currentFilePath)) {
184
+ exitedMiddleware = [...exitedMiddleware, mwName];
185
+ }
186
+
187
+ return [routeMatchedMiddleware, routeDispatchedMiddleware, throwableCaughtMiddleware, exitedMiddleware];
188
+ }
189
+
190
+ protected buildRouteExpr(data: CliRouteData): ts.Expression {
191
+ const args: ts.Expression[] = [this.buildEnumCaseExpr(data.name), this.buildStringExpr(data.description)];
192
+
193
+ if (data.handler !== null) {
194
+ args.push(this.buildHandlerExpr(data.handler));
195
+ } else {
196
+ args.push(this.buildNullExpr());
197
+ }
198
+
199
+ if (data.helpText !== null) {
200
+ args.push(this.buildHandlerExpr(data.helpText));
201
+ } else {
202
+ args.push(this.buildNullExpr());
203
+ }
204
+
205
+ args.push(...this.buildRouteMiddlewareArgs(data));
206
+ args.push(...this.parameterReader.buildParameterArgs(data));
207
+
208
+ return this.buildNewExpr('Valkyrja\\Cli\\Routing\\Data\\Route', args);
209
+ }
210
+
211
+ protected buildRouteMiddlewareArgs(data: CliRouteData): ts.Expression[] {
212
+ return [
213
+ this.buildClassArrayExpr(data.routeMatchedMiddleware),
214
+ this.buildClassArrayExpr(data.routeDispatchedMiddleware),
215
+ this.buildClassArrayExpr(data.throwableCaughtMiddleware),
216
+ this.buildClassArrayExpr(data.exitedMiddleware),
217
+ ];
218
+ }
219
+ }
@@ -0,0 +1,204 @@
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 { AstReader } from './Abstract/AstReader.ts';
13
+ import { CliArgumentParameterData } from './Data/CliArgumentParameterData.ts';
14
+ import { CliOptionParameterData } from './Data/CliOptionParameterData.ts';
15
+
16
+ import type { MethodDeclaration } from 'ts-morph';
17
+
18
+ import type { CliRouteData } from './Data/CliRouteData.ts';
19
+ import type { CliRouteParameterReaderContract } from './Contract/CliRouteParameterReaderContract.ts';
20
+
21
+ /**
22
+ * Builds AST expressions for CLI route argument and option parameters.
23
+ *
24
+ * Extracted from CliRouteAttributeReader to keep each class under the
25
+ * complexity threshold; injected as a constructor argument.
26
+ */
27
+ export class CliRouteParameterReader extends AstReader implements CliRouteParameterReaderContract {
28
+ buildParameterArgs(data: CliRouteData): ts.Expression[] {
29
+ const args: ts.Expression[] = [];
30
+
31
+ if (data.arguments.length > 0) {
32
+ args.push(this.buildArgumentListExpr(data.arguments));
33
+ }
34
+
35
+ if (data.options.length > 0) {
36
+ args.push(this.buildOptionListExpr(data.options));
37
+ }
38
+
39
+ return args;
40
+ }
41
+
42
+ updateArguments(
43
+ method: MethodDeclaration,
44
+ useMap: Record<string, string>,
45
+ namespace: string,
46
+ currentClass: string,
47
+ ): CliArgumentParameterData[] {
48
+ const arguments_: CliArgumentParameterData[] = [];
49
+
50
+ for (const decorator of this.findDecoratorsOnNode(method, 'ArgumentParameter', useMap, namespace)) {
51
+ const data = this.buildArgumentData(decorator, useMap, namespace, currentClass);
52
+
53
+ if (data !== null) {
54
+ arguments_.push(data);
55
+ }
56
+ }
57
+
58
+ return arguments_;
59
+ }
60
+
61
+ updateOptions(
62
+ method: MethodDeclaration,
63
+ useMap: Record<string, string>,
64
+ namespace: string,
65
+ currentClass: string,
66
+ ): CliOptionParameterData[] {
67
+ const options: CliOptionParameterData[] = [];
68
+
69
+ for (const decorator of this.findDecoratorsOnNode(method, 'OptionParameter', useMap, namespace)) {
70
+ const data = this.buildOptionData(decorator, useMap, namespace, currentClass);
71
+
72
+ if (data !== null) {
73
+ options.push(data);
74
+ }
75
+ }
76
+
77
+ return options;
78
+ }
79
+
80
+ protected buildArgumentData(
81
+ decorator: import('ts-morph').Decorator,
82
+ useMap: Record<string, string>,
83
+ currentFilePath: string,
84
+ currentClass: string,
85
+ ): CliArgumentParameterData | null {
86
+ const name = this.extractStringArg(decorator, 0, useMap, currentFilePath, currentClass);
87
+ const description = this.extractStringArg(decorator, 1, useMap, currentFilePath, currentClass);
88
+
89
+ if (name === '' || description === '') {
90
+ return null;
91
+ }
92
+
93
+ return new CliArgumentParameterData(
94
+ name,
95
+ description,
96
+ this.extractStringArg(decorator, 2, useMap, currentFilePath, currentClass) || null,
97
+ this.extractStringArg(
98
+ decorator,
99
+ 3,
100
+ useMap,
101
+ currentFilePath,
102
+ currentClass,
103
+ 'Valkyrja\\Cli\\Routing\\Enum\\ArgumentMode::OPTIONAL',
104
+ ),
105
+ this.extractStringArg(
106
+ decorator,
107
+ 4,
108
+ useMap,
109
+ currentFilePath,
110
+ currentClass,
111
+ 'Valkyrja\\Cli\\Routing\\Enum\\ArgumentValueMode::DEFAULT',
112
+ ),
113
+ );
114
+ }
115
+
116
+ protected buildOptionData(
117
+ decorator: import('ts-morph').Decorator,
118
+ useMap: Record<string, string>,
119
+ currentFilePath: string,
120
+ currentClass: string,
121
+ ): CliOptionParameterData | null {
122
+ const name = this.extractStringArg(decorator, 0, useMap, currentFilePath, currentClass);
123
+ const description = this.extractStringArg(decorator, 1, useMap, currentFilePath, currentClass);
124
+
125
+ if (name === '' || description === '') {
126
+ return null;
127
+ }
128
+
129
+ return new CliOptionParameterData(
130
+ name,
131
+ description,
132
+ this.extractStringArg(decorator, 2, useMap, currentFilePath, currentClass),
133
+ this.extractStringArg(decorator, 3, useMap, currentFilePath, currentClass) || null,
134
+ this.extractStringArg(decorator, 4, useMap, currentFilePath, currentClass),
135
+ this.extractStringListArgFromDecorator(decorator, 5, useMap, currentFilePath, currentClass),
136
+ this.extractStringListArgFromDecorator(decorator, 6, useMap, currentFilePath, currentClass),
137
+ this.extractStringArg(
138
+ decorator,
139
+ 7,
140
+ useMap,
141
+ currentFilePath,
142
+ currentClass,
143
+ 'Valkyrja\\Cli\\Routing\\Enum\\OptionMode::OPTIONAL',
144
+ ),
145
+ this.extractStringArg(
146
+ decorator,
147
+ 8,
148
+ useMap,
149
+ currentFilePath,
150
+ currentClass,
151
+ 'Valkyrja\\Cli\\Routing\\Enum\\OptionValueMode::DEFAULT',
152
+ ),
153
+ );
154
+ }
155
+
156
+ protected buildArgumentListExpr(arguments_: readonly CliArgumentParameterData[]): ts.ArrayLiteralExpression {
157
+ const elements = arguments_.map((a) => this.buildArgumentExpr(a));
158
+ return ts.factory.createArrayLiteralExpression(elements);
159
+ }
160
+
161
+ protected buildArgumentExpr(data: CliArgumentParameterData): ts.Expression {
162
+ const args: ts.Expression[] = [
163
+ this.buildStringExpr(data.name),
164
+ this.buildStringExpr(data.description),
165
+ data.cast !== null ? this.buildEnumCaseExpr(data.cast) : this.buildNullExpr(),
166
+ this.buildEnumCaseExpr(data.mode),
167
+ this.buildEnumCaseExpr(data.valueMode),
168
+ ];
169
+
170
+ return this.buildNewExpr('Valkyrja\\Cli\\Routing\\Data\\ArgumentParameter', args);
171
+ }
172
+
173
+ protected buildOptionListExpr(options: readonly CliOptionParameterData[]): ts.ArrayLiteralExpression {
174
+ const elements = options.map((o) => this.buildOptionExpr(o));
175
+ return ts.factory.createArrayLiteralExpression(elements);
176
+ }
177
+
178
+ protected buildOptionExpr(data: CliOptionParameterData): ts.Expression {
179
+ const args: ts.Expression[] = [
180
+ this.buildStringExpr(data.name),
181
+ this.buildStringExpr(data.description),
182
+ this.buildStringExpr(data.valueDisplayName),
183
+ data.cast !== null ? this.buildEnumCaseExpr(data.cast) : this.buildNullExpr(),
184
+ this.buildStringExpr(data.defaultValue),
185
+ ];
186
+
187
+ if (data.shortNames.length > 0) {
188
+ args.push(this.buildStringArrayExpr(data.shortNames));
189
+ } else {
190
+ args.push(ts.factory.createArrayLiteralExpression([]));
191
+ }
192
+
193
+ if (data.validValues.length > 0) {
194
+ args.push(this.buildStringArrayExpr(data.validValues));
195
+ } else {
196
+ args.push(ts.factory.createArrayLiteralExpression([]));
197
+ }
198
+
199
+ args.push(this.buildEnumCaseExpr(data.mode));
200
+ args.push(this.buildEnumCaseExpr(data.valueMode));
201
+
202
+ return this.buildNewExpr('Valkyrja\\Cli\\Routing\\Data\\OptionParameter', args);
203
+ }
204
+ }
@@ -0,0 +1,41 @@
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 { AstReader } from './Abstract/AstReader.ts';
11
+ import { ComponentProviderResult } from './Data/Result/ComponentProviderResult.ts';
12
+
13
+ import type { ComponentProviderReaderContract } from './Contract/ComponentProviderReaderContract.ts';
14
+
15
+ export class ComponentProviderReader extends AstReader implements ComponentProviderReaderContract {
16
+ protected static readonly METHOD_COMPONENT = 'getComponentProviders';
17
+ protected static readonly METHOD_CONTAINER = 'getContainerProviders';
18
+ protected static readonly METHOD_EVENT = 'getEventProviders';
19
+ protected static readonly METHOD_CLI = 'getCliProviders';
20
+ protected static readonly METHOD_HTTP = 'getHttpProviders';
21
+
22
+ readFile(filePath: string): ComponentProviderResult {
23
+ const sourceFile = this.parseFileToSourceFile(filePath);
24
+ const classDecl = this.findClass(sourceFile);
25
+
26
+ if (classDecl === undefined) {
27
+ return new ComponentProviderResult();
28
+ }
29
+
30
+ const useMap = this.buildUseMap(sourceFile);
31
+ const methods = this.indexMethods(classDecl);
32
+
33
+ return new ComponentProviderResult(
34
+ this.extractClassListFromValues(methods[ComponentProviderReader.METHOD_COMPONENT], useMap, filePath),
35
+ this.extractClassListFromValues(methods[ComponentProviderReader.METHOD_CONTAINER], useMap, filePath),
36
+ this.extractClassListFromValues(methods[ComponentProviderReader.METHOD_EVENT], useMap, filePath),
37
+ this.extractClassListFromValues(methods[ComponentProviderReader.METHOD_CLI], useMap, filePath),
38
+ this.extractClassListFromValues(methods[ComponentProviderReader.METHOD_HTTP], useMap, filePath),
39
+ );
40
+ }
41
+ }