diff --git a/src/compiler/transformers/decorators-to-static/event-decorator.ts b/src/compiler/transformers/decorators-to-static/event-decorator.ts index 3a51cf717c5..9a9c46693f3 100644 --- a/src/compiler/transformers/decorators-to-static/event-decorator.ts +++ b/src/compiler/transformers/decorators-to-static/event-decorator.ts @@ -27,12 +27,22 @@ export const eventDecoratorsToStatic = ( } }; +/** + * Parse a single instance of Stencil's `@Event()` decorator and generate metadata for the class member that is + * decorated + * @param diagnostics a list of diagnostics used as a part of the parsing process. Any parse errors/warnings shall be + * added to this collection + * @param typeChecker an instance of the TypeScript type checker, used to generate information about the `@Event()` and + * its surrounding context in the AST + * @param prop the property on the Stencil component class that is decorated with `@Event()` + * @returns generated metadata for the class member decorated by `@Event()`, or `null` if none could be derived + */ const parseEventDecorator = ( diagnostics: d.Diagnostic[], typeChecker: ts.TypeChecker, prop: ts.PropertyDeclaration -): d.ComponentCompilerStaticEvent => { - const eventDecorator = prop.decorators.find(isDecoratorNamed('Event')); +): d.ComponentCompilerStaticEvent | null => { + const eventDecorator = prop.decorators?.find(isDecoratorNamed('Event')); if (eventDecorator == null) { return null; @@ -70,6 +80,12 @@ export const getEventName = (eventOptions: d.EventOptions, memberName: string) = return memberName; }; +/** + * Derive Stencil's class member type metadata from a node in the AST + * @param typeChecker the TypeScript type checker + * @param node the node in the AST to generate metadata for + * @returns the generated metadata + */ const getComplexType = ( typeChecker: ts.TypeChecker, node: ts.PropertyDeclaration @@ -83,6 +99,11 @@ const getComplexType = ( }; }; +/** + * Derive the type of the event from the typings of `EventEmitter` + * @param type the AST node containing the `EventEmitter` typing + * @returns the type taken from `EventEmitter`, or `null` if the type cannot be derived + */ const getEventType = (type: ts.TypeNode): ts.TypeNode | null => { if ( ts.isTypeReferenceNode(type) && @@ -96,7 +117,18 @@ const getEventType = (type: ts.TypeNode): ts.TypeNode | null => { return null; }; -const validateEventName = (diagnostics: d.Diagnostic[], node: ts.Node, eventName: string) => { +/** + * Helper function for validating the name of the event + * + * This function assumes that the name of the event has been determined prior to calling it + * + * @param diagnostics a list of diagnostics used as a part of the validation process. Any parse errors/warnings shall be + * added to this collection + * @param node the node in the AT containing the class member decorated with `@Event()` + * @param eventName the name of the event + */ +const validateEventName = (diagnostics: d.Diagnostic[], node: ts.Node, eventName: string): void => { + // this regex checks for a string that begins with a capital letter - e.g. 'AskJeeves', 'Zoo', 'Spotify' if (/^[A-Z]/.test(eventName)) { const diagnostic = buildWarn(diagnostics); diagnostic.messageText = [ @@ -108,6 +140,7 @@ const validateEventName = (diagnostics: d.Diagnostic[], node: ts.Node, eventName return; } + // this regex checks for a string that begins 'on', followed by a capital letter - e.g. 'onAbout', 'onZing', 'onBlur' if (/^on[A-Z]/.test(eventName)) { const warn = buildWarn(diagnostics); const suggestedEventName = eventName[2].toLowerCase() + eventName.slice(3);