Skip to content

Commit e35e813

Browse files
committed
overlay: keep comments and linewidth when dumping to YAML
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.
1 parent 63d20d7 commit e35e813

File tree

6 files changed

+218
-4
lines changed

6 files changed

+218
-4
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Some comments in the API definition
2+
asyncapi: 2.2.0
3+
info:
4+
title: Streetlights API
5+
version: 1.0.0
6+
description: |
7+
Turn lights on or off. And get notified when lights are dimmed or switched.
8+
license:
9+
name: Apache 2.0
10+
url: 'https://www.apache.org/licenses/LICENSE-2.0'
11+
servers:
12+
# This is a Production MQTT server
13+
production:
14+
url: 'test.mosquitto.org:{port}'
15+
protocol: mqtt
16+
description: Test broker
17+
variables:
18+
port:
19+
description: Secure connection (TLS) is available through port 8883.
20+
default: '1883'
21+
enum:
22+
- '1883'
23+
- '8883'
24+
security:
25+
- apiKey: []
26+
- supportedOauthFlows:
27+
- 'streetlights:on'
28+
- 'streetlights:off'
29+
- 'streetlights:dim'
30+
- openIdConnectWellKnown: []
31+
defaultContentType: application/json
32+
channels:
33+
'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured':
34+
description: The topic on which measured values may be produced and consumed.
35+
parameters:
36+
streetlightId:
37+
$ref: 'http://example.org/param-lights.json'
38+
publish:
39+
summary: Inform about environmental lighting conditions of a particular streetlight.
40+
operationId: receiveLightMeasurement
41+
traits:
42+
- $ref: ./traits/kafka.yml
43+
message:
44+
$ref: '#/components/messages/lightMeasured'
45+
'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on':
46+
parameters:
47+
streetlightId:
48+
$ref: ./params/streetlightId.json
49+
subscribe:
50+
operationId: turnOn
51+
traits:
52+
- $ref: ./traits/kafka.yml
53+
message:
54+
$ref: '#/components/messages/turnOnOff'
55+
'smartylighting/streetlights/1/0/action/{streetlightId}/turn/off':
56+
parameters:
57+
streetlightId:
58+
$ref: ./params/streetlightId.json
59+
'smartylighting/streetlights/1/0/action/{streetlightId}/dim':
60+
parameters:
61+
streetlightId:
62+
$ref: params/streetlightId.json
63+
subscribe:
64+
operationId: dimLight
65+
traits:
66+
- $ref: ./traits/kafka.yml
67+
message:
68+
$ref: '#/components/messages/dimLight'
69+
components:
70+
messages:
71+
lightMeasured:
72+
name: lightMeasured
73+
title: Light measured
74+
summary: Inform about environmental lighting conditions of a particular streetlight.
75+
contentType: application/json
76+
traits:
77+
- $ref: '#/components/messageTraits/commonHeaders'
78+
payload:
79+
$ref: '#/components/schemas/lightMeasuredPayload'
80+
turnOnOff:
81+
name: turnOnOff
82+
title: Turn on/off
83+
summary: Command a particular streetlight to turn the lights on or off.
84+
traits:
85+
- $ref: '#/components/messageTraits/commonHeaders'
86+
payload:
87+
$ref: '#/components/schemas/turnOnOffPayload'
88+
dimLight:
89+
name: dimLight
90+
title: Dim light
91+
summary: Command a particular streetlight to dim the lights.
92+
traits:
93+
- $ref: '#/components/messageTraits/commonHeaders'
94+
payload:
95+
$ref: '#/components/schemas/dimLightPayload'
96+
schemas:
97+
lightMeasuredPayload:
98+
type: object
99+
properties:
100+
lumens:
101+
type: integer
102+
minimum: 0
103+
description: Light intensity measured in lumens.
104+
sentAt:
105+
$ref: '#/components/schemas/sentAt'
106+
turnOnOffPayload:
107+
type: object
108+
properties:
109+
command:
110+
type: string
111+
enum:
112+
- 'on'
113+
- 'off'
114+
description: Whether to turn on or off the light.
115+
sentAt:
116+
$ref: '#/components/schemas/sentAt'
117+
dimLightPayload:
118+
type: object
119+
properties:
120+
percentage:
121+
type: integer
122+
description: Percentage to which the light should be dimmed to.
123+
minimum: 0
124+
maximum: 100
125+
sentAt:
126+
$ref: '#/components/schemas/sentAt'
127+
sentAt:
128+
type: string
129+
format: date-time
130+
description: Date and time when the message was sent.
131+
securitySchemes:
132+
apiKey:
133+
type: apiKey
134+
in: user
135+
description: Provide your API key as the user and leave the password empty.
136+
supportedOauthFlows:
137+
type: oauth2
138+
description: Flows to support OAuth 2.0
139+
flows:
140+
implicit:
141+
authorizationUrl: 'https://authserver.example/auth'
142+
scopes:
143+
'streetlights:on': Ability to switch lights on
144+
'streetlights:off': Ability to switch lights off
145+
'streetlights:dim': Ability to dim the lights
146+
password:
147+
tokenUrl: 'https://authserver.example/token'
148+
scopes:
149+
'streetlights:on': Ability to switch lights on
150+
'streetlights:off': Ability to switch lights off
151+
'streetlights:dim': Ability to dim the lights
152+
clientCredentials:
153+
tokenUrl: 'https://authserver.example/token'
154+
scopes:
155+
'streetlights:on': Ability to switch lights on
156+
'streetlights:off': Ability to switch lights off
157+
'streetlights:dim': Ability to dim the lights
158+
authorizationCode:
159+
authorizationUrl: 'https://authserver.example/auth'
160+
tokenUrl: 'https://authserver.example/token'
161+
refreshUrl: 'https://authserver.example/refresh'
162+
scopes:
163+
'streetlights:on': Ability to switch lights on
164+
'streetlights:off': Ability to switch lights off
165+
'streetlights:dim': Ability to dim the lights
166+
openIdConnectWellKnown:
167+
type: openIdConnect
168+
openIdConnectUrl: 'https://authserver.example/.well-known'
169+
messageTraits:
170+
commonHeaders:
171+
headers:
172+
type: object
173+
properties:
174+
my-app-header:
175+
type: integer
176+
minimum: 0
177+
maximum: 100

