Skip to content

Commit 27766bc

Browse files
improve code structure
1 parent 79a9c01 commit 27766bc

File tree

11 files changed

+599
-110
lines changed

11 files changed

+599
-110
lines changed

src/apps/cli/internal/base.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ export default abstract class extends Command {
3535
await this.recordActionInvoked(commandName, this.metricsMetadata);
3636
}
3737

38-
async catch(err: Error & { exitCode?: number }): Promise<any> {
38+
async catch(err: Error & { exitCode?: number }): Promise<void> {
3939
try {
40-
return await super.catch(err);
41-
} catch (e: any) {
42-
if (e.message.includes('EEXIT: 0')) {
43-
process.exitCode = 0;
44-
return;
45-
}
40+
await super.catch(err);
41+
} catch (e: unknown) {
4642
if (e instanceof Error) {
43+
if (e.message.includes('EEXIT: 0')) {
44+
process.exitCode = 0;
45+
return;
46+
}
4747
this.logToStderr(`${e.name}: ${e.message}`);
4848
process.exitCode = 1;
4949
}
@@ -63,7 +63,7 @@ export default abstract class extends Command {
6363
// @ts-ignore
6464
metadata = MetadataFromDocument(document, metadata);
6565
}
66-
} catch (e: any) {
66+
} catch (e: unknown) {
6767
if (e instanceof Error) {
6868
this.log(
6969
`Skipping submitting anonymous metrics due to the following error: ${e.name}: ${e.message}`,
@@ -92,7 +92,7 @@ export default abstract class extends Command {
9292
await this.setSource();
9393
await recordFunc(await this.recorder);
9494
await (await this.recorder).flush();
95-
} catch (e: any) {
95+
} catch (e: unknown) {
9696
if (e instanceof Error) {
9797
this.log(
9898
`Skipping submitting anonymous metrics due to the following error: ${e.name}: ${e.message}`,
@@ -109,8 +109,9 @@ export default abstract class extends Command {
109109
try {
110110
const stats = await stat(specFilePath);
111111
this.metricsMetadata['file_creation_timestamp'] = stats.birthtimeMs;
112-
} catch (e: any) {
113-
// If there's an error with the file, we don't handle it here because it's expected to be handled and reported in the 'finally' method of the command.
112+
} catch {
113+
// If there's an error with the file, we don't handle it here
114+
// because it's expected to be handled and reported in the 'finally' method of the command.
114115
}
115116
}
116117
async finally(error: Error | undefined): Promise<any> {

src/apps/cli/internal/globals.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import chokidar from 'chokidar';
22
import chalk from 'chalk';
33
import Command from './base';
44
import { Specification } from '@models/SpecificationFile';
5+
import { getErrorMessage } from '@utils/error-handler';
56

67
const GreenLog = chalk.hex('#00FF00');
78
const OrangeLog = chalk.hex('#FFA500');
@@ -50,12 +51,12 @@ export const specWatcher = (params: SpecWatcherParams) => {
5051

5152
try {
5253
await params.handler.run();
53-
} catch (err: any) {
54-
await params.handler.catch(err);
54+
} catch (err: unknown) {
55+
await params.handler.catch(err as Error);
5556
}
5657
});
5758
CHOKIDAR_INSTANCE_STORE.set(params.label || '_default', true);
58-
} catch (error) {
59-
console.log(error);
59+
} catch (error: unknown) {
60+
console.error(chalk.red(`Watch error: ${getErrorMessage(error)}`));
6061
}
6162
};

src/domains/models/SpecificationFile.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { ErrorLoadingSpec } from '@errors/specification-file';
77
import { MissingContextFileError } from '@errors/context-error';
88
import { fileFormat } from '@cli/internal/flags/format.flags';
99
import { HttpsProxyAgent } from 'https-proxy-agent';
10+
import { logger } from '@utils/logger';
11+
import { getErrorMessage } from '@utils/error-handler';
1012
const { readFile, lstat } = fs;
1113
const allowedFileNames: string[] = [
1214
'asyncapi.json',
@@ -102,7 +104,7 @@ export class Specification {
102104
// Validate the target URL
103105
new URL(targetUrl);
104106

105-
const fetchOptions: any = { method: 'GET' };
107+
const fetchOptions: RequestInit & { agent?: HttpsProxyAgent<string> } = { method: 'GET' };
106108

107109
// If proxy URL is provided, create a proxy agent
108110
if (proxyUrl) {
@@ -111,7 +113,8 @@ export class Specification {
111113
const proxyAgent = new HttpsProxyAgent(proxyUrl);
112114
fetchOptions.agent = proxyAgent;
113115
response = await fetch(targetUrl, fetchOptions);
114-
} catch (err: any) {
116+
} catch (err: unknown) {
117+
logger.error(`Proxy connection error: ${getErrorMessage(err)}`);
115118
throw new Error(
116119
'Proxy Connection Error: Unable to establish a connection to the proxy check hostName or PortNumber',
117120
);
@@ -122,8 +125,8 @@ export class Specification {
122125
throw new ErrorLoadingSpec('url', targetUrl);
123126
}
124127
}
125-
} catch (error) {
126-
console.log(error);
128+
} catch (error: unknown) {
129+
logger.error(`Error loading spec from URL: ${getErrorMessage(error)}`);
127130
throw new ErrorLoadingSpec('url', targetUrl);
128131
}
129132

@@ -289,23 +292,37 @@ export function retrieveFileFormat(content: string): fileFormat | undefined {
289292
}
290293
}
291294

292-
export function convertToYaml(spec: string) {
295+
/**
296+
* Converts a JSON or YAML specification to YAML format.
297+
*
298+
* @param spec - The specification content as a string
299+
* @returns The YAML formatted string, or undefined if conversion fails
300+
*/
301+
export function convertToYaml(spec: string): string | undefined {
293302
try {
294303
// JS object -> YAML string
295304
const jsonContent = yaml.load(spec);
296305
return yaml.dump(jsonContent);
297-
} catch (err) {
298-
console.error(err);
306+
} catch (err: unknown) {
307+
logger.error(`Failed to convert spec to YAML: ${getErrorMessage(err)}`);
308+
return undefined;
299309
}
300310
}
301311

302-
export function convertToJSON(spec: string) {
312+
/**
313+
* Converts a JSON or YAML specification to JSON format.
314+
*
315+
* @param spec - The specification content as a string
316+
* @returns The JSON formatted string, or undefined if conversion fails
317+
*/
318+
export function convertToJSON(spec: string): string | undefined {
303319
try {
304320
// JSON or YAML String -> JS object
305321
const jsonContent = yaml.load(spec);
306322
// JS Object -> pretty JSON string
307323
return JSON.stringify(jsonContent, null, 2);
308-
} catch (err) {
309-
console.error(err);
324+
} catch (err: unknown) {
325+
logger.error(`Failed to convert spec to JSON: ${getErrorMessage(err)}`);
326+
return undefined;
310327
}
311328
}
Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,50 @@
11
import { ServiceResult } from '@/interfaces';
2+
import type { Diagnostic } from '@asyncapi/parser/cjs';
23

4+
/**
5+
* Base service class providing common functionality for all domain services.
6+
* Provides standardized result handling and error management.
7+
*/
38
export abstract class BaseService {
9+
/**
10+
* Creates a successful service result with the provided data.
11+
*
12+
* @param data - The data to include in the result
13+
* @returns A successful ServiceResult containing the data
14+
*/
415
protected createSuccessResult<T>(data: T): ServiceResult<T> {
516
return {
617
success: true,
718
data,
819
};
920
}
1021

11-
protected createErrorResult(
22+
/**
23+
* Creates an error service result with the provided error message.
24+
*
25+
* @param error - The error message
26+
* @param diagnostics - Optional diagnostics array for validation errors
27+
* @returns A failed ServiceResult containing the error
28+
*/
29+
protected createErrorResult<T>(
1230
error: string,
13-
diagnostics?: any[],
14-
): ServiceResult {
31+
diagnostics?: Diagnostic[],
32+
): ServiceResult<T> {
1533
return {
1634
success: false,
1735
error,
1836
diagnostics,
1937
};
2038
}
2139

22-
protected async handleServiceError(error: any): Promise<ServiceResult> {
40+
/**
41+
* Handles service errors by converting them to a standardized error result.
42+
*
43+
* @param error - The caught error (can be any type)
44+
* @returns A failed ServiceResult with the error message
45+
*/
46+
protected async handleServiceError<T>(error: unknown): Promise<ServiceResult<T>> {
2347
const errorMessage = error instanceof Error ? error.message : String(error);
24-
return this.createErrorResult(errorMessage);
48+
return this.createErrorResult<T>(errorMessage);
2549
}
2650
}

src/domains/services/convert.service.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,27 @@ export class ConversionService extends BaseService {
6868
return `🎉 The ${outputMap[flags.format]} from ${cyan(sourcePath)} has been successfully converted to AsyncAPI version ${green(targetVersion)}!!`;
6969
}
7070

71-
// Helper function to format the converted file
72-
private formatConvertedFile(convertedFile: any) {
71+
/**
72+
* Formats the converted document for output.
73+
* Objects are stringified with indentation, strings are returned as-is.
74+
*
75+
* @param convertedFile - The converted file content
76+
* @returns Formatted string representation
77+
*/
78+
private formatConvertedFile(convertedFile: string | object): string {
7379
return typeof convertedFile === 'object'
7480
? JSON.stringify(convertedFile, null, 4)
7581
: convertedFile;
7682
}
7783

78-
// Helper function to handle output
79-
async handleOutput(outputPath: string, convertedFileFormatted: string) {
80-
await fPromises.writeFile(`${outputPath}`, convertedFileFormatted, {
84+
/**
85+
* Writes the converted document to the specified output path.
86+
*
87+
* @param outputPath - The path to write the file to
88+
* @param convertedFileFormatted - The formatted content to write
89+
*/
90+
async handleOutput(outputPath: string, convertedFileFormatted: string): Promise<void> {
91+
await fPromises.writeFile(outputPath, convertedFileFormatted, {
8192
encoding: 'utf8',
8293
});
8394
}

src/domains/services/generator.service.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ import { spinner } from '@clack/prompts';
1111
import path from 'path';
1212
import os from 'os';
1313
import { yellow, magenta } from 'picocolors';
14+
import { getErrorMessage } from '@utils/error-handler';
15+
16+
/**
17+
* Options passed to the generator for code generation.
18+
*/
19+
interface GeneratorRunOptions {
20+
path?: Specification;
21+
[key: string]: unknown;
22+
}
1423

1524
export class GeneratorService extends BaseService {
1625
private defaultInteractive: boolean;
@@ -63,12 +72,23 @@ export class GeneratorService extends BaseService {
6372
}
6473
}
6574

75+
/**
76+
* Generates code from an AsyncAPI specification using the specified template.
77+
*
78+
* @param asyncapi - The AsyncAPI specification to generate from
79+
* @param template - The template to use for generation
80+
* @param output - The output directory for generated files
81+
* @param options - Generator options
82+
* @param genOption - Additional generator run options
83+
* @param interactive - Whether to show interactive spinner (default: false)
84+
* @returns ServiceResult containing generation result or error
85+
*/
6686
async generate(
6787
asyncapi: Specification,
6888
template: string,
6989
output: string,
7090
options: GenerationOptions,
71-
genOption: any,
91+
genOption: GeneratorRunOptions = {},
7292
interactive = this.defaultInteractive,
7393
): Promise<ServiceResult<GenerationResult>> {
7494
const v3NotSupported = this.checkV3NotSupported(asyncapi, template);
@@ -84,16 +104,20 @@ export class GeneratorService extends BaseService {
84104
);
85105
const s = interactive
86106
? spinner()
87-
: { start: () => null, stop: (string: string) => logs.push(string) };
107+
: { start: () => null, stop: (message: string) => logs.push(message) };
88108
s.start('Generation in progress. Keep calm and wait a bit');
89109
try {
90110
await generator.generateFromString(asyncapi.text(), {
91111
...genOption,
92112
path: asyncapi,
93113
});
94-
} catch (err: any) {
114+
} catch (err: unknown) {
95115
s.stop('Generation failed');
96-
return this.createErrorResult(err.message, err.diagnostics);
116+
const errorMessage = getErrorMessage(err, 'Generation failed');
117+
const diagnostics = err && typeof err === 'object' && 'diagnostics' in err
118+
? (err as { diagnostics?: unknown[] }).diagnostics as Parameters<typeof this.createErrorResult>[1]
119+
: undefined;
120+
return this.createErrorResult(errorMessage, diagnostics);
97121
}
98122
s.stop(
99123
this.getGenerationSuccessMessage(output),

0 commit comments

Comments
 (0)