Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions packages/components/src/components/Connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { OnOpen } from './OnOpen';
import { OnMessage } from './OnMessage';
import { OnError } from './OnError';
import { OnClose } from './OnClose';
import { unsupportedLanguage } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'dart'} Language
Expand Down Expand Up @@ -115,13 +116,18 @@ Future<void> connect() async {
* renderConnect();
*/
export function Connect({ language, title }) {
const onOpenMethod = render(<OnOpen language={language} title={title} />);
const supportedLanguages = Object.keys(websocketConnectMethod);
const generateConnectCode = websocketConnectMethod[language];

if (!generateConnectCode) {
throw unsupportedLanguage(language, supportedLanguages);
}

const onOpenMethod = language === 'dart' ? '' : render(<OnOpen language={language} title={title} />);
const onMessageMethod = render(<OnMessage language={language} />);
const onErrorMethod = render(<OnError language={language} />);
const onCloseMethod = render(<OnClose language={language} title={title} />);

const generateConnectCode = websocketConnectMethod[language];

let connectMethod;

if (language === 'dart') {
Expand Down
43 changes: 34 additions & 9 deletions packages/components/src/components/DependencyProvider.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable sonarjs/no-duplicate-string */
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedFramework, unsupportedLanguage, invalidRole } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'dart' | 'java'} Language
Expand Down Expand Up @@ -57,6 +58,33 @@ const dependenciesConfig = {
}
};

/**
* Helper function to resolve dependencies for framework and role configurations.
*
* @private
* @param {Object} frameworkConfig - The framework configuration object.
* @param {string} role - The role (e.g., 'client', 'connector' for Java).
* @returns {string[]} Array of dependency strings or empty array.
*/
function resolveFrameworkDependencies(frameworkConfig, role) {
if (role) {
const supportedRoles = Object.keys(frameworkConfig);
if (!supportedRoles.includes(role)) {
throw invalidRole(role, supportedRoles);
}

if (frameworkConfig[role] && frameworkConfig[role].dependencies) {
return frameworkConfig[role].dependencies;
}
}

if (frameworkConfig.dependencies) {
return frameworkConfig.dependencies;
}

return [];
}

