Skip to content

Commit

Permalink
fix: disclose limitation about parameter schema reference (#192)
Browse files Browse the repository at this point in the history
Co-authored-by: Lukasz Gornicki <[email protected]>
  • Loading branch information
jonaslagoni and derberg authored Nov 7, 2023
1 parent 7e91d4c commit 6e66aa3
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 8 deletions.
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down
41 changes: 34 additions & 7 deletions src/third-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -377,6 +378,7 @@ function convertParameters(parameters: Record<string, any>): Record<string, any>
});
return newParameters;
}

/**
* Convert the old v2 parameter object to v3.
*
Expand All @@ -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"];
Expand All @@ -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.
*/
Expand Down
7 changes: 7 additions & 0 deletions test/input/2.6.0/for-3.0.0-with-mixed-parameters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
30 changes: 30 additions & 0 deletions test/input/2.6.0/for-3.0.0-with-reference-parameter.yml
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 5 additions & 0 deletions test/output/3.0.0/from-2.6.0-with-mixed-parameters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
31 changes: 31 additions & 0 deletions test/output/3.0.0/from-2.6.0-with-reference-parameter.yml
Original file line number Diff line number Diff line change
@@ -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.
7 changes: 7 additions & 0 deletions test/second-to-third-version.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});

0 comments on commit 6e66aa3

Please sign in to comment.