examples/valid/asyncapi.v2.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# Some comments in the API definition
12
asyncapi: '2.2.0'
23
info:
34
title: Streetlights API
@@ -9,6 +10,7 @@ info:
910
url: https://www.apache.org/licenses/LICENSE-2.0
1011

1112
servers:
13+
# This is a Production MQTT server
1214
production:
1315
url: test.mosquitto.org:{port}
1416
protocol: mqtt
@@ -60,6 +62,7 @@ channels:
6062
streetlightId:
6163
$ref: './params/streetlightId.json'
6264
subscribe:
65+
x-beta: true
6366
operationId: turnOff
6467
traits:
6568
- $ref: './traits/kafka.yml'

examples/valid/overlay-async.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
overlay: 1.0.0
2+
info:
3+
title: Overlay to customise API for Streetlights
4+
version: 0.0.1
5+
actions:
6+
- target: '$.info.description'
7+
description: Provide a better introduction for our end users than this techno babble.
8+
update: |
9+
Turn lights on or off. And get notified when lights are dimmed or switched.
10+
11+
- target: '$..[?(@["x-beta"]==true)]'
12+
description: Remove all beta operations
13+
remove: true

package-lock.json

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/definition.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {default as $RefParser, getJsonSchemaRefParserDefaultOptions} from '@apidevtools/json-schema-ref-parser'
22
import asyncapi from '@asyncapi/specs'
33
import {CLIError} from '@oclif/core/errors'
4-
import {safeStringify} from '@stoplight/yaml'
4+
import {parseWithPointers, safeStringify} from '@stoplight/yaml'
55
import debug from 'debug'
66
import {
77
JSONSchema4,
@@ -277,9 +277,11 @@ class API {
277277

278278
serializeDefinition(outputPath?: string): string {
279279
if (this.overlayedDefinition) {
280+
const {comments} = parseWithPointers(this.rawDefinition, {attachComments: true})
281+
const dumpOptions = {comments, lineWidth: Number.POSITIVE_INFINITY}
280282
return this.guessFormat(outputPath) === 'json'
281283
? JSON.stringify(this.overlayedDefinition)
282-
: safeStringify(this.overlayedDefinition)
284+
: safeStringify(this.overlayedDefinition, dumpOptions)
283285
}
284286

285287
return this.rawDefinition

test/unit/definition.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as YAML from '@stoplight/yaml'
22
import {expect} from 'chai'
33
import nock from 'nock'
4+
import * as fs from 'node:fs'
45
import path from 'node:path'
56

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

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

139-
expect(api.serializeDefinition('destination/file.yaml')).to.equal(YAML.safeStringify(api.overlayedDefinition))
140+
expect(api.serializeDefinition('destination/file.yaml')).to.equal(
141+
YAML.safeStringify(api.overlayedDefinition, {lineWidth: Number.POSITIVE_INFINITY}),
142+
)
143+
})
144+
145+
it('preserves line width and YAML comments', async () => {
146+
nock('http://example.org').get('/param-lights.json').reply(200, {})
147+
148+
const api = await API.load('examples/valid/asyncapi.v2.yml')
149+
await api.applyOverlay('examples/valid/overlay-async.yaml')
150+
151+
expect(api.serializeDefinition()).to.equal(
152+
fs.readFileSync('examples/valid/asyncapi.v2.overlayed.yml', 'utf8').replaceAll('\r', ''),
153+
)
140154
})
141155
})
142156
})

0 commit comments

Comments
 (0)