/**
* Helper function to resolve dependencies based on language, framework, and role.
*
Expand All @@ -68,9 +96,10 @@ const dependenciesConfig = {
*/
function resolveDependencies(language, framework = '', role = '') {
const config = dependenciesConfig[language];
const supportedLanguages = Object.keys(dependenciesConfig);

if (!config) {
return [];
throw unsupportedLanguage(language, supportedLanguages);
}

// Handle flat structure (python, javascript, dart)
Expand All @@ -79,16 +108,12 @@ function resolveDependencies(language, framework = '', role = '') {
}

// Handle nested structure (java with quarkus framework and roles)
if (framework && config[framework]) {
const frameworkConfig = config[framework];

if (role && frameworkConfig[role] && frameworkConfig[role].dependencies) {
return frameworkConfig[role].dependencies;
if (framework) {
if (!config[framework]) {
throw unsupportedFramework(language, framework, ['quarkus']);
}

if (frameworkConfig.dependencies) {
return frameworkConfig.dependencies;
}
return resolveFrameworkDependencies(config[framework], role);
}

return [];
Expand Down
20 changes: 16 additions & 4 deletions packages/components/src/components/FileHeaderInfo.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedLanguage, invalidInfo, invalidServer } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'typescript' | 'java' | 'csharp' | 'rust' | 'dart'} Language
Expand Down Expand Up @@ -54,10 +55,21 @@ const commentConfig = {
* renderFileHeader().catch(console.error);
*/
export function FileHeaderInfo({ info, server, language }) {
const { commentChar, lineStyle } = commentConfig[language] || {
commentChar: '//',
lineStyle: '//'.repeat(25)
};
if (!info) {
throw invalidInfo();
}

if (!server) {
throw invalidServer();
}

const supportedLanguages = Object.keys(commentConfig);

if (!supportedLanguages.includes(language)) {
throw unsupportedLanguage(language, supportedLanguages);
}

const { commentChar, lineStyle } = commentConfig[language];

return (
<Text>
Expand Down
30 changes: 27 additions & 3 deletions packages/components/src/components/MethodGenerator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedLanguage, negativeIndent, invalidMethodName, invalidNewLines, invalidMethodParams } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'dart' | 'java'} Language
Expand Down Expand Up @@ -75,18 +76,19 @@ const buildIndentedLogic = (logic, preExecutionCode, postExecutionCode, indentSi
*
* @param {Object} props - Component props.
* @param {Language} props.language - Programming language used for method formatting.
* @param {string} props.methodName - Name of the method.
* @param {string} props.methodName - Name of the method (non-empty string required).
* @param {string[]} [props.methodParams=[]] - Method parameters.
* @param {string} [props.methodDocs=''] - Optional documentation string.
* @param {string} [props.methodLogic=''] - Core method logic.
* @param {string} [props.preExecutionCode=''] - Code before main logic.
* @param {string} [props.postExecutionCode=''] - Code after main logic.
* @param {number} [props.indent=2] - Indentation for the method block.
* @param {number} [props.indent=2] - Indentation for the method block (must be >= 0).
* @param {number} [props.newLines=1] - Number of new lines after method.
* @param {{ returnType: string | undefined, openingTag: string | undefined, closingTag: string | undefined, indentSize: number | undefined, parameterWrap: boolean | undefined }} [props.customMethodConfig] - Optional custom syntax configuration for the current language.
* @param {{ returnType: string | undefined, openingTag: string | undefined, closingTag: string | undefined, indentSize: number | undefined, parameterWrap: boolean | undefined }} [props.customMethodConfig] - Optional custom syntax configuration for the current language.
* @param {Record<Language, { methodDocs: string | undefined, methodLogic: string | undefined } | Record<string, { methodDocs: string | undefined, methodLogic: string | undefined }>>} [props.methodConfig] - Language-level or framework-level configuration.
* @param {string} [props.framework] - Framework name for nested configurations (e.g., 'quarkus' for Java).
* @returns {JSX.Element} A Text component that contains method block with appropriate formatting.
* @throws {Error} If language is unsupported, methodName is invalid, or indent is negative.
*
* @example
* const language = "java";
Expand Down Expand Up @@ -133,6 +135,28 @@ export function MethodGenerator({
methodConfig,
framework
}) {
const supportedLanguages = Object.keys(defaultMethodConfig);

if (!supportedLanguages.includes(language)) {
throw unsupportedLanguage(language, supportedLanguages);
}

if (typeof methodName !== 'string' || methodName.trim() === '') {
throw invalidMethodName(methodName);
}
Comment on lines +144 to +146
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

methodName validation is incomplete and loses error context.

Two issues:

  1. The error message from invalidMethodName says "Expected a non-empty string", but the check only rejects non-string types — an empty string "" passes through and would produce malformed output.
  2. invalidMethodName() is called without the actual methodName value, so the error message will always say "Received: undefined" regardless of what was actually passed.
Suggested fix
-  if (typeof methodName !== 'string') {
-    throw invalidMethodName();
+  if (typeof methodName !== 'string' || methodName.trim() === '') {
+    throw invalidMethodName(methodName);
   }
🤖 Prompt for AI Agents
In `@packages/components/src/components/MethodGenerator.js` around lines 144 -
146, The current validation for methodName only checks type and calls
invalidMethodName() without context; update the check in the function that uses
methodName to ensure it is a non-empty string (e.g., typeof methodName ===
'string' && methodName.trim().length > 0) and pass the actual methodName value
into invalidMethodName(methodName) so the thrown error includes the received
value and properly rejects empty strings; reference the methodName variable and
the invalidMethodName() factory in your change.

Copy link
Contributor Author

@batchu5 batchu5 Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Adi-204 I'm a little bit confused here, because in

<CloseConnection language="java" framework="quarkus" methodName="" indent={0} />

We are calling CloseConnection, which in turn calls the methodGenerator with an empty string as the methodName.

What do you suggest?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@batchu5 honestly I don't have much idea as the template was develop during last year GSoC project by other guy. It also depends what params for a component you are keeping as optional/required and logic inside the component.
A small advice from myside would be after refactoring you do, please make sure integration test snapshots are not changed too much as it means template is generated as older version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@batchu5 one imp thing remember you will have to look at how components are used in different templates and decide which params of component are required or optional. As you can't make every param as required becoz than it would fail for some templates.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay @Adi-204

Copy link
Contributor Author

@batchu5 batchu5 Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment, I'll keep it as it is!


if (indent < 0) {
throw negativeIndent(indent);
}

if (newLines < 0) {
throw invalidNewLines(newLines);
}

if (!Array.isArray(methodParams)) {
throw invalidMethodParams(methodParams);
}

const { docs: resolvedMethodDocs, logic: resolvedMethodLogic } = resolveDocsAndLogic({
language,
methodDocs,
Expand Down
23 changes: 15 additions & 8 deletions packages/components/src/components/OnClose.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedFramework, unsupportedLanguage } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'dart' | 'java' } Language
Expand Down Expand Up @@ -96,15 +97,21 @@ export function OnClose({ language, framework = '', title }) {
let onCloseMethod = '';
let indent = 0;

if (websocketOnCloseMethod[language]) {
const generateOnCloseCode = resolveCloseConfig(language, framework);
if (!generateOnCloseCode) {
return <Text indent={0}>{''}</Text>;
}
const closeResult = generateOnCloseCode(title);
onCloseMethod = closeResult.onCloseMethod;
indent = closeResult.indent ?? 0;
const supportedLanguages = Object.keys(websocketOnCloseMethod);

if (!websocketOnCloseMethod[language]) {
throw unsupportedLanguage(language, supportedLanguages);
}

const generateOnCloseCode = resolveCloseConfig(language, framework);

if (typeof generateOnCloseCode !== 'function') {
throw unsupportedFramework(language, framework, ['quarkus']);
}

const closeResult = generateOnCloseCode(title);
onCloseMethod = closeResult.onCloseMethod;
indent = closeResult.indent ?? 0;

return (
<Text indent={indent}>
Expand Down
15 changes: 10 additions & 5 deletions packages/components/src/components/OnError.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedLanguage } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'dart'} Language
Expand Down Expand Up @@ -68,13 +69,17 @@ const websocketOnErrorMethod = {
*/
export function OnError({ language }) {
let onErrorMethod = '';
const supportedLanguages = Object.keys(websocketOnErrorMethod);

if (websocketOnErrorMethod[language]) {
const generateErrorCode = websocketOnErrorMethod[language];
const errorResult = generateErrorCode();
onErrorMethod = errorResult.onErrorMethod;
}
const generateErrorCode = websocketOnErrorMethod[language];

if (!generateErrorCode) {
throw unsupportedLanguage(language, supportedLanguages);
}

const errorResult = generateErrorCode();
onErrorMethod = errorResult.onErrorMethod;

return (
<Text>
{onErrorMethod}
Expand Down
12 changes: 8 additions & 4 deletions packages/components/src/components/OnMessage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedLanguage } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'dart'} Language
Expand Down Expand Up @@ -96,12 +97,15 @@ const websocketOnMessageMethod = {
*/
export function OnMessage({ language }) {
let onMessageMethod = '';
const supportedLanguages = Object.keys(websocketOnMessageMethod);
const generateOnMessageCode = websocketOnMessageMethod[language];

if (websocketOnMessageMethod[language]) {
const generateOnMessageCode = websocketOnMessageMethod[language];
const messageResult = generateOnMessageCode();
onMessageMethod = messageResult.onMessageMethod;
if (!generateOnMessageCode) {
throw unsupportedLanguage(language, supportedLanguages);
}

const messageResult = generateOnMessageCode();
onMessageMethod = messageResult.onMessageMethod;

return (
<Text>
Expand Down
25 changes: 16 additions & 9 deletions packages/components/src/components/OnOpen.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedFramework, unsupportedLanguage } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript' | 'java'} Language
Expand Down Expand Up @@ -81,18 +82,24 @@ export function OnOpen({ language, framework='', title }) {
let onOpenMethod = '';
let indent = 0;
let newLines = 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd packages/components/src/components && cat -n OnOpen.js | sed -n '75,110p'

Repository: asyncapi/generator

Length of output: 1201


🏁 Script executed:

git log --oneline -- packages/components/src/components/OnOpen.js | head -10

Repository: asyncapi/generator

Length of output: 108


🏁 Script executed:

# Check the previous version of the file to see what newLines default was
git show HEAD~1:packages/components/src/components/OnOpen.js 2>/dev/null | cat -n | sed -n '75,110p' || echo "No previous version available"

Repository: asyncapi/generator

Length of output: 44


🏁 Script executed:

# Also check resolveOpenConfig JSDoc
cat -n packages/components/src/components/OnOpen.js | sed -n '40,60p'

Repository: asyncapi/generator

Length of output: 907


🏁 Script executed:

# For comparison, check OnClose.js resolveCloseConfig JSDoc
cat -n packages/components/src/components/OnClose.js | sed -n '45,75p'

Repository: asyncapi/generator

Length of output: 1419


Add missing JSDoc to resolveOpenConfig function and clarify newLines default behavior.

The resolveOpenConfig function (lines 43–52) lacks JSDoc documentation. Unlike the comparable resolveCloseConfig function in OnClose.js, which has proper JSDoc with @param, @returns, and @private tags, resolveOpenConfig is undocumented. This violates the coding guideline requiring JSDoc for all functions in JavaScript files.

Additionally, line 84 initializes let newLines = 0; but this is immediately overwritten on line 102 with newLines = openResult.newLines ?? 1;. This means the effective default is 1 for languages that don't return a newLines property (like javascript and python). The initialization on line 84 is dead code. Confirm whether defaulting to 1 is intentional, or if it should be ?? 0 to match the initial declaration.

🤖 Prompt for AI Agents
In `@packages/components/src/components/OnOpen.js` around lines 82 - 84, Add JSDoc
to the resolveOpenConfig function mirroring the style in resolveCloseConfig:
include a brief description, `@param` entries for the input object and any
expected properties, `@returns` describing the resolved config shape (including
onOpenMethod, indent, newLines), and mark it `@private`; also eliminate the dead
initialization of newLines by choosing a single source of truth for its
default—either set the initial declaration of newLines to 1 (and remove the
later ?? fallback) or keep it 0 and change the assignment newLines =
openResult.newLines ?? 1 to newLines = openResult.newLines ?? 0 so the effective
default matches the intended value—ensure the variable name newLines and
function resolveOpenConfig are updated consistently.


const supportedLanguages = Object.keys(websocketOnOpenMethod);

if (!websocketOnOpenMethod[language]) {
throw unsupportedLanguage(language, supportedLanguages);
}

if (websocketOnOpenMethod[language]) {
const generateOnOpenCode = resolveOpenConfig(language, framework);
if (typeof generateOnOpenCode !== 'function') {
throw new Error(`Unsupported onOpen handler for language="${language}" framework="${framework}"`);
}
const openResult = generateOnOpenCode(title);
onOpenMethod = openResult.onOpenMethod;
indent = openResult.indent ?? 0;
newLines = openResult.newLines ?? 1;
const generateOnOpenCode = resolveOpenConfig(language, framework);

if (typeof generateOnOpenCode !== 'function') {
throw unsupportedFramework(language, framework, ['quarkus']);
}

const openResult = generateOnOpenCode(title);
onOpenMethod = openResult.onOpenMethod;
indent = openResult.indent ?? 0;
newLines = openResult.newLines ?? 1;

return (
<Text newLines={newLines} indent={indent}>
{onOpenMethod}
Expand Down
18 changes: 16 additions & 2 deletions packages/components/src/components/SendOperations.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { toSnakeCase } from '@asyncapi/generator-helpers';
import { unsupportedLanguage, invalidClientName, invalidOperation } from '../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript'} Language
Expand Down Expand Up @@ -156,13 +157,26 @@ static ${methodName}(message, socket, schemas) {
export function SendOperations({ language, sendOperations, clientName }) {
if (!sendOperations || sendOperations.length === 0) {
return null;
}
}

const supportedLanguages = Object.keys(websocketSendOperationConfig);

if (!supportedLanguages.includes(language)) {
throw unsupportedLanguage(language, supportedLanguages);
}

if (typeof clientName !== 'string' || clientName.trim() === '') {
throw invalidClientName(clientName);
}

const generateSendOperationCode = websocketSendOperationConfig[language];

return sendOperations.map((operation) => {
const { nonStaticMethod, staticMethod } = generateSendOperationCode(operation, clientName);
if (!operation || typeof operation.id !== 'function' || !operation.id()) {
throw invalidOperation();
}

const { nonStaticMethod, staticMethod } = generateSendOperationCode(operation, clientName);
return (
<>
<Text indent={2} newLines={2}>
Expand Down
6 changes: 5 additions & 1 deletion packages/components/src/components/readme/CoreMethods.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Text } from '@asyncapi/generator-react-sdk';
import { unsupportedLanguage } from '../../../utils/ErrorHandling';

/**
* @typedef {'python' | 'javascript'} Language
Expand Down Expand Up @@ -36,10 +37,13 @@ const methodConfig = {
*/

export function CoreMethods({ language }) {
const supportedLanguages = Object.keys(methodConfig);
const config = methodConfig[language];

if (!config) {
throw new Error(`Unsupported language: ${language}. Expected 'python' or 'javascript'.`);
throw unsupportedLanguage(language, supportedLanguages);
}

const { msgHandler, errHandler } = config;

return (
Expand Down
Loading
Loading