From e781736a46f3265ea2bcf2906b782fc9806b0a0d Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Mon, 13 Nov 2023 14:50:29 +0530 Subject: [PATCH 1/9] feat: added file path as input --- src/generators/AbstractFileGenerator.ts | 2 +- src/generators/AbstractGenerator.ts | 37 ++++++++++++++++++++--- test/generators/AbstractGenerator.spec.ts | 21 +++++++++++++ test/generators/testasyncapi.yml | 23 ++++++++++++++ 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 test/generators/testasyncapi.yml diff --git a/src/generators/AbstractFileGenerator.ts b/src/generators/AbstractFileGenerator.ts index 6ce8c1801e..75da970fd6 100644 --- a/src/generators/AbstractFileGenerator.ts +++ b/src/generators/AbstractFileGenerator.ts @@ -7,7 +7,7 @@ export type FileGenerator = (content: string, toFile: string) => Promise; */ export interface AbstractFileGenerator { generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: RenderCompleteModelOptions ): Promise; diff --git a/src/generators/AbstractGenerator.ts b/src/generators/AbstractGenerator.ts index e3d238f73c..05967d4c2d 100644 --- a/src/generators/AbstractGenerator.ts +++ b/src/generators/AbstractGenerator.ts @@ -14,11 +14,12 @@ import { InputProcessor } from '../processors'; import { IndentationTypes } from '../helpers'; import { DeepPartial, isPresetWithOptions } from '../utils'; import { AbstractDependencyManager } from './AbstractDependencyManager'; +import Parser, { fromFile } from '@asyncapi/parser'; export interface CommonGeneratorOptions< P extends Preset = Preset, DependencyManager extends - AbstractDependencyManager = AbstractDependencyManager + AbstractDependencyManager = AbstractDependencyManager > { indentation?: { type: IndentationTypes; @@ -27,6 +28,7 @@ export interface CommonGeneratorOptions< defaultPreset?: P; presets?: Presets

; processorOptions?: ProcessorOptions; + inputProcessor?: InputProcessorOptions; /** * This dependency manager type serves two functions. * 1. It can be used to provide a factory for generate functions @@ -63,6 +65,16 @@ export interface AbstractGeneratorRenderCompleteModelArgs< options?: DeepPartial; } +export interface InputProcessorOptions { + type?: InputType +} + +export enum InputType { + FILE = 'file', + DOCUMENT = 'document', + OBJECT = 'object' +} + /** * Abstract generator which must be implemented by each language */ @@ -73,7 +85,7 @@ export abstract class AbstractGenerator< constructor( public readonly languageName: string, public readonly options: Options - ) {} + ) { } public abstract render( args: AbstractGeneratorRenderArgs @@ -165,7 +177,7 @@ export abstract class AbstractGenerator< for (const unionConstrainedModel of unionConstrainedModelsWithDepManager) { if ( unionConstrainedModel.constrainedModel instanceof - ConstrainedUnionModel && + ConstrainedUnionModel && unionConstrainedModel.constrainedModel.union.some( (m) => m.name === constrainedModel.name && @@ -259,8 +271,7 @@ export abstract class AbstractGenerator< protected async processInput( input: any | InputMetaModel ): Promise { - const rawInputModel = - input instanceof InputMetaModel ? input : await this.process(input); + const rawInputModel = await this.getRawInputModel(input) //Split out the models based on the language specific requirements of which models is rendered separately const splitOutModels: { [key: string]: MetaModel } = {}; @@ -274,6 +285,22 @@ export abstract class AbstractGenerator< return rawInputModel; } + protected async getRawInputModel( + input: any | InputMetaModel + ): Promise { + const inputProcessorOptions = this.options.inputProcessor + switch (inputProcessorOptions?.type) { + case InputType.FILE: + const parser = new Parser(); + const { document, diagnostics } = await fromFile(parser, input).parse(); + // TODO : Want to log the diagnostics + if (!document) throw new Error('Invalid file input') + return this.process(document as any) + default: + return input instanceof InputMetaModel ? input : this.process(input); + } + } + /** * Get all presets (default and custom ones from options) for a given preset type (class, enum, etc). */ diff --git a/test/generators/AbstractGenerator.spec.ts b/test/generators/AbstractGenerator.spec.ts index 5748cf2c18..017df11e14 100644 --- a/test/generators/AbstractGenerator.spec.ts +++ b/test/generators/AbstractGenerator.spec.ts @@ -1,3 +1,5 @@ +import path from 'path'; +import { InputType } from '../../src'; import { InputMetaModel, AnyModel, @@ -50,6 +52,25 @@ describe('AbstractGenerator', () => { expect(outputModels[0].modelName).toEqual('TestName'); }); + test('generate() should process file input', async () => { + const newGenerator = new TestGenerator({ + inputProcessor: { type: InputType.FILE } + }); + const outputModels = await newGenerator.generate(path.resolve('test/generators/testasyncapi.yml')); + expect(outputModels[0].result).toEqual('anonymous_schema_1'); + expect(outputModels[0].modelName).toEqual('TestName'); + }); + + test('generateCompleteModels() should process InputMetaModel instance', async () => { + const newGenerator = new TestGenerator({ + inputProcessor: { type: InputType.FILE } + }); + const outputModels = await newGenerator.generate(path.resolve('test/generators/testasyncapi.yml')); + + expect(outputModels[0].result).toEqual('anonymous_schema_1'); + expect(outputModels[0].modelName).toEqual('TestName'); + }); + test('should `process` function return InputMetaModel', async () => { const doc: any = { type: 'string', $id: 'test' }; const commonInputModel = await generator.process(doc); diff --git a/test/generators/testasyncapi.yml b/test/generators/testasyncapi.yml new file mode 100644 index 0000000000..6c9aaec66b --- /dev/null +++ b/test/generators/testasyncapi.yml @@ -0,0 +1,23 @@ +asyncapi: '2.6.0' +info: + title: Account Service + version: 1.0.0 + description: This service is in charge of processing user signups +channels: + user/signedup: + subscribe: + message: + $ref: '#/components/messages/UserSignedUp' +components: + messages: + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user From 82214e28f374ccc0bf79d7ef65fa4f112cfcf8ee Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Tue, 14 Nov 2023 18:31:43 +0530 Subject: [PATCH 2/9] chore: added file input in processor --- src/generators/AbstractGenerator.ts | 30 +- src/processors/AsyncAPIInputProcessor.ts | 40 ++- test/generators/AbstractGenerator.spec.ts | 21 -- .../processors/AsyncAPIInputProcessor.spec.ts | 10 + .../AsyncAPIInputProcessor}/testasyncapi.yml | 2 +- .../AsyncAPIInputProcessor.spec.ts.snap | 256 ++++++++++++++++++ 6 files changed, 301 insertions(+), 58 deletions(-) rename test/{generators => processors/AsyncAPIInputProcessor}/testasyncapi.yml (92%) diff --git a/src/generators/AbstractGenerator.ts b/src/generators/AbstractGenerator.ts index 05967d4c2d..62aa37b6e3 100644 --- a/src/generators/AbstractGenerator.ts +++ b/src/generators/AbstractGenerator.ts @@ -14,7 +14,6 @@ import { InputProcessor } from '../processors'; import { IndentationTypes } from '../helpers'; import { DeepPartial, isPresetWithOptions } from '../utils'; import { AbstractDependencyManager } from './AbstractDependencyManager'; -import Parser, { fromFile } from '@asyncapi/parser'; export interface CommonGeneratorOptions< P extends Preset = Preset, @@ -28,7 +27,6 @@ export interface CommonGeneratorOptions< defaultPreset?: P; presets?: Presets

; processorOptions?: ProcessorOptions; - inputProcessor?: InputProcessorOptions; /** * This dependency manager type serves two functions. * 1. It can be used to provide a factory for generate functions @@ -65,16 +63,6 @@ export interface AbstractGeneratorRenderCompleteModelArgs< options?: DeepPartial; } -export interface InputProcessorOptions { - type?: InputType -} - -export enum InputType { - FILE = 'file', - DOCUMENT = 'document', - OBJECT = 'object' -} - /** * Abstract generator which must be implemented by each language */ @@ -271,7 +259,7 @@ export abstract class AbstractGenerator< protected async processInput( input: any | InputMetaModel ): Promise { - const rawInputModel = await this.getRawInputModel(input) + const rawInputModel = input instanceof InputMetaModel ? input : await this.process(input); //Split out the models based on the language specific requirements of which models is rendered separately const splitOutModels: { [key: string]: MetaModel } = {}; @@ -285,22 +273,6 @@ export abstract class AbstractGenerator< return rawInputModel; } - protected async getRawInputModel( - input: any | InputMetaModel - ): Promise { - const inputProcessorOptions = this.options.inputProcessor - switch (inputProcessorOptions?.type) { - case InputType.FILE: - const parser = new Parser(); - const { document, diagnostics } = await fromFile(parser, input).parse(); - // TODO : Want to log the diagnostics - if (!document) throw new Error('Invalid file input') - return this.process(document as any) - default: - return input instanceof InputMetaModel ? input : this.process(input); - } - } - /** * Get all presets (default and custom ones from options) for a given preset type (class, enum, etc). */ diff --git a/src/processors/AsyncAPIInputProcessor.ts b/src/processors/AsyncAPIInputProcessor.ts index a7f96a591d..7e118983c4 100644 --- a/src/processors/AsyncAPIInputProcessor.ts +++ b/src/processors/AsyncAPIInputProcessor.ts @@ -7,7 +7,8 @@ import { Parser, AsyncAPIDocumentInterface, SchemaInterface as AsyncAPISchemaInterface, - SchemaV2 as AsyncAPISchema + SchemaV2 as AsyncAPISchema, + fromFile } from '@asyncapi/parser'; import { AsyncAPISchemaObject } from '@asyncapi/parser/cjs/spec-types/v2'; import { AvroSchemaParser } from '@asyncapi/avro-schema-parser'; @@ -20,6 +21,7 @@ import { InputMetaModel, ProcessorOptions, UnionModel } from '../models'; import { Logger } from '../utils'; import { AsyncapiV2Schema } from '../models/AsyncapiV2Schema'; import { convertToMetaModel } from '../helpers'; +import fs from 'fs'; /** * Class for processing AsyncAPI inputs @@ -53,7 +55,11 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { input?: any, options?: ProcessorOptions ): Promise { - if (!this.shouldProcess(input)) { + let rawInput = input; + if (this.isFilePathInput(input)) + rawInput = await this.getParsedFileInput(input); + + if (!this.shouldProcess(rawInput)) { throw new Error( 'Input is not an AsyncAPI document so it cannot be processed.' ); @@ -62,9 +68,9 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { Logger.debug('Processing input as an AsyncAPI document'); let doc: AsyncAPIDocumentInterface; const inputModel = new InputMetaModel(); - if (!AsyncAPIInputProcessor.isFromParser(input)) { + if (!AsyncAPIInputProcessor.isFromParser(rawInput)) { const { document, diagnostics } = await this.parser.parse( - input as any, + rawInput as any, options?.asyncapi || {} ); if (document) { @@ -76,11 +82,11 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { (err as any).diagnostics = diagnostics; throw err; } - } else if (AsyncAPIInputProcessor.isFromNewParser(input)) { - doc = input as AsyncAPIDocumentInterface; + } else if (AsyncAPIInputProcessor.isFromNewParser(rawInput)) { + doc = rawInput as AsyncAPIDocumentInterface; } else { // Is from old parser - const parsedJSON = input.json(); + const parsedJSON = rawInput.json(); const detailed = createDetailedAsyncAPI(parsedJSON, parsedJSON); doc = createAsyncAPIDocument(detailed); } @@ -390,6 +396,9 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { if (!input) { return false; } + if(this.isFilePathInput(input)){ + return true; + } const version = this.tryGetVersionOfDocument(input); if (!version) { return false; @@ -429,4 +438,21 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { static isFromNewParser(input?: any): boolean { return isAsyncAPIDocument(input); } + + isFilePathInput(input: any): boolean { + return typeof input === 'string' && fs.existsSync(input); + } + + async getParsedFileInput(filePath: string): Promise { + const parser = new Parser(); + const { document, diagnostics } = await fromFile(parser, filePath).parse(); + if (!document) { + const err = new Error( + 'Input is not an correct AsyncAPI document so it cannot be processed.' + ); + (err as any).diagnostics = diagnostics; + throw err; + } + return document; + } } diff --git a/test/generators/AbstractGenerator.spec.ts b/test/generators/AbstractGenerator.spec.ts index 017df11e14..5748cf2c18 100644 --- a/test/generators/AbstractGenerator.spec.ts +++ b/test/generators/AbstractGenerator.spec.ts @@ -1,5 +1,3 @@ -import path from 'path'; -import { InputType } from '../../src'; import { InputMetaModel, AnyModel, @@ -52,25 +50,6 @@ describe('AbstractGenerator', () => { expect(outputModels[0].modelName).toEqual('TestName'); }); - test('generate() should process file input', async () => { - const newGenerator = new TestGenerator({ - inputProcessor: { type: InputType.FILE } - }); - const outputModels = await newGenerator.generate(path.resolve('test/generators/testasyncapi.yml')); - expect(outputModels[0].result).toEqual('anonymous_schema_1'); - expect(outputModels[0].modelName).toEqual('TestName'); - }); - - test('generateCompleteModels() should process InputMetaModel instance', async () => { - const newGenerator = new TestGenerator({ - inputProcessor: { type: InputType.FILE } - }); - const outputModels = await newGenerator.generate(path.resolve('test/generators/testasyncapi.yml')); - - expect(outputModels[0].result).toEqual('anonymous_schema_1'); - expect(outputModels[0].modelName).toEqual('TestName'); - }); - test('should `process` function return InputMetaModel', async () => { const doc: any = { type: 'string', $id: 'test' }; const commonInputModel = await generator.process(doc); diff --git a/test/processors/AsyncAPIInputProcessor.spec.ts b/test/processors/AsyncAPIInputProcessor.spec.ts index d509c82b36..ef086c8928 100644 --- a/test/processors/AsyncAPIInputProcessor.spec.ts +++ b/test/processors/AsyncAPIInputProcessor.spec.ts @@ -15,6 +15,7 @@ const operationOneOf2DocString = fs.readFileSync( path.resolve(__dirname, './AsyncAPIInputProcessor/operation_oneof2.json'), 'utf8' ); +const ymlFilePath = path.resolve(__dirname, './AsyncAPIInputProcessor/testasyncapi.yml'); jest.mock('../../src/utils/LoggingInterface'); describe('AsyncAPIInputProcessor', () => { @@ -30,6 +31,9 @@ describe('AsyncAPIInputProcessor', () => { const { document } = await parser.parse(basicDocString); expect(processor.shouldProcess(document)).toEqual(true); }); + test('should be able to detect file', async () => { + expect(processor.shouldProcess(ymlFilePath)).toEqual(true); + }); test('should be able to process AsyncAPI 2.0.0', () => { const parsedObject = { asyncapi: '2.0.0' }; expect(processor.shouldProcess(parsedObject)).toEqual(true); @@ -123,6 +127,12 @@ describe('AsyncAPIInputProcessor', () => { expect(commonInputModel).toMatchSnapshot(); }); + test('should be able to process file', async () => { + const processor = new AsyncAPIInputProcessor(); + const commonInputModel = await processor.process(ymlFilePath); + expect(commonInputModel).toMatchSnapshot(); + }); + test('should be able to process operation with oneOf #1', async () => { const { document } = await parser.parse(operationOneOf1DocString); const processor = new AsyncAPIInputProcessor(); diff --git a/test/generators/testasyncapi.yml b/test/processors/AsyncAPIInputProcessor/testasyncapi.yml similarity index 92% rename from test/generators/testasyncapi.yml rename to test/processors/AsyncAPIInputProcessor/testasyncapi.yml index 6c9aaec66b..fbb3f891b7 100644 --- a/test/generators/testasyncapi.yml +++ b/test/processors/AsyncAPIInputProcessor/testasyncapi.yml @@ -20,4 +20,4 @@ components: email: type: string format: email - description: Email of the user + description: Email of the user \ No newline at end of file diff --git a/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap b/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap index 4f35c47b35..8b82498747 100644 --- a/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap +++ b/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap @@ -4276,3 +4276,259 @@ InputMetaModel { }, } `; +exports[`AsyncAPIInputProcessor process() should be able to process file 1`] = ` +InputMetaModel { + "models": Object { + "anonymous_schema_1": ObjectModel { + "name": "anonymous_schema_1", + "options": Object { + "isNullable": false, + }, + "originalInput": AsyncapiV2Schema { + "properties": Object { + "displayName": AsyncapiV2Schema { + "description": "Name of the user", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_2", + "x-parser-schema-id": "", + }, + "email": AsyncapiV2Schema { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_3", + "x-parser-schema-id": "", + }, + }, + "type": "object", + "x-modelgen-inferred-name": "anonymous_schema_1", + "x-parser-schema-id": "", + }, + "properties": Object { + "additionalProperties": ObjectPropertyModel { + "property": DictionaryModel { + "key": StringModel { + "name": "additionalProperties", + "options": Object { + "isNullable": false, + }, + "originalInput": Array [ + true, + ], + }, + "name": "additionalProperties", + "options": Object { + "isNullable": false, + }, + "originalInput": Array [ + true, + ], + "serializationType": "unwrap", + "value": AnyModel { + "name": "undefined", + "options": Object { + "isNullable": true, + }, + "originalInput": true, + }, + }, + "propertyName": "additionalProperties", + "required": false, + }, + "displayName": ObjectPropertyModel { + "property": StringModel { + "name": "anonymous_schema_2", + "options": Object { + "isNullable": false, + }, + "originalInput": AsyncapiV2Schema { + "description": "Name of the user", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_2", + "x-parser-schema-id": "", + }, + }, + "propertyName": "displayName", + "required": false, + }, + "email": ObjectPropertyModel { + "property": StringModel { + "name": "anonymous_schema_3", + "options": Object { + "format": "email", + "isNullable": false, + }, + "originalInput": AsyncapiV2Schema { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_3", + "x-parser-schema-id": "", + }, + }, + "propertyName": "email", + "required": false, + }, + }, + }, + }, + "originalInput": AsyncAPIDocument { + "_json": Object { + "asyncapi": "2.6.0", + "channels": Object { + "user/signedup": Object { + "subscribe": Object { + "message": Object { + "payload": Object { + "properties": Object { + "displayName": Object { + "description": "Name of the user", + "type": "string", + "x-parser-schema-id": "", + }, + "email": Object { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-parser-schema-id": "", + }, + }, + "type": "object", + "x-parser-schema-id": "", + }, + "x-parser-message-name": "UserSignedUp", + }, + }, + }, + }, + "components": Object { + "messages": Object { + "UserSignedUp": Object { + "payload": Object { + "properties": Object { + "displayName": Object { + "description": "Name of the user", + "type": "string", + "x-parser-schema-id": "", + }, + "email": Object { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-parser-schema-id": "", + }, + }, + "type": "object", + "x-parser-schema-id": "", + }, + "x-parser-message-name": "UserSignedUp", + }, + }, + }, + "info": Object { + "description": "This service is in charge of processing user signups", + "title": "Account Service", + "version": "1.0.0", + }, + "x-parser-api-version": 1, + "x-parser-spec-parsed": true, + }, + "_meta": Object { + "asyncapi": Object { + "input": "asyncapi: '2.6.0' +info: + title: Account Service + version: 1.0.0 + description: This service is in charge of processing user signups +channels: + user/signedup: + subscribe: + message: + $ref: '#/components/messages/UserSignedUp' +components: + messages: + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user", + "parsed": Object { + "asyncapi": "2.6.0", + "channels": Object { + "user/signedup": Object { + "subscribe": Object { + "message": Object { + "payload": Object { + "properties": Object { + "displayName": Object { + "description": "Name of the user", + "type": "string", + "x-parser-schema-id": "", + }, + "email": Object { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-parser-schema-id": "", + }, + }, + "type": "object", + "x-parser-schema-id": "", + }, + "x-parser-message-name": "UserSignedUp", + }, + }, + }, + }, + "components": Object { + "messages": Object { + "UserSignedUp": Object { + "payload": Object { + "properties": Object { + "displayName": Object { + "description": "Name of the user", + "type": "string", + "x-parser-schema-id": "", + }, + "email": Object { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-parser-schema-id": "", + }, + }, + "type": "object", + "x-parser-schema-id": "", + }, + "x-parser-message-name": "UserSignedUp", + }, + }, + }, + "info": Object { + "description": "This service is in charge of processing user signups", + "title": "Account Service", + "version": "1.0.0", + }, + "x-parser-api-version": 1, + "x-parser-spec-parsed": true, + }, + "semver": Object { + "major": 2, + "minor": 6, + "patch": 0, + "rc": undefined, + "version": "2.6.0", + }, + "source": "/Users/nilkanthparmar/Documents/Projects/asyncapi/modelina/test/processors/AsyncAPIInputProcessor/testasyncapi.yml", + }, + "pointer": "/", + }, + }, +} +`; From 4a0e482fcb9a1ac7f03af91a738652d1586fcb38 Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Wed, 15 Nov 2023 11:14:07 +0530 Subject: [PATCH 3/9] feat: file path to file uri --- src/processors/AsyncAPIInputProcessor.ts | 17 +- .../processors/AsyncAPIInputProcessor.spec.ts | 19 +- .../AsyncAPIInputProcessor.spec.ts.snap | 353 +++++------------- 3 files changed, 123 insertions(+), 266 deletions(-) diff --git a/src/processors/AsyncAPIInputProcessor.ts b/src/processors/AsyncAPIInputProcessor.ts index 7e118983c4..75b6992ab7 100644 --- a/src/processors/AsyncAPIInputProcessor.ts +++ b/src/processors/AsyncAPIInputProcessor.ts @@ -22,6 +22,7 @@ import { Logger } from '../utils'; import { AsyncapiV2Schema } from '../models/AsyncapiV2Schema'; import { convertToMetaModel } from '../helpers'; import fs from 'fs'; +import { fileURLToPath } from 'url'; /** * Class for processing AsyncAPI inputs @@ -56,7 +57,7 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { options?: ProcessorOptions ): Promise { let rawInput = input; - if (this.isFilePathInput(input)) + if (this.isFileInput(input)) rawInput = await this.getParsedFileInput(input); if (!this.shouldProcess(rawInput)) { @@ -396,7 +397,7 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { if (!input) { return false; } - if(this.isFilePathInput(input)){ + if(this.isFileInput(input)){ return true; } const version = this.tryGetVersionOfDocument(input); @@ -439,11 +440,17 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { return isAsyncAPIDocument(input); } - isFilePathInput(input: any): boolean { - return typeof input === 'string' && fs.existsSync(input); + isFileInput(input: any): boolean { + return typeof input === 'string' && /^file:\/\//g.test(input); } - async getParsedFileInput(filePath: string): Promise { + async getParsedFileInput(input: string): Promise { + const filePath = fileURLToPath(input); + if(!fs.existsSync(filePath)){ + throw new Error( + 'File does not exists.' + ); + } const parser = new Parser(); const { document, diagnostics } = await fromFile(parser, filePath).parse(); if (!document) { diff --git a/test/processors/AsyncAPIInputProcessor.spec.ts b/test/processors/AsyncAPIInputProcessor.spec.ts index ef086c8928..943557ad80 100644 --- a/test/processors/AsyncAPIInputProcessor.spec.ts +++ b/test/processors/AsyncAPIInputProcessor.spec.ts @@ -2,6 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { Parser } from '@asyncapi/parser'; import { AsyncAPIInputProcessor } from '../../src/processors/AsyncAPIInputProcessor'; +import { InputMetaModel } from '../../src/models'; const basicDocString = fs.readFileSync( path.resolve(__dirname, './AsyncAPIInputProcessor/basic.json'), @@ -15,7 +16,7 @@ const operationOneOf2DocString = fs.readFileSync( path.resolve(__dirname, './AsyncAPIInputProcessor/operation_oneof2.json'), 'utf8' ); -const ymlFilePath = path.resolve(__dirname, './AsyncAPIInputProcessor/testasyncapi.yml'); +const ymlFileURI = `file://${path.resolve(__dirname, './AsyncAPIInputProcessor/testasyncapi.yml')}`; jest.mock('../../src/utils/LoggingInterface'); describe('AsyncAPIInputProcessor', () => { @@ -32,7 +33,7 @@ describe('AsyncAPIInputProcessor', () => { expect(processor.shouldProcess(document)).toEqual(true); }); test('should be able to detect file', async () => { - expect(processor.shouldProcess(ymlFilePath)).toEqual(true); + expect(processor.shouldProcess(ymlFileURI)).toEqual(true); }); test('should be able to process AsyncAPI 2.0.0', () => { const parsedObject = { asyncapi: '2.0.0' }; @@ -113,6 +114,13 @@ describe('AsyncAPIInputProcessor', () => { ); }); + test('should throw error when file does not exists', async () => { + const processor = new AsyncAPIInputProcessor(); + await expect( + processor.process(`${ymlFileURI}test`) + ).rejects.toThrow('File does not exists.'); + }); + test('should be able to process pure object', async () => { const basicDoc = JSON.parse(basicDocString); const processor = new AsyncAPIInputProcessor(); @@ -129,8 +137,9 @@ describe('AsyncAPIInputProcessor', () => { test('should be able to process file', async () => { const processor = new AsyncAPIInputProcessor(); - const commonInputModel = await processor.process(ymlFilePath); - expect(commonInputModel).toMatchSnapshot(); + const commonInputModel = await processor.process(ymlFileURI); + expect(commonInputModel instanceof InputMetaModel).toBeTruthy() + expect(commonInputModel.models).toMatchSnapshot(); }); test('should be able to process operation with oneOf #1', async () => { @@ -195,7 +204,7 @@ describe('AsyncAPIInputProcessor', () => { ).toEqual('anonymous_schema_8'); expect( expected.properties.propWithObject.properties.propWithObject[ - 'x-modelgen-inferred-name' + 'x-modelgen-inferred-name' ] ).toEqual('anonymous_schema_9'); diff --git a/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap b/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap index 8b82498747..ed7d1889c1 100644 --- a/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap +++ b/test/processors/__snapshots__/AsyncAPIInputProcessor.spec.ts.snap @@ -1,5 +1,102 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`AsyncAPIInputProcessor process() should be able to process file 1`] = ` +Object { + "anonymous_schema_1": ObjectModel { + "name": "anonymous_schema_1", + "options": Object { + "isNullable": false, + }, + "originalInput": AsyncapiV2Schema { + "properties": Object { + "displayName": AsyncapiV2Schema { + "description": "Name of the user", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_2", + "x-parser-schema-id": "", + }, + "email": AsyncapiV2Schema { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_3", + "x-parser-schema-id": "", + }, + }, + "type": "object", + "x-modelgen-inferred-name": "anonymous_schema_1", + "x-parser-schema-id": "", + }, + "properties": Object { + "additionalProperties": ObjectPropertyModel { + "property": DictionaryModel { + "key": StringModel { + "name": "additionalProperties", + "options": Object { + "isNullable": false, + }, + "originalInput": Array [ + true, + ], + }, + "name": "additionalProperties", + "options": Object { + "isNullable": false, + }, + "originalInput": Array [ + true, + ], + "serializationType": "unwrap", + "value": AnyModel { + "name": "undefined", + "options": Object { + "isNullable": true, + }, + "originalInput": true, + }, + }, + "propertyName": "additionalProperties", + "required": false, + }, + "displayName": ObjectPropertyModel { + "property": StringModel { + "name": "anonymous_schema_2", + "options": Object { + "isNullable": false, + }, + "originalInput": AsyncapiV2Schema { + "description": "Name of the user", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_2", + "x-parser-schema-id": "", + }, + }, + "propertyName": "displayName", + "required": false, + }, + "email": ObjectPropertyModel { + "property": StringModel { + "name": "anonymous_schema_3", + "options": Object { + "format": "email", + "isNullable": false, + }, + "originalInput": AsyncapiV2Schema { + "description": "Email of the user", + "format": "email", + "type": "string", + "x-modelgen-inferred-name": "anonymous_schema_3", + "x-parser-schema-id": "", + }, + }, + "propertyName": "email", + "required": false, + }, + }, + }, +} +`; + exports[`AsyncAPIInputProcessor process() should be able to process operation with oneOf #1 1`] = ` InputMetaModel { "models": Object { @@ -4276,259 +4373,3 @@ InputMetaModel { }, } `; -exports[`AsyncAPIInputProcessor process() should be able to process file 1`] = ` -InputMetaModel { - "models": Object { - "anonymous_schema_1": ObjectModel { - "name": "anonymous_schema_1", - "options": Object { - "isNullable": false, - }, - "originalInput": AsyncapiV2Schema { - "properties": Object { - "displayName": AsyncapiV2Schema { - "description": "Name of the user", - "type": "string", - "x-modelgen-inferred-name": "anonymous_schema_2", - "x-parser-schema-id": "", - }, - "email": AsyncapiV2Schema { - "description": "Email of the user", - "format": "email", - "type": "string", - "x-modelgen-inferred-name": "anonymous_schema_3", - "x-parser-schema-id": "", - }, - }, - "type": "object", - "x-modelgen-inferred-name": "anonymous_schema_1", - "x-parser-schema-id": "", - }, - "properties": Object { - "additionalProperties": ObjectPropertyModel { - "property": DictionaryModel { - "key": StringModel { - "name": "additionalProperties", - "options": Object { - "isNullable": false, - }, - "originalInput": Array [ - true, - ], - }, - "name": "additionalProperties", - "options": Object { - "isNullable": false, - }, - "originalInput": Array [ - true, - ], - "serializationType": "unwrap", - "value": AnyModel { - "name": "undefined", - "options": Object { - "isNullable": true, - }, - "originalInput": true, - }, - }, - "propertyName": "additionalProperties", - "required": false, - }, - "displayName": ObjectPropertyModel { - "property": StringModel { - "name": "anonymous_schema_2", - "options": Object { - "isNullable": false, - }, - "originalInput": AsyncapiV2Schema { - "description": "Name of the user", - "type": "string", - "x-modelgen-inferred-name": "anonymous_schema_2", - "x-parser-schema-id": "", - }, - }, - "propertyName": "displayName", - "required": false, - }, - "email": ObjectPropertyModel { - "property": StringModel { - "name": "anonymous_schema_3", - "options": Object { - "format": "email", - "isNullable": false, - }, - "originalInput": AsyncapiV2Schema { - "description": "Email of the user", - "format": "email", - "type": "string", - "x-modelgen-inferred-name": "anonymous_schema_3", - "x-parser-schema-id": "", - }, - }, - "propertyName": "email", - "required": false, - }, - }, - }, - }, - "originalInput": AsyncAPIDocument { - "_json": Object { - "asyncapi": "2.6.0", - "channels": Object { - "user/signedup": Object { - "subscribe": Object { - "message": Object { - "payload": Object { - "properties": Object { - "displayName": Object { - "description": "Name of the user", - "type": "string", - "x-parser-schema-id": "", - }, - "email": Object { - "description": "Email of the user", - "format": "email", - "type": "string", - "x-parser-schema-id": "", - }, - }, - "type": "object", - "x-parser-schema-id": "", - }, - "x-parser-message-name": "UserSignedUp", - }, - }, - }, - }, - "components": Object { - "messages": Object { - "UserSignedUp": Object { - "payload": Object { - "properties": Object { - "displayName": Object { - "description": "Name of the user", - "type": "string", - "x-parser-schema-id": "", - }, - "email": Object { - "description": "Email of the user", - "format": "email", - "type": "string", - "x-parser-schema-id": "", - }, - }, - "type": "object", - "x-parser-schema-id": "", - }, - "x-parser-message-name": "UserSignedUp", - }, - }, - }, - "info": Object { - "description": "This service is in charge of processing user signups", - "title": "Account Service", - "version": "1.0.0", - }, - "x-parser-api-version": 1, - "x-parser-spec-parsed": true, - }, - "_meta": Object { - "asyncapi": Object { - "input": "asyncapi: '2.6.0' -info: - title: Account Service - version: 1.0.0 - description: This service is in charge of processing user signups -channels: - user/signedup: - subscribe: - message: - $ref: '#/components/messages/UserSignedUp' -components: - messages: - UserSignedUp: - payload: - type: object - properties: - displayName: - type: string - description: Name of the user - email: - type: string - format: email - description: Email of the user", - "parsed": Object { - "asyncapi": "2.6.0", - "channels": Object { - "user/signedup": Object { - "subscribe": Object { - "message": Object { - "payload": Object { - "properties": Object { - "displayName": Object { - "description": "Name of the user", - "type": "string", - "x-parser-schema-id": "", - }, - "email": Object { - "description": "Email of the user", - "format": "email", - "type": "string", - "x-parser-schema-id": "", - }, - }, - "type": "object", - "x-parser-schema-id": "", - }, - "x-parser-message-name": "UserSignedUp", - }, - }, - }, - }, - "components": Object { - "messages": Object { - "UserSignedUp": Object { - "payload": Object { - "properties": Object { - "displayName": Object { - "description": "Name of the user", - "type": "string", - "x-parser-schema-id": "", - }, - "email": Object { - "description": "Email of the user", - "format": "email", - "type": "string", - "x-parser-schema-id": "", - }, - }, - "type": "object", - "x-parser-schema-id": "", - }, - "x-parser-message-name": "UserSignedUp", - }, - }, - }, - "info": Object { - "description": "This service is in charge of processing user signups", - "title": "Account Service", - "version": "1.0.0", - }, - "x-parser-api-version": 1, - "x-parser-spec-parsed": true, - }, - "semver": Object { - "major": 2, - "minor": 6, - "patch": 0, - "rc": undefined, - "version": "2.6.0", - }, - "source": "/Users/nilkanthparmar/Documents/Projects/asyncapi/modelina/test/processors/AsyncAPIInputProcessor/testasyncapi.yml", - }, - "pointer": "/", - }, - }, -} -`; From 85fa99aa25c973ffc1b65b961cb3890624c089df Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Wed, 15 Nov 2023 11:42:32 +0530 Subject: [PATCH 4/9] fix: parser in file input --- src/processors/AsyncAPIInputProcessor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processors/AsyncAPIInputProcessor.ts b/src/processors/AsyncAPIInputProcessor.ts index b1abcb826d..5298e3871c 100644 --- a/src/processors/AsyncAPIInputProcessor.ts +++ b/src/processors/AsyncAPIInputProcessor.ts @@ -1,6 +1,6 @@ /* eslint-disable no-undef */ /* eslint-disable @typescript-eslint/no-var-requires */ -import { +import Parser, { isAsyncAPIDocument, isOldAsyncAPIDocument, AsyncAPIDocumentInterface, @@ -426,7 +426,7 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { 'File does not exists.' ); } - const parser = new NewParser(); + const parser = new Parser(); const { document, diagnostics } = await fromFile(parser, filePath).parse(); if (!document) { const err = new Error( From 21384b6edf1bbfd15b8df181d606ce2820d39529 Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Thu, 16 Nov 2023 11:28:09 +0530 Subject: [PATCH 5/9] fix: lint fixed --- src/generators/AbstractGenerator.ts | 9 +++++---- src/processors/AsyncAPIInputProcessor.ts | 14 +++++++------- test/processors/AsyncAPIInputProcessor.spec.ts | 17 ++++++++++------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/generators/AbstractGenerator.ts b/src/generators/AbstractGenerator.ts index 62aa37b6e3..e3d238f73c 100644 --- a/src/generators/AbstractGenerator.ts +++ b/src/generators/AbstractGenerator.ts @@ -18,7 +18,7 @@ import { AbstractDependencyManager } from './AbstractDependencyManager'; export interface CommonGeneratorOptions< P extends Preset = Preset, DependencyManager extends - AbstractDependencyManager = AbstractDependencyManager + AbstractDependencyManager = AbstractDependencyManager > { indentation?: { type: IndentationTypes; @@ -73,7 +73,7 @@ export abstract class AbstractGenerator< constructor( public readonly languageName: string, public readonly options: Options - ) { } + ) {} public abstract render( args: AbstractGeneratorRenderArgs @@ -165,7 +165,7 @@ export abstract class AbstractGenerator< for (const unionConstrainedModel of unionConstrainedModelsWithDepManager) { if ( unionConstrainedModel.constrainedModel instanceof - ConstrainedUnionModel && + ConstrainedUnionModel && unionConstrainedModel.constrainedModel.union.some( (m) => m.name === constrainedModel.name && @@ -259,7 +259,8 @@ export abstract class AbstractGenerator< protected async processInput( input: any | InputMetaModel ): Promise { - const rawInputModel = input instanceof InputMetaModel ? input : await this.process(input); + const rawInputModel = + input instanceof InputMetaModel ? input : await this.process(input); //Split out the models based on the language specific requirements of which models is rendered separately const splitOutModels: { [key: string]: MetaModel } = {}; diff --git a/src/processors/AsyncAPIInputProcessor.ts b/src/processors/AsyncAPIInputProcessor.ts index 5298e3871c..f27e029172 100644 --- a/src/processors/AsyncAPIInputProcessor.ts +++ b/src/processors/AsyncAPIInputProcessor.ts @@ -48,8 +48,9 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { options?: ProcessorOptions ): Promise { let rawInput = input; - if (this.isFileInput(input)) + if (this.isFileInput(input)) { rawInput = await this.getParsedFileInput(input); + } if (!this.shouldProcess(rawInput)) { throw new Error( @@ -372,7 +373,7 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { if (!input) { return false; } - if(this.isFileInput(input)){ + if (this.isFileInput(input)) { return true; } const version = this.tryGetVersionOfDocument(input); @@ -416,15 +417,14 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { } isFileInput(input: any): boolean { - return typeof input === 'string' && /^file:\/\//g.test(input); + // prettier-ignore + return typeof input === 'string' && (/^file:\/\//g).test(input); } async getParsedFileInput(input: string): Promise { const filePath = fileURLToPath(input); - if(!fs.existsSync(filePath)){ - throw new Error( - 'File does not exists.' - ); + if (!fs.existsSync(filePath)) { + throw new Error('File does not exists.'); } const parser = new Parser(); const { document, diagnostics } = await fromFile(parser, filePath).parse(); diff --git a/test/processors/AsyncAPIInputProcessor.spec.ts b/test/processors/AsyncAPIInputProcessor.spec.ts index 7bf6ef71fa..6ff561be93 100644 --- a/test/processors/AsyncAPIInputProcessor.spec.ts +++ b/test/processors/AsyncAPIInputProcessor.spec.ts @@ -20,7 +20,10 @@ const operationOneOf2DocString = fs.readFileSync( path.resolve(__dirname, './AsyncAPIInputProcessor/operation_oneof2.json'), 'utf8' ); -const ymlFileURI = `file://${path.resolve(__dirname, './AsyncAPIInputProcessor/testasyncapi.yml')}`; +const ymlFileURI = `file://${path.resolve( + __dirname, + './AsyncAPIInputProcessor/testasyncapi.yml' +)}`; jest.mock('../../src/utils/LoggingInterface'); describe('AsyncAPIInputProcessor', () => { @@ -36,7 +39,7 @@ describe('AsyncAPIInputProcessor', () => { const { document } = await parser.parse(basicDocString); expect(processor.shouldProcess(document)).toEqual(true); }); - test('should be able to detect file', async () => { + test('should be able to detect file', () => { expect(processor.shouldProcess(ymlFileURI)).toEqual(true); }); test('should be able to process AsyncAPI 2.0.0', () => { @@ -124,9 +127,9 @@ describe('AsyncAPIInputProcessor', () => { test('should throw error when file does not exists', async () => { const processor = new AsyncAPIInputProcessor(); - await expect( - processor.process(`${ymlFileURI}test`) - ).rejects.toThrow('File does not exists.'); + await expect(processor.process(`${ymlFileURI}test`)).rejects.toThrow( + 'File does not exists.' + ); }); test('should be able to process pure object', async () => { @@ -152,7 +155,7 @@ describe('AsyncAPIInputProcessor', () => { test('should be able to process file', async () => { const processor = new AsyncAPIInputProcessor(); const commonInputModel = await processor.process(ymlFileURI); - expect(commonInputModel instanceof InputMetaModel).toBeTruthy() + expect(commonInputModel instanceof InputMetaModel).toBeTruthy(); expect(commonInputModel.models).toMatchSnapshot(); }); @@ -218,7 +221,7 @@ describe('AsyncAPIInputProcessor', () => { ).toEqual('anonymous_schema_8'); expect( expected.properties.propWithObject.properties.propWithObject[ - 'x-modelgen-inferred-name' + 'x-modelgen-inferred-name' ] ).toEqual('anonymous_schema_9'); From 693b25e72affbbb128e1fc1d03280d399ed67880 Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Sun, 19 Nov 2023 11:21:00 +0530 Subject: [PATCH 6/9] chore: changed type for input to any --- src/generators/cplusplus/CplusplusFileGenerator.ts | 2 +- src/generators/csharp/CSharpFileGenerator.ts | 2 +- src/generators/dart/DartFileGenerator.ts | 2 +- src/generators/go/GoFileGenerator.ts | 2 +- src/generators/java/JavaFileGenerator.ts | 2 +- src/generators/javascript/JavaScriptFileGenerator.ts | 2 +- src/generators/kotlin/KotlinFileGenerator.ts | 2 +- src/generators/php/PhpFileGenerator.ts | 2 +- src/generators/python/PythonFileGenerator.ts | 2 +- src/generators/rust/RustFileGenerator.ts | 4 ++-- src/generators/rust/RustGenerator.ts | 2 +- src/generators/template/TemplateFileGenerator.ts | 2 +- src/generators/typescript/TypeScriptFileGenerator.ts | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/generators/cplusplus/CplusplusFileGenerator.ts b/src/generators/cplusplus/CplusplusFileGenerator.ts index d57022af85..71281a7ccb 100644 --- a/src/generators/cplusplus/CplusplusFileGenerator.ts +++ b/src/generators/cplusplus/CplusplusFileGenerator.ts @@ -16,7 +16,7 @@ export class CplusplusFileGenerator * @param options */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options?: CplusplusRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/csharp/CSharpFileGenerator.ts b/src/generators/csharp/CSharpFileGenerator.ts index da32f8f90e..8ac2c618bb 100644 --- a/src/generators/csharp/CSharpFileGenerator.ts +++ b/src/generators/csharp/CSharpFileGenerator.ts @@ -18,7 +18,7 @@ export class CSharpFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: DeepPartial, ensureFilesWritten = false diff --git a/src/generators/dart/DartFileGenerator.ts b/src/generators/dart/DartFileGenerator.ts index f00a800a53..f85d0c374a 100644 --- a/src/generators/dart/DartFileGenerator.ts +++ b/src/generators/dart/DartFileGenerator.ts @@ -17,7 +17,7 @@ export class DartFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: DartRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/go/GoFileGenerator.ts b/src/generators/go/GoFileGenerator.ts index 785a47a0de..0324932955 100644 --- a/src/generators/go/GoFileGenerator.ts +++ b/src/generators/go/GoFileGenerator.ts @@ -17,7 +17,7 @@ export class GoFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: GoRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/java/JavaFileGenerator.ts b/src/generators/java/JavaFileGenerator.ts index e9c045fd0b..8aa224e40d 100644 --- a/src/generators/java/JavaFileGenerator.ts +++ b/src/generators/java/JavaFileGenerator.ts @@ -17,7 +17,7 @@ export class JavaFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: JavaRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/javascript/JavaScriptFileGenerator.ts b/src/generators/javascript/JavaScriptFileGenerator.ts index ddebdaae5d..cadfdc6406 100644 --- a/src/generators/javascript/JavaScriptFileGenerator.ts +++ b/src/generators/javascript/JavaScriptFileGenerator.ts @@ -17,7 +17,7 @@ export class JavaScriptFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options?: JavaScriptRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/kotlin/KotlinFileGenerator.ts b/src/generators/kotlin/KotlinFileGenerator.ts index e0686ecae9..446a08738b 100644 --- a/src/generators/kotlin/KotlinFileGenerator.ts +++ b/src/generators/kotlin/KotlinFileGenerator.ts @@ -17,7 +17,7 @@ export class KotlinFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: KotlinRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/php/PhpFileGenerator.ts b/src/generators/php/PhpFileGenerator.ts index 377ba57cfe..90dc949295 100644 --- a/src/generators/php/PhpFileGenerator.ts +++ b/src/generators/php/PhpFileGenerator.ts @@ -17,7 +17,7 @@ export class PhpFileGenerator * @param ensureFilesWritten */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options?: PhpRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/python/PythonFileGenerator.ts b/src/generators/python/PythonFileGenerator.ts index 79854bec8b..46b2fecbc4 100644 --- a/src/generators/python/PythonFileGenerator.ts +++ b/src/generators/python/PythonFileGenerator.ts @@ -17,7 +17,7 @@ export class PythonFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: PythonRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/rust/RustFileGenerator.ts b/src/generators/rust/RustFileGenerator.ts index 5264aad16b..8a6b8609c3 100644 --- a/src/generators/rust/RustFileGenerator.ts +++ b/src/generators/rust/RustFileGenerator.ts @@ -17,7 +17,7 @@ export class RustFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: RustRenderCompleteModelOptions, ensureFilesWritten = false @@ -50,7 +50,7 @@ export class RustFileGenerator * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToPackage( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options: RustRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/rust/RustGenerator.ts b/src/generators/rust/RustGenerator.ts index 758f5e2d60..c979bebbaa 100644 --- a/src/generators/rust/RustGenerator.ts +++ b/src/generators/rust/RustGenerator.ts @@ -419,7 +419,7 @@ export class RustGenerator extends AbstractGenerator< } async generateCompleteSupport( - input: Record | InputMetaModel, + input: any | InputMetaModel, completeModelOptions: Partial, options?: DeepPartial ): Promise { diff --git a/src/generators/template/TemplateFileGenerator.ts b/src/generators/template/TemplateFileGenerator.ts index 495a3851ad..cc92e87e1f 100644 --- a/src/generators/template/TemplateFileGenerator.ts +++ b/src/generators/template/TemplateFileGenerator.ts @@ -16,7 +16,7 @@ export class TemplateFileGenerator * @param options */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options?: TemplateRenderCompleteModelOptions, ensureFilesWritten = false diff --git a/src/generators/typescript/TypeScriptFileGenerator.ts b/src/generators/typescript/TypeScriptFileGenerator.ts index 345937d4e4..06b59aa43d 100644 --- a/src/generators/typescript/TypeScriptFileGenerator.ts +++ b/src/generators/typescript/TypeScriptFileGenerator.ts @@ -13,7 +13,7 @@ export class TypeScriptFileGenerator extends TypeScriptGenerator { * @param ensureFilesWritten verify that the files is completely written before returning, this can happen if the file system is swamped with write requests. */ public async generateToFiles( - input: Record | InputMetaModel, + input: any | InputMetaModel, outputDirectory: string, options?: TypeScriptRenderCompleteModelOptions, ensureFilesWritten = false From 0268121a74ea8c92d56cf22b711e1e65d080f4e7 Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Sun, 19 Nov 2023 11:46:37 +0530 Subject: [PATCH 7/9] docs: added example and docs --- examples/file-uri-input/README.md | 17 ++++++ .../__snapshots__/index.spec.ts.snap | 59 +++++++++++++++++++ examples/file-uri-input/index.spec.ts | 26 ++++++++ examples/file-uri-input/index.ts | 26 ++++++++ examples/file-uri-input/package-lock.json | 10 ++++ examples/file-uri-input/package.json | 10 ++++ examples/file-uri-input/testasyncapi.yml | 23 ++++++++ 7 files changed, 171 insertions(+) create mode 100644 examples/file-uri-input/README.md create mode 100644 examples/file-uri-input/__snapshots__/index.spec.ts.snap create mode 100644 examples/file-uri-input/index.spec.ts create mode 100644 examples/file-uri-input/index.ts create mode 100644 examples/file-uri-input/package-lock.json create mode 100644 examples/file-uri-input/package.json create mode 100644 examples/file-uri-input/testasyncapi.yml diff --git a/examples/file-uri-input/README.md b/examples/file-uri-input/README.md new file mode 100644 index 0000000000..92f3825ff5 --- /dev/null +++ b/examples/file-uri-input/README.md @@ -0,0 +1,17 @@ +# Generate models using file URI as input + +A basic example of how to generate models using file URI as input for AsyncAPI + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/file-uri-input/__snapshots__/index.spec.ts.snap b/examples/file-uri-input/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..a563fe8ae8 --- /dev/null +++ b/examples/file-uri-input/__snapshots__/index.spec.ts.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate models using file URI as input to output folder and should log expected output to console 1`] = ` +Array [ + "class AnonymousSchema_1 { + private _displayName?: string; + private _email?: string; + private _additionalProperties?: Map; + + constructor(input: { + displayName?: string, + email?: string, + additionalProperties?: Map, + }) { + this._displayName = input.displayName; + this._email = input.email; + this._additionalProperties = input.additionalProperties; + } + + get displayName(): string | undefined { return this._displayName; } + set displayName(displayName: string | undefined) { this._displayName = displayName; } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } + + get additionalProperties(): Map | undefined { return this._additionalProperties; } + set additionalProperties(additionalProperties: Map | undefined) { this._additionalProperties = additionalProperties; } +}", +] +`; + +exports[`Should be able to render models using file URI as input and should log expected output to console 1`] = ` +Array [ + "class AnonymousSchema_1 { + private _displayName?: string; + private _email?: string; + private _additionalProperties?: Map; + + constructor(input: { + displayName?: string, + email?: string, + additionalProperties?: Map, + }) { + this._displayName = input.displayName; + this._email = input.email; + this._additionalProperties = input.additionalProperties; + } + + get displayName(): string | undefined { return this._displayName; } + set displayName(displayName: string | undefined) { this._displayName = displayName; } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } + + get additionalProperties(): Map | undefined { return this._additionalProperties; } + set additionalProperties(additionalProperties: Map | undefined) { this._additionalProperties = additionalProperties; } +}", +] +`; diff --git a/examples/file-uri-input/index.spec.ts b/examples/file-uri-input/index.spec.ts new file mode 100644 index 0000000000..428b0cf504 --- /dev/null +++ b/examples/file-uri-input/index.spec.ts @@ -0,0 +1,26 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { + return; +}); +import { generate, generateToFiles } from './index'; + +describe('Should be able to render models using file URI as input', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); +}); + +describe('Should be able to generate models using file URI as input to output folder', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generateToFiles(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); +}); diff --git a/examples/file-uri-input/index.ts b/examples/file-uri-input/index.ts new file mode 100644 index 0000000000..30fd45356a --- /dev/null +++ b/examples/file-uri-input/index.ts @@ -0,0 +1,26 @@ +import path from 'path'; +import { TypeScriptFileGenerator, TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator(); +const fileGenerator = new TypeScriptFileGenerator(); + +export async function generate(): Promise { + const fileUri = `file://${path.resolve(__dirname, './testasyncapi.yml')}`; + const models = await generator.generate(fileUri); + for (const model of models) { + console.log(model.result); + } +} + +export async function generateToFiles(): Promise { + const outputFolder = './examples/file-uri-input/output'; + const fileUri = `file://${path.resolve(__dirname, './testasyncapi.yml')}`; + const models = await fileGenerator.generateToFiles(fileUri, outputFolder); + for (const model of models) { + console.log(model.result); + } +} +if (require.main === module) { + generate(); + generateToFiles(); +} diff --git a/examples/file-uri-input/package-lock.json b/examples/file-uri-input/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/file-uri-input/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/file-uri-input/package.json b/examples/file-uri-input/package.json new file mode 100644 index 0000000000..c62bc2362b --- /dev/null +++ b/examples/file-uri-input/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "TEMPLATE" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} diff --git a/examples/file-uri-input/testasyncapi.yml b/examples/file-uri-input/testasyncapi.yml new file mode 100644 index 0000000000..fbb3f891b7 --- /dev/null +++ b/examples/file-uri-input/testasyncapi.yml @@ -0,0 +1,23 @@ +asyncapi: '2.6.0' +info: + title: Account Service + version: 1.0.0 + description: This service is in charge of processing user signups +channels: + user/signedup: + subscribe: + message: + $ref: '#/components/messages/UserSignedUp' +components: + messages: + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user \ No newline at end of file From 653439e6d0281184a250ee30e475d427ce636299 Mon Sep 17 00:00:00 2001 From: nilkanth987 Date: Tue, 21 Nov 2023 18:11:24 +0530 Subject: [PATCH 8/9] fix: lint issue fixed --- src/processors/AsyncAPIInputProcessor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/processors/AsyncAPIInputProcessor.ts b/src/processors/AsyncAPIInputProcessor.ts index f27e029172..1ec4469439 100644 --- a/src/processors/AsyncAPIInputProcessor.ts +++ b/src/processors/AsyncAPIInputProcessor.ts @@ -423,6 +423,7 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { async getParsedFileInput(input: string): Promise { const filePath = fileURLToPath(input); + /* eslint-disable-next-line security/detect-non-literal-fs-filename -- Safe as it just checks file existance */ if (!fs.existsSync(filePath)) { throw new Error('File does not exists.'); } From 453128859f5778b5693994930335708844bcfd46 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Wed, 22 Nov 2023 09:49:39 -1000 Subject: [PATCH 9/9] Update examples/file-uri-input/package.json --- examples/file-uri-input/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/file-uri-input/package.json b/examples/file-uri-input/package.json index c62bc2362b..4dd081d2e1 100644 --- a/examples/file-uri-input/package.json +++ b/examples/file-uri-input/package.json @@ -1,5 +1,5 @@ { - "config" : { "example_name" : "TEMPLATE" }, + "config" : { "example_name" : "file-uri-input" }, "scripts": { "install": "cd ../.. && npm i", "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts",