Skip to content

Commit

Permalink
overlay: keep comments and linewidth when dumping to YAML
Browse files Browse the repository at this point in the history
If the original file is YAML and the target overlayed definition is
YAML, we now preserve comments from the original document and also
keep the same line width as the original file.
  • Loading branch information
paulRbr committed Dec 17, 2024
1 parent 63d20d7 commit e35e813
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 4 deletions.
177 changes: 177 additions & 0 deletions examples/valid/asyncapi.v2.overlayed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Some comments in the API definition
asyncapi: 2.2.0
info:
title: Streetlights API
version: 1.0.0
description: |
Turn lights on or off. And get notified when lights are dimmed or switched.
license:
name: Apache 2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0'
servers:
# This is a Production MQTT server
production:
url: 'test.mosquitto.org:{port}'
protocol: mqtt
description: Test broker
variables:
port:
description: Secure connection (TLS) is available through port 8883.
default: '1883'
enum:
- '1883'
- '8883'
security:
- apiKey: []
- supportedOauthFlows:
- 'streetlights:on'
- 'streetlights:off'
- 'streetlights:dim'
- openIdConnectWellKnown: []
defaultContentType: application/json
channels:
'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured':
description: The topic on which measured values may be produced and consumed.
parameters:
streetlightId:
$ref: 'http://example.org/param-lights.json'
publish:
summary: Inform about environmental lighting conditions of a particular streetlight.
operationId: receiveLightMeasurement
traits:
- $ref: ./traits/kafka.yml
message:
$ref: '#/components/messages/lightMeasured'
'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on':
parameters:
streetlightId:
$ref: ./params/streetlightId.json
subscribe:
operationId: turnOn
traits:
- $ref: ./traits/kafka.yml
message:
$ref: '#/components/messages/turnOnOff'
'smartylighting/streetlights/1/0/action/{streetlightId}/turn/off':
parameters:
streetlightId:
$ref: ./params/streetlightId.json
'smartylighting/streetlights/1/0/action/{streetlightId}/dim':
parameters:
streetlightId:
$ref: params/streetlightId.json
subscribe:
operationId: dimLight
traits:
- $ref: ./traits/kafka.yml
message:
$ref: '#/components/messages/dimLight'
components:
messages:
lightMeasured:
name: lightMeasured
title: Light measured
summary: Inform about environmental lighting conditions of a particular streetlight.
contentType: application/json
traits:
- $ref: '#/components/messageTraits/commonHeaders'
payload:
$ref: '#/components/schemas/lightMeasuredPayload'
turnOnOff:
name: turnOnOff
title: Turn on/off
summary: Command a particular streetlight to turn the lights on or off.
traits:
- $ref: '#/components/messageTraits/commonHeaders'
payload:
$ref: '#/components/schemas/turnOnOffPayload'
dimLight:
name: dimLight
title: Dim light
summary: Command a particular streetlight to dim the lights.
traits:
- $ref: '#/components/messageTraits/commonHeaders'
payload:
$ref: '#/components/schemas/dimLightPayload'
schemas:
lightMeasuredPayload:
type: object
properties:
lumens:
type: integer
minimum: 0
description: Light intensity measured in lumens.
sentAt:
$ref: '#/components/schemas/sentAt'
turnOnOffPayload:
type: object
properties:
command:
type: string
enum:
- 'on'
- 'off'
description: Whether to turn on or off the light.
sentAt:
$ref: '#/components/schemas/sentAt'
dimLightPayload:
type: object
properties:
percentage:
type: integer
description: Percentage to which the light should be dimmed to.
minimum: 0
maximum: 100
sentAt:
$ref: '#/components/schemas/sentAt'
sentAt:
type: string
format: date-time
description: Date and time when the message was sent.
securitySchemes:
apiKey:
type: apiKey
in: user
description: Provide your API key as the user and leave the password empty.
supportedOauthFlows:
type: oauth2
description: Flows to support OAuth 2.0
flows:
implicit:
authorizationUrl: 'https://authserver.example/auth'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
password:
tokenUrl: 'https://authserver.example/token'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
clientCredentials:
tokenUrl: 'https://authserver.example/token'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
authorizationCode:
authorizationUrl: 'https://authserver.example/auth'
tokenUrl: 'https://authserver.example/token'
refreshUrl: 'https://authserver.example/refresh'
scopes:
'streetlights:on': Ability to switch lights on
'streetlights:off': Ability to switch lights off
'streetlights:dim': Ability to dim the lights
openIdConnectWellKnown:
type: openIdConnect
openIdConnectUrl: 'https://authserver.example/.well-known'
messageTraits:
commonHeaders:
headers:
type: object
properties:
my-app-header:
type: integer
minimum: 0
maximum: 100
3 changes: 3 additions & 0 deletions examples/valid/asyncapi.v2.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Some comments in the API definition
asyncapi: '2.2.0'
info:
title: Streetlights API
Expand All @@ -9,6 +10,7 @@ info:
url: https://www.apache.org/licenses/LICENSE-2.0

