@spine-event-engine/proto-tools 2.0.0-snapshot.10 → 2.0.0-snapshot.11
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/README.md +2 -0
- package/dist/src/generation/build-time-handler-analyzer.d.ts +28 -6
- package/dist/src/generation/build-time-handler-analyzer.d.ts.map +1 -1
- package/dist/src/generation/build-time-handler-analyzer.js +230 -57
- package/dist/src/generation/build-time-handler-analyzer.js.map +1 -1
- package/dist/src/generation/generated-registry-writer.d.ts.map +1 -1
- package/dist/src/generation/generated-registry-writer.js +78 -47
- package/dist/src/generation/generated-registry-writer.js.map +1 -1
- package/dist/src/generation/rejection-generator.d.ts +1 -0
- package/dist/src/generation/rejection-generator.d.ts.map +1 -1
- package/dist/src/generation/rejection-generator.js +14 -11
- package/dist/src/generation/rejection-generator.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -80,6 +80,8 @@ the generated handler registry for decorated application classes. Its emitted
|
|
|
80
80
|
source imports the Server handler-registry contract as a type from
|
|
81
81
|
`@spine-event-engine/server/spi/handler-registry`; the CLI itself has no Server
|
|
82
82
|
runtime dependency. Run both after the related model or handler changes.
|
|
83
|
+
The handler analyzer records `@Throws(...)` declarations as rejection outcomes;
|
|
84
|
+
the generated rejection companion supplies the schema used by that metadata.
|
|
83
85
|
|
|
84
86
|
The public CLI is `spine-proto`. Programmatic config and manifest readers are
|
|
85
87
|
for build tooling that needs the same validated package contracts; application
|
|
@@ -100,24 +100,46 @@ export interface BuildHandlerRecord {
|
|
|
100
100
|
/**
|
|
101
101
|
* Generated schema accepted by the first handler parameter.
|
|
102
102
|
*/
|
|
103
|
-
readonly
|
|
103
|
+
readonly input: BuildHandlerInput;
|
|
104
104
|
/**
|
|
105
|
-
* Generated schemas
|
|
105
|
+
* Generated schemas returned normally or declared as thrown rejections.
|
|
106
106
|
*/
|
|
107
|
-
readonly
|
|
107
|
+
readonly outcomes: BuildHandlerOutcomes;
|
|
108
108
|
/**
|
|
109
109
|
* Public method arity: `handler(signal)` or `handler(signal, context)`.
|
|
110
110
|
*/
|
|
111
111
|
readonly parameterCount: GeneratedHandlerParameterCount;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Input metadata for one generated handler.
|
|
115
|
+
*/
|
|
116
|
+
export interface BuildHandlerInput {
|
|
112
117
|
/**
|
|
113
|
-
*
|
|
118
|
+
* Generated schema accepted by the handler.
|
|
119
|
+
*/
|
|
120
|
+
readonly schema: SchemaReference;
|
|
121
|
+
/**
|
|
122
|
+
* Origin required for an Event input.
|
|
114
123
|
*/
|
|
115
124
|
readonly origin: "domestic" | "external";
|
|
116
125
|
/**
|
|
117
|
-
* Optional
|
|
126
|
+
* Optional generated Event field filter.
|
|
118
127
|
*/
|
|
119
128
|
readonly where?: BuildWhereOptions;
|
|
120
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Normal and declared rejection outcomes for one generated handler.
|
|
132
|
+
*/
|
|
133
|
+
export interface BuildHandlerOutcomes {
|
|
134
|
+
/**
|
|
135
|
+
* Generated schemas returned normally by the handler.
|
|
136
|
+
*/
|
|
137
|
+
readonly returned: readonly SchemaReference[];
|
|
138
|
+
/**
|
|
139
|
+
* Generated rejection schemas that the handler may throw.
|
|
140
|
+
*/
|
|
141
|
+
readonly thrown: readonly SchemaReference[];
|
|
142
|
+
}
|
|
121
143
|
/**
|
|
122
144
|
* Build-time representation of one `@Where` declaration.
|
|
123
145
|
*/
|
|
@@ -134,7 +156,7 @@ export interface BuildWhereOptions {
|
|
|
134
156
|
/**
|
|
135
157
|
* Stable diagnostic codes emitted by build-time handler analysis.
|
|
136
158
|
*/
|
|
137
|
-
export type BuildHandlerDiagnosticCode = "APPLY_DECORATOR" | "FRAMEWORK_ENVELOPE_RETURN" | "INVALID_EMITTED_SCHEMA" | "INVALID_HANDLER_NAME" | "INVALID_HANDLER_CONTEXT" | "INVALID_HANDLER_VISIBILITY" | "INVALID_PARAMETER_COUNT" | "INVALID_SIGNAL_TYPE" | "INVALID_EXTERNAL_ORIGIN" | "EXTERNAL_COMMAND_RECEIVER" | "INVALID_SUBSCRIBE_RETURN" | "INVALID_WHERE" | "MISSING_EMITTED_SCHEMAS" | "MISSING_ENTITY_STATE_SCHEMA" | "MISSING_RETURN_TYPE" | "MISSING_SIGNAL_TYPE" | "NON_EXPORTED_RECEIVER_CLASS" | "SCHEMA_BEARING_DECORATOR" | "TYPESCRIPT_SYNTAX_ERROR" | "UNSUPPORTED_COMMAND_HANDLER" | "UNSUPPORTED_RETURN_TYPE";
|
|
159
|
+
export type BuildHandlerDiagnosticCode = "APPLY_DECORATOR" | "FRAMEWORK_ENVELOPE_RETURN" | "INVALID_EMITTED_SCHEMA" | "INVALID_HANDLER_NAME" | "INVALID_HANDLER_CONTEXT" | "INVALID_HANDLER_VISIBILITY" | "INVALID_PARAMETER_COUNT" | "INVALID_SIGNAL_TYPE" | "INVALID_EXTERNAL_ORIGIN" | "EXTERNAL_COMMAND_RECEIVER" | "INVALID_SUBSCRIBE_RETURN" | "INVALID_THROWS" | "INVALID_WHERE" | "MISSING_EMITTED_SCHEMAS" | "MISSING_ENTITY_STATE_SCHEMA" | "MISSING_RETURN_TYPE" | "MISSING_SIGNAL_TYPE" | "NON_EXPORTED_RECEIVER_CLASS" | "SCHEMA_BEARING_DECORATOR" | "TYPESCRIPT_SYNTAX_ERROR" | "UNSUPPORTED_ASSIGN_HANDLER" | "UNSUPPORTED_COMMAND_HANDLER" | "UNSUPPORTED_RETURN_TYPE";
|
|
138
160
|
/**
|
|
139
161
|
* One build-time analyzer diagnostic.
|
|
140
162
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-time-handler-analyzer.d.ts","sourceRoot":"","sources":["../../../src/generation/build-time-handler-analyzer.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,KAAK,oBAAoB,GACrB,oBAAoB,GACpB,sBAAsB,GACtB,kBAAkB,GAClB,oBAAoB,GACpB,oBAAoB,GACpB,gBAAgB,CAAC;AACrB,KAAK,8BAA8B,GAAG,CAAC,GAAG,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,oBAAoB;IAGnC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAErD;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAGlC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC;IAEhC;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC;IAEtC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IAGtC;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IAEjC;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAClD;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,mBAAmB,GAAG,uBAAuB,CAAC;AAElF;;GAEG;AACH,MAAM,WAAW,eAAe;IAG9B;;OAEG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAEjC;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAGjC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"build-time-handler-analyzer.d.ts","sourceRoot":"","sources":["../../../src/generation/build-time-handler-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -89,23 +89,26 @@ const HandlerSources = Object.freeze({
|
|
|
89
89
|
return undefined;
|
|
90
90
|
}
|
|
91
91
|
const lineage = HandlerSources.receiverLineage(node, scope);
|
|
92
|
-
const
|
|
93
|
-
|
|
92
|
+
const handlers = HandlerSources.analyzeMethods(node, className, lineage, scope);
|
|
93
|
+
if (lineage === undefined || handlers.length === 0) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return HandlerSources.receiverRecord(node, className, lineage, handlers, scope.source.fileName);
|
|
97
|
+
},
|
|
98
|
+
analyzeMethods(node, className, lineage, scope) {
|
|
94
99
|
const handlers = [];
|
|
95
100
|
for (const member of node.members) {
|
|
96
|
-
if (!ts.isMethodDeclaration(member))
|
|
101
|
+
if (!ts.isMethodDeclaration(member))
|
|
97
102
|
continue;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (handler !== undefined) {
|
|
103
|
+
const handler = HandlerSources.analyzeMethod(member, className, lineage?.base, lineage?.stateSchema, lineage?.receiverKind, scope);
|
|
104
|
+
if (handler !== undefined)
|
|
101
105
|
handlers.push(handler);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (lineage === undefined || handlers.length === 0) {
|
|
105
|
-
return undefined;
|
|
106
106
|
}
|
|
107
|
+
return handlers;
|
|
108
|
+
},
|
|
109
|
+
receiverRecord(node, className, lineage, handlers, sourceFile) {
|
|
107
110
|
return lineage.receiverKind === "entity"
|
|
108
|
-
? stateSchema === undefined
|
|
111
|
+
? lineage.stateSchema === undefined
|
|
109
112
|
? undefined
|
|
110
113
|
: {
|
|
111
114
|
receiverKind: "entity",
|
|
@@ -113,8 +116,8 @@ const HandlerSources = Object.freeze({
|
|
|
113
116
|
...(HandlerTypes.hasModifier(node, ts.SyntaxKind.DefaultKeyword)
|
|
114
117
|
? { defaultExport: true }
|
|
115
118
|
: {}),
|
|
116
|
-
sourceFile
|
|
117
|
-
stateSchema,
|
|
119
|
+
sourceFile,
|
|
120
|
+
stateSchema: lineage.stateSchema,
|
|
118
121
|
handlers,
|
|
119
122
|
}
|
|
120
123
|
: {
|
|
@@ -123,7 +126,7 @@ const HandlerSources = Object.freeze({
|
|
|
123
126
|
...(HandlerTypes.hasModifier(node, ts.SyntaxKind.DefaultKeyword)
|
|
124
127
|
? { defaultExport: true }
|
|
125
128
|
: {}),
|
|
126
|
-
sourceFile
|
|
129
|
+
sourceFile,
|
|
127
130
|
handlers,
|
|
128
131
|
};
|
|
129
132
|
},
|
|
@@ -132,58 +135,171 @@ const HandlerSources = Object.freeze({
|
|
|
132
135
|
const apply = decorators.find((decorator) => decorator.name === "Apply");
|
|
133
136
|
const handler = decorators.find(HandlerSources.isHandlerUse);
|
|
134
137
|
const whereUses = decorators.filter((decorator) => decorator.name === "Where");
|
|
135
|
-
|
|
136
|
-
HandlerTypes.pushDiagnostic(scope, "APPLY_DECORATOR", apply.node, "Generated registries do not support @Apply.", className, HandlerTypes.methodName(node));
|
|
137
|
-
}
|
|
138
|
-
if (handler === undefined) {
|
|
139
|
-
if (whereUses.length > 0) {
|
|
140
|
-
HandlerTypes.pushDiagnostic(scope, "INVALID_WHERE", whereUses[0]?.node ?? node, "@Where requires an Event-consuming @Subscribe, @React, or @Command handler.", className, HandlerTypes.methodName(node));
|
|
141
|
-
}
|
|
142
|
-
return undefined;
|
|
143
|
-
}
|
|
138
|
+
const throwsUses = decorators.filter((decorator) => decorator.name === "Throws");
|
|
144
139
|
const method = HandlerTypes.methodName(node);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (invalid) {
|
|
140
|
+
const use = {
|
|
141
|
+
node,
|
|
142
|
+
apply,
|
|
143
|
+
handler,
|
|
144
|
+
whereUses,
|
|
145
|
+
throwsUses,
|
|
146
|
+
className,
|
|
147
|
+
entityBase,
|
|
148
|
+
stateSchema,
|
|
149
|
+
receiverKind,
|
|
150
|
+
scope,
|
|
151
|
+
method,
|
|
152
|
+
};
|
|
153
|
+
if (!HandlerSources.validMethodUse(use))
|
|
160
154
|
return undefined;
|
|
161
|
-
|
|
162
|
-
|
|
155
|
+
return HandlerSources.analyzeValidMethod(use);
|
|
156
|
+
},
|
|
157
|
+
analyzeValidMethod(input) {
|
|
158
|
+
const { className, handler, method, node, scope } = input;
|
|
159
|
+
const parameters = node.parameters;
|
|
160
|
+
const origin = HandlerSources.externalOrigin(parameters, scope, className, method);
|
|
163
161
|
if (origin === undefined)
|
|
164
162
|
return undefined;
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
if (signal === undefined || emittedSchemas === undefined || method === undefined) {
|
|
163
|
+
const schemas = HandlerSources.methodSchemaUses(node, handler, origin.type, scope);
|
|
164
|
+
if (schemas === undefined || method === undefined)
|
|
168
165
|
return undefined;
|
|
169
|
-
}
|
|
170
|
-
if (!HandlerSources.validContextParameter(
|
|
166
|
+
const { signal, returnedSchemas } = schemas;
|
|
167
|
+
if (!HandlerSources.validContextParameter(parameters, signal.kind, scope, className, method))
|
|
171
168
|
return undefined;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (whereUses.length > 0 && where === undefined) {
|
|
169
|
+
const declarations = HandlerSources.methodDeclarations(input, signal.kind, method);
|
|
170
|
+
if (declarations === undefined)
|
|
175
171
|
return undefined;
|
|
176
|
-
|
|
172
|
+
return HandlerSources.buildHandlerRecord(node, handler, signal, method, returnedSchemas, declarations.thrown, origin.value, declarations.where);
|
|
173
|
+
},
|
|
174
|
+
methodDeclarations(input, signalKind, methodName) {
|
|
175
|
+
const { className, handler, scope, throwsUses, whereUses } = input;
|
|
176
|
+
const where = HandlerSources.whereDeclaration(whereUses, handler, signalKind, scope, className, methodName);
|
|
177
|
+
if (whereUses.length > 0 && where === undefined)
|
|
178
|
+
return undefined;
|
|
179
|
+
const thrown = HandlerSources.throwsDeclaration(throwsUses, handler, signalKind, scope, className, methodName);
|
|
180
|
+
return throwsUses.length > 0 && thrown === undefined
|
|
181
|
+
? undefined
|
|
182
|
+
: { where, thrown: thrown ?? [] };
|
|
183
|
+
},
|
|
184
|
+
methodSchemaUses(node, handler, signalType, scope) {
|
|
185
|
+
const signal = HandlerSources.schemaUseFromType(signalType, scope.imports);
|
|
186
|
+
const returned = HandlerSources.emittedSchemaUses(node.type === undefined ? undefined : HandlerSources.unwrapOuterPromise(node.type, scope), handler.name, scope.imports);
|
|
187
|
+
return signal === undefined || returned === undefined
|
|
188
|
+
? undefined
|
|
189
|
+
: { signal, returnedSchemas: returned.map((schema) => schema.reference) };
|
|
190
|
+
},
|
|
191
|
+
buildHandlerRecord(node, handler, signal, method, returnedSchemas, thrownSchemas, origin, where) {
|
|
177
192
|
return {
|
|
178
193
|
kind: HandlerSources.handlerKind(handler.name, signal.kind),
|
|
179
194
|
methodName: method,
|
|
180
|
-
|
|
181
|
-
|
|
195
|
+
input: { schema: signal.reference, origin, ...(where === undefined ? {} : { where }) },
|
|
196
|
+
outcomes: { returned: returnedSchemas, thrown: thrownSchemas },
|
|
182
197
|
parameterCount: node.parameters.length,
|
|
183
|
-
origin: origin.value,
|
|
184
|
-
...(where === undefined ? {} : { where }),
|
|
185
198
|
};
|
|
186
199
|
},
|
|
200
|
+
validMethodUse(input) {
|
|
201
|
+
HandlerSources.reportUnsupportedApply(input);
|
|
202
|
+
if (input.handler === undefined)
|
|
203
|
+
return HandlerSources.reportMissingHandler(input);
|
|
204
|
+
const { className, handler, method, node, scope } = input;
|
|
205
|
+
if (!HandlerSources.validHandlerKind({ ...input, handler }))
|
|
206
|
+
return false;
|
|
207
|
+
if (!HandlerSources.validBareHandlerDecorator(handler, scope, className, method))
|
|
208
|
+
return false;
|
|
209
|
+
return !HandlerSources.validateHandlerNode(node, handler.name, input.receiverKind === "entity" ? input.stateSchema : undefined, input.receiverKind !== "standalone", scope, className, method);
|
|
210
|
+
},
|
|
211
|
+
throwsDeclaration(uses, handler, signalKind, scope, className, methodName) {
|
|
212
|
+
if (uses.length === 0)
|
|
213
|
+
return [];
|
|
214
|
+
const expression = HandlerSources.throwsCall(uses, handler, signalKind, scope, className, methodName);
|
|
215
|
+
if (expression === undefined)
|
|
216
|
+
return undefined;
|
|
217
|
+
return HandlerSources.thrownSchemas(expression, scope, className, methodName);
|
|
218
|
+
},
|
|
219
|
+
throwsCall(uses, handler, signalKind, scope, className, methodName) {
|
|
220
|
+
const use = uses[0];
|
|
221
|
+
const commandReceptor = handler.name === "Assign" || (handler.name === "Command" && signalKind === "command");
|
|
222
|
+
if (uses.length !== 1 || !commandReceptor || use === undefined) {
|
|
223
|
+
HandlerSources.invalidThrows(scope, use?.node ?? handler.node, "@Throws is allowed once on a command-accepting @Assign or @Command handler.", className, methodName);
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
const expression = use.node.expression;
|
|
227
|
+
if (ts.isCallExpression(expression) && expression.arguments.length > 0)
|
|
228
|
+
return expression;
|
|
229
|
+
HandlerSources.invalidThrows(scope, use.node, "@Throws requires at least one generated rejection companion.", className, methodName);
|
|
230
|
+
return undefined;
|
|
231
|
+
},
|
|
232
|
+
thrownSchemas(expression, scope, className, methodName) {
|
|
233
|
+
const schemas = expression.arguments.map((argument) => HandlerSources.rejectionSchemaFromExpression(argument, scope.imports));
|
|
234
|
+
if (schemas.some((schema) => schema === undefined)) {
|
|
235
|
+
HandlerSources.invalidThrows(scope, expression, "@Throws accepts only generated rejection companions.", className, methodName);
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
const resolved = schemas;
|
|
239
|
+
const keys = resolved.map((schema) => `${schema.moduleSpecifier}\u0000${schema.exportName}`);
|
|
240
|
+
if (new Set(keys).size !== keys.length) {
|
|
241
|
+
HandlerSources.invalidThrows(scope, expression, "@Throws cannot declare the same rejection more than once.", className, methodName);
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
return resolved;
|
|
245
|
+
},
|
|
246
|
+
invalidThrows(scope, node, message, className, methodName) {
|
|
247
|
+
HandlerTypes.pushDiagnostic(scope, "INVALID_THROWS", node, message, className, methodName);
|
|
248
|
+
return undefined;
|
|
249
|
+
},
|
|
250
|
+
rejectionSchemaFromExpression(expression, imports) {
|
|
251
|
+
const unwrapped = HandlerSources.unwrapExpression(expression);
|
|
252
|
+
if (ts.isIdentifier(unwrapped))
|
|
253
|
+
return imports.rejectionSymbols.get(unwrapped.text);
|
|
254
|
+
if (!ts.isPropertyAccessExpression(unwrapped) || !ts.isIdentifier(unwrapped.expression)) {
|
|
255
|
+
return undefined;
|
|
256
|
+
}
|
|
257
|
+
const namespace = imports.rejectionNamespaces.get(unwrapped.expression.text);
|
|
258
|
+
const schemaName = `${unwrapped.name.text}Schema`;
|
|
259
|
+
return namespace?.exports.schemaRoles.get(schemaName) !== "rejection"
|
|
260
|
+
? undefined
|
|
261
|
+
: { moduleSpecifier: namespace.moduleSpecifier, exportName: schemaName };
|
|
262
|
+
},
|
|
263
|
+
reportUnsupportedApply(input) {
|
|
264
|
+
if (input.apply === undefined)
|
|
265
|
+
return;
|
|
266
|
+
HandlerTypes.pushDiagnostic(input.scope, "APPLY_DECORATOR", input.apply.node, "Generated registries do not support @Apply.", input.className, input.method);
|
|
267
|
+
},
|
|
268
|
+
reportMissingHandler(input) {
|
|
269
|
+
if (input.whereUses.length > 0)
|
|
270
|
+
HandlerTypes.pushDiagnostic(input.scope, "INVALID_WHERE", input.whereUses[0]?.node ?? input.node, "@Where requires an Event-consuming @Subscribe, @React, or @Command handler.", input.className, input.method);
|
|
271
|
+
if (input.throwsUses.length > 0)
|
|
272
|
+
HandlerTypes.pushDiagnostic(input.scope, "INVALID_THROWS", input.throwsUses[0]?.node ?? input.node, "@Throws requires an @Assign handler.", input.className, input.method);
|
|
273
|
+
return false;
|
|
274
|
+
},
|
|
275
|
+
validBareHandlerDecorator(handler, scope, className, method) {
|
|
276
|
+
if (!handler.hasArguments)
|
|
277
|
+
return true;
|
|
278
|
+
HandlerTypes.pushDiagnostic(scope, "SCHEMA_BEARING_DECORATOR", handler.node, `@${handler.name}(...) is not supported in analyzed app source.`, className, method);
|
|
279
|
+
return false;
|
|
280
|
+
},
|
|
281
|
+
validHandlerKind(input) {
|
|
282
|
+
return (HandlerSources.validEntityHandlerKind(input) &&
|
|
283
|
+
HandlerSources.validStandaloneHandlerKind(input));
|
|
284
|
+
},
|
|
285
|
+
validEntityHandlerKind(input) {
|
|
286
|
+
const { className, entityBase, handler, method, scope } = input;
|
|
287
|
+
if (entityBase === "Projection" && handler.name === "Assign")
|
|
288
|
+
return HandlerSources.unsupported(scope, "UNSUPPORTED_ASSIGN_HANDLER", handler.node, "Projection handlers cannot use @Assign.", className, method);
|
|
289
|
+
return ((entityBase !== "Aggregate" && entityBase !== "Projection") ||
|
|
290
|
+
handler.name !== "Command" ||
|
|
291
|
+
HandlerSources.unsupported(scope, "UNSUPPORTED_COMMAND_HANDLER", handler.node, "Only Process Managers support @Command handlers.", className, method));
|
|
292
|
+
},
|
|
293
|
+
validStandaloneHandlerKind(input) {
|
|
294
|
+
const { className, entityBase, handler, method, receiverKind, scope } = input;
|
|
295
|
+
return (receiverKind !== "standalone" ||
|
|
296
|
+
HandlerSources.allowsStandaloneDecorator(entityBase, handler.name) ||
|
|
297
|
+
HandlerSources.unsupported(scope, "UNSUPPORTED_COMMAND_HANDLER", handler.node, `@${handler.name} is not legal for standalone ${entityBase ?? "receiver"}.`, className, method));
|
|
298
|
+
},
|
|
299
|
+
unsupported(scope, code, node, message, className, method) {
|
|
300
|
+
HandlerTypes.pushDiagnostic(scope, code, node, message, className, method);
|
|
301
|
+
return false;
|
|
302
|
+
},
|
|
187
303
|
whereDeclaration(uses, handler, signalKind, scope, className, methodName) {
|
|
188
304
|
if (uses.length === 0)
|
|
189
305
|
return undefined;
|
|
@@ -839,6 +955,8 @@ const HandlerSources = Object.freeze({
|
|
|
839
955
|
const state = {
|
|
840
956
|
generatedNamespaces: new Map(),
|
|
841
957
|
generatedSymbols: new Map(),
|
|
958
|
+
rejectionNamespaces: new Map(),
|
|
959
|
+
rejectionSymbols: new Map(),
|
|
842
960
|
localTypeAliases: new Map(),
|
|
843
961
|
serverNamespaces: new Set(),
|
|
844
962
|
serverSymbols: new Map(),
|
|
@@ -861,18 +979,64 @@ const HandlerSources = Object.freeze({
|
|
|
861
979
|
},
|
|
862
980
|
recordImportDeclaration(statement, moduleSpecifier, source, program, state) {
|
|
863
981
|
const bindings = statement.importClause?.namedBindings;
|
|
864
|
-
if (bindings === undefined)
|
|
982
|
+
if (bindings === undefined)
|
|
865
983
|
return;
|
|
984
|
+
HandlerSources.recordFrameworkImport(bindings, moduleSpecifier, state);
|
|
985
|
+
if (HandlerSources.isGeneratedModule(moduleSpecifier)) {
|
|
986
|
+
HandlerSources.recordGeneratedImport(bindings, moduleSpecifier, statement.importClause?.phaseModifier !== ts.SyntaxKind.TypeKeyword, source, program, state);
|
|
866
987
|
}
|
|
988
|
+
if (!HandlerSources.isRejectionCompanion(moduleSpecifier))
|
|
989
|
+
return;
|
|
990
|
+
HandlerSources.recordRejectionCompanionImport(bindings, moduleSpecifier, source, program, state);
|
|
991
|
+
},
|
|
992
|
+
recordFrameworkImport(bindings, moduleSpecifier, state) {
|
|
867
993
|
if (moduleSpecifier === "@spine-event-engine/server") {
|
|
868
994
|
HandlerSources.recordServerImport(bindings, state);
|
|
869
995
|
}
|
|
870
996
|
if (moduleSpecifier === "@spine-event-engine/proto") {
|
|
871
997
|
HandlerSources.recordProtoImport(bindings, state);
|
|
872
998
|
}
|
|
873
|
-
|
|
874
|
-
|
|
999
|
+
},
|
|
1000
|
+
recordRejectionCompanionImport(bindings, moduleSpecifier, source, program, state) {
|
|
1001
|
+
const schemaModule = HandlerSources.rejectionSchemaModule(moduleSpecifier);
|
|
1002
|
+
const companion = HandlerSources.generatedModuleSource(source, moduleSpecifier, program);
|
|
1003
|
+
const companionSchemaModule = companion === undefined ? undefined : HandlerSources.rejectionSchemaImport(companion);
|
|
1004
|
+
const exported = HandlerSources.generatedModuleExports(companion ?? source, companionSchemaModule ?? schemaModule, program);
|
|
1005
|
+
if (exported === undefined)
|
|
1006
|
+
return;
|
|
1007
|
+
if (ts.isNamespaceImport(bindings)) {
|
|
1008
|
+
state.rejectionNamespaces.set(bindings.name.text, {
|
|
1009
|
+
exports: exported,
|
|
1010
|
+
moduleSpecifier: schemaModule,
|
|
1011
|
+
});
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
for (const element of bindings.elements) {
|
|
1015
|
+
if (element.isTypeOnly)
|
|
1016
|
+
continue;
|
|
1017
|
+
const exportName = element.propertyName?.text ?? element.name.text;
|
|
1018
|
+
const schemaName = `${exportName}Schema`;
|
|
1019
|
+
if (exported.schemaRoles.get(schemaName) !== "rejection")
|
|
1020
|
+
continue;
|
|
1021
|
+
state.rejectionSymbols.set(element.name.text, {
|
|
1022
|
+
moduleSpecifier: schemaModule,
|
|
1023
|
+
exportName: schemaName,
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
},
|
|
1027
|
+
rejectionSchemaImport(source) {
|
|
1028
|
+
for (const statement of source.statements) {
|
|
1029
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
const bindings = statement.importClause?.namedBindings;
|
|
1033
|
+
if (bindings !== undefined &&
|
|
1034
|
+
!ts.isNamespaceImport(bindings) &&
|
|
1035
|
+
bindings.elements.some((element) => (element.propertyName?.text ?? element.name.text).endsWith("Schema"))) {
|
|
1036
|
+
return statement.moduleSpecifier.text;
|
|
1037
|
+
}
|
|
875
1038
|
}
|
|
1039
|
+
return undefined;
|
|
876
1040
|
},
|
|
877
1041
|
recordServerImport(bindings, state) {
|
|
878
1042
|
if (ts.isNamespaceImport(bindings)) {
|
|
@@ -926,6 +1090,14 @@ const HandlerSources = Object.freeze({
|
|
|
926
1090
|
isGeneratedModule(moduleSpecifier) {
|
|
927
1091
|
return /(^|\/)generated\/.+_pb(\.js)?$/.test(moduleSpecifier);
|
|
928
1092
|
},
|
|
1093
|
+
isRejectionCompanion(moduleSpecifier) {
|
|
1094
|
+
return /(^|\/)generated\/(?:.+\/)?(?:[^/]+_)?rejections(\.js)?$/u.test(moduleSpecifier);
|
|
1095
|
+
},
|
|
1096
|
+
rejectionSchemaModule(moduleSpecifier) {
|
|
1097
|
+
return moduleSpecifier.endsWith(".js")
|
|
1098
|
+
? moduleSpecifier.replace(/\.js$/u, "_pb.js")
|
|
1099
|
+
: `${moduleSpecifier}_pb`;
|
|
1100
|
+
},
|
|
929
1101
|
generatedModuleExports(source, moduleSpecifier, program) {
|
|
930
1102
|
const module = HandlerSources.generatedModuleSource(source, moduleSpecifier, program);
|
|
931
1103
|
if (module === undefined)
|
|
@@ -1255,7 +1427,8 @@ const HandlerTypes = Object.freeze({
|
|
|
1255
1427
|
name === "React" ||
|
|
1256
1428
|
name === "Subscribe" ||
|
|
1257
1429
|
name === "Apply" ||
|
|
1258
|
-
name === "Where"
|
|
1430
|
+
name === "Where" ||
|
|
1431
|
+
name === "Throws"
|
|
1259
1432
|
? name
|
|
1260
1433
|
: undefined;
|
|
1261
1434
|
},
|