From 6e66aa365d3dd4d73e3d47310af3c5d753365323 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 7 Nov 2023 01:21:08 -1000 Subject: [PATCH] fix: disclose limitation about parameter schema reference (#192) Co-authored-by: Lukasz Gornicki --- README.md | 31 +++++++++++++- src/third-version.ts | 41 +++++++++++++++---- .../2.6.0/for-3.0.0-with-mixed-parameters.yml | 7 ++++ .../for-3.0.0-with-reference-parameter.yml | 30 ++++++++++++++ .../from-2.6.0-with-mixed-parameters.yml | 5 +++ .../from-2.6.0-with-reference-parameter.yml | 31 ++++++++++++++ test/second-to-third-version.spec.ts | 7 ++++ 7 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 test/input/2.6.0/for-3.0.0-with-reference-parameter.yml create mode 100644 test/output/3.0.0/from-2.6.0-with-reference-parameter.yml diff --git a/README.md b/README.md index 808bad14..39831bcf 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ try { > **NOTE**: This feature is still WIP, and is until the final release of `3.0.0`. -Conversion to version `3.x.x` from `2.x.x` has several assumptions that should be know before converting: +Conversion to version `3.x.x` from `2.x.x` has several assumptions that should be known before converting: - The input must be valid AsyncAPI document. - External references are not resolved and converted, they remain untouched, even if they are incorrect. @@ -164,6 +164,35 @@ Conversion to version `3.x.x` from `2.x.x` has several assumptions that should b ## Known missing features * When converting from 1.x to 2.x, Streaming APIs (those using `stream` instead of `topics` or `events`) are converted correctly but information about framing type and delimiter is missing until a [protocolInfo](https://github.com/asyncapi/extensions-catalog/issues/1) for that purpose is created. +* When converting from 2.x to 3.x, and `parameter.schema` is defined with a reference, it will NOT look into the schema reference and include any relevant keywords for the v3 parameter. It will just create an empty parameter but leave the schema in the components section as is. + ```yaml + # 2.x.x + channels: + "{myParameter}": + parameters: + myParameter: + schema: + $ref: "#/components/schemas/mySchema" + components: + schemas: + mySchema: + enum: ["test"] + default: "test" + examples: ["test"] + + # 3.0.0 + channels: + "{myParameter}": + parameters: + myParameter: {} + + components: + schemas: + mySchema: + enum: ["test"] + default: "test" + examples: ["test"] + ``` ## Development diff --git a/src/third-version.ts b/src/third-version.ts index b5d91153..01af8c4e 100644 --- a/src/third-version.ts +++ b/src/third-version.ts @@ -18,6 +18,7 @@ function from__2_6_0__to__3_0_0(asyncapi: AsyncAPIDocument, options: ConvertOpti useChannelIdExtension: true, convertServerComponents: true, convertChannelComponents: true, + failOnParameterReference: false, ...(options.v2tov3 ?? {}), } as RequiredConvertV2ToV3Options; v2tov3Options.idGenerator = v2tov3Options.idGenerator || idGeneratorFactory(v2tov3Options); @@ -377,6 +378,7 @@ function convertParameters(parameters: Record): Record }); return newParameters; } + /** * Convert the old v2 parameter object to v3. * @@ -392,11 +394,18 @@ function convertParameter(parameter: any): any { } } + if(parameter.schema?.$ref) { + console.warn('Could not convert parameter object because the `.schema` property was a reference.\nThis have to be changed manually if you want any of the properties included. For now your parameter is an empty object after conversion. The reference was ' + parameter.schema?.$ref); + } + const enumValues = parameter.schema?.enum ?? null; + const constValue = parameter.schema?.const ?? null; const defaultValues = parameter.schema?.default ?? null; const description = parameter.description ?? parameter.schema?.description ?? null; const examples = parameter.schema?.examples ?? null; const location = parameter.location ?? null; + + reportUnsupportedParameterValues(parameter.schema); //Make sure we keep parameter extensions const v2ParameterObjectProperties = ["location", "schema", "description"]; @@ -405,14 +414,32 @@ function convertParameter(parameter: any): any { }); //Return the new v3 parameter object - return Object.assign({...v2ParameterObjectExtensions}, - enumValues === null ? null : {enum: enumValues}, - defaultValues === null ? null : {default: defaultValues}, - description === null ? null : {description}, - examples === null ? null : {examples}, - location === null ? null : {location} - ); + return {...v2ParameterObjectExtensions, + ...(enumValues === null ? null : {enum: enumValues}), + ...(constValue === null ? null : {enum: [constValue]}), + ...(defaultValues === null ? null : {default: defaultValues}), + ...(description === null ? null : {description}), + ...(examples === null ? null : {examples}), + ...(location === null ? null : {location}) + }; } + +/** + * This function makes sure we complain if a parameter schema uses now unsupported properties + */ +function reportUnsupportedParameterValues(schema: any) { + if(schema === undefined) return; + const excessProperties = Object.entries(schema).filter((([propertyName,]) => { + return !['$ref', 'enum', 'const', 'default', 'examples', 'description'].includes(propertyName); + })); + if(excessProperties.length > 0) { + const listOfProperties = excessProperties.map(([propertyName, property]) => { + return `- schema.${propertyName} with value: ${JSON.stringify(property)} are no longer supported` + }) + console.warn(`Found properties in parameter schema that are no longer supported. Conversion completes with empty parameter object.\n${listOfProperties.join('\n')}`); + } +} + /** * Convert `channels`, `servers` and `securitySchemes` in components. */ diff --git a/test/input/2.6.0/for-3.0.0-with-mixed-parameters.yml b/test/input/2.6.0/for-3.0.0-with-mixed-parameters.yml index 522c919c..452b15da 100644 --- a/test/input/2.6.0/for-3.0.0-with-mixed-parameters.yml +++ b/test/input/2.6.0/for-3.0.0-with-mixed-parameters.yml @@ -19,7 +19,14 @@ channels: $ref: '#/components/parameters/location' mixed: $ref: '#/components/parameters/mixed' + schemaRef: + schema: + $ref: '#/components/schemas/schemaParameter' components: + schemas: + schemaParameter: + type: string + enum: ["test"] parameters: enum: schema: diff --git a/test/input/2.6.0/for-3.0.0-with-reference-parameter.yml b/test/input/2.6.0/for-3.0.0-with-reference-parameter.yml new file mode 100644 index 00000000..d82767a1 --- /dev/null +++ b/test/input/2.6.0/for-3.0.0-with-reference-parameter.yml @@ -0,0 +1,30 @@ +asyncapi: 2.6.0 + +info: + title: AsyncAPI Sample App + version: 1.0.1 + +channels: + 'lightingMeasured/{parameter}/{parameter2}': + parameters: + parameter: + schema: + $ref: '#/components/schemas/sentAt' + parameter2: + schema: + pattern: test + publish: + operationId: lightMeasured + message: + payload: + type: object + properties: + someProperty: + type: string + +components: + schemas: + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. \ No newline at end of file diff --git a/test/output/3.0.0/from-2.6.0-with-mixed-parameters.yml b/test/output/3.0.0/from-2.6.0-with-mixed-parameters.yml index 44d40cbd..54005b32 100644 --- a/test/output/3.0.0/from-2.6.0-with-mixed-parameters.yml +++ b/test/output/3.0.0/from-2.6.0-with-mixed-parameters.yml @@ -19,7 +19,12 @@ channels: $ref: '#/components/parameters/location' mixed: $ref: '#/components/parameters/mixed' + schemaRef: {} components: + schemas: + schemaParameter: + type: string + enum: ["test"] parameters: enum: enum: ["test"] diff --git a/test/output/3.0.0/from-2.6.0-with-reference-parameter.yml b/test/output/3.0.0/from-2.6.0-with-reference-parameter.yml new file mode 100644 index 00000000..4e885347 --- /dev/null +++ b/test/output/3.0.0/from-2.6.0-with-reference-parameter.yml @@ -0,0 +1,31 @@ +asyncapi: 3.0.0 +info: + title: AsyncAPI Sample App + version: 1.0.1 +channels: + 'lightingMeasured/{parameter}/{parameter2}': + address: 'lightingMeasured/{parameter}/{parameter2}' + messages: + lightMeasured.message: + payload: + type: object + properties: + someProperty: + type: string + parameters: + parameter: {} + parameter2: {} +operations: + lightMeasured: + action: receive + channel: + $ref: '#/channels/lightingMeasured~1{parameter}~1{parameter2}' + messages: + - $ref: >- + #/channels/lightingMeasured~1{parameter}~1{parameter2}/messages/lightMeasured.message +components: + schemas: + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. diff --git a/test/second-to-third-version.spec.ts b/test/second-to-third-version.spec.ts index 5304e262..32de63e4 100644 --- a/test/second-to-third-version.spec.ts +++ b/test/second-to-third-version.spec.ts @@ -32,4 +32,11 @@ describe('convert() - 2.X.X to 3.X.X versions', () => { const result = convert(input, '3.0.0'); assertResults(output, result); }); + + it('should handle parameter object', () => { + const input = fs.readFileSync(path.resolve(__dirname, 'input', '2.6.0', 'for-3.0.0-with-reference-parameter.yml'), 'utf8'); + const output = fs.readFileSync(path.resolve(__dirname, 'output', '3.0.0', 'from-2.6.0-with-reference-parameter.yml'), 'utf8'); + const result = convert(input, '3.0.0'); + assertResults(output, result); + }); });