servers:
# This is a Production MQTT server
production:
url: test.mosquitto.org:{port}
protocol: mqtt
Expand Down Expand Up @@ -60,6 +62,7 @@ channels:
streetlightId:
$ref: './params/streetlightId.json'
subscribe:
x-beta: true
operationId: turnOff
traits:
- $ref: './traits/kafka.yml'
Expand Down
13 changes: 13 additions & 0 deletions examples/valid/overlay-async.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
overlay: 1.0.0
info:
title: Overlay to customise API for Streetlights
version: 0.0.1
actions:
- target: '$.info.description'
description: Provide a better introduction for our end users than this techno babble.
update: |
Turn lights on or off. And get notified when lights are dimmed or switched.
- target: '$..[?(@["x-beta"]==true)]'
description: Remove all beta operations
remove: true
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions src/definition.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {default as $RefParser, getJsonSchemaRefParserDefaultOptions} from '@apidevtools/json-schema-ref-parser'
import asyncapi from '@asyncapi/specs'
import {CLIError} from '@oclif/core/errors'
import {safeStringify} from '@stoplight/yaml'
import {parseWithPointers, safeStringify} from '@stoplight/yaml'
import debug from 'debug'
import {
JSONSchema4,
Expand Down Expand Up @@ -277,9 +277,11 @@ class API {

serializeDefinition(outputPath?: string): string {
if (this.overlayedDefinition) {
const {comments} = parseWithPointers(this.rawDefinition, {attachComments: true})
const dumpOptions = {comments, lineWidth: Number.POSITIVE_INFINITY}
return this.guessFormat(outputPath) === 'json'
? JSON.stringify(this.overlayedDefinition)
: safeStringify(this.overlayedDefinition)
: safeStringify(this.overlayedDefinition, dumpOptions)
}

return this.rawDefinition
Expand Down
16 changes: 15 additions & 1 deletion test/unit/definition.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as YAML from '@stoplight/yaml'
import {expect} from 'chai'
import nock from 'nock'
import * as fs from 'node:fs'
import path from 'node:path'

import {API, APIDefinition} from '../../src/definition'
Expand Down Expand Up @@ -136,7 +137,20 @@ describe('API class', () => {

expect(api.serializeDefinition()).to.equal(JSON.stringify(api.overlayedDefinition))

expect(api.serializeDefinition('destination/file.yaml')).to.equal(YAML.safeStringify(api.overlayedDefinition))
expect(api.serializeDefinition('destination/file.yaml')).to.equal(
YAML.safeStringify(api.overlayedDefinition, {lineWidth: Number.POSITIVE_INFINITY}),
)
})

it('preserves line width and YAML comments', async () => {
nock('http://example.org').get('/param-lights.json').reply(200, {})

const api = await API.load('examples/valid/asyncapi.v2.yml')
await api.applyOverlay('examples/valid/overlay-async.yaml')

expect(api.serializeDefinition()).to.equal(
fs.readFileSync('examples/valid/asyncapi.v2.overlayed.yml', 'utf8').replaceAll('\r', ''),
)
})
})
})
Expand Down

0 comments on commit e35e813

Please sign in to comment.