diff --git a/src/overlay.js b/src/overlay.js index 0994111..d732d88 100644 --- a/src/overlay.js +++ b/src/overlay.js @@ -25,11 +25,11 @@ function applyOverlayToOpenAPI (spec, overlay) { } else { try { // It must be an update - jsonpath.apply(spec, a.target, (chunk) => { - // Deep merge using a module (built-in spread operator is only shallow) - const merger = mergician({ appendArrays: true }) - return merger(chunk, a.update) - }) + if (a.target === '$') { + spec = merger(a.update)(spec) + } else { + jsonpath.apply(spec, a.target, merger(a.update)) + } } catch (ex) { process.stderr.write(`Error applying overlay: ${ex.message}\n`) // return chunk @@ -41,6 +41,13 @@ function applyOverlayToOpenAPI (spec, overlay) { return spec } +// Deep merge using a module (built-in spread operator is only shallow) +function merger (obj) { + return (chunk) => { + return mergician({ appendArrays: true })(chunk, obj) + } +} + function sortOpenAPIFields (field1, field2) { const orderedKeys = ['info', 'servers', 'summary', 'operationId', 'tags', 'paths', 'components', 'description', 'parameters', 'responses'] diff --git a/test/expected/town-root-updated.yaml b/test/expected/town-root-updated.yaml new file mode 100644 index 0000000..22fbe70 --- /dev/null +++ b/test/expected/town-root-updated.yaml @@ -0,0 +1,71 @@ +openapi: 3.1.0 +info: + version: 1.0.0 + title: Imaginary town + x-overlaid: true +servers: + - url: 'https://example.com' + description: Example server +paths: + /buildings: + get: + summary: All buildings + operationId: buildingsList + responses: + '200': + description: Return all known buildings + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Building' + '/buildings/{buildingId}': + get: + summary: Specific building + operationId: buildingById + parameters: + - name: buildingId + in: path + required: true + description: Which building to return + schema: + type: string + responses: + '200': + description: Return a building + content: + application/json: + schema: + $ref: '#/components/schemas/Building' + /locations: + get: + summary: All locations + operationId: locationList + responses: + '200': + description: Returns all locations + content: + application/json: + schema: + type: array + items: + type: object + properties: + location_id: + type: integer + example: 44 + name: + type: string + example: North Village +components: + schemas: + Building: + type: object + properties: + building: + type: string + example: house + location_id: + type: integer + example: 44 diff --git a/test/overlay.test.js b/test/overlay.test.js index 60d921f..db7d740 100644 --- a/test/overlay.test.js +++ b/test/overlay.test.js @@ -23,6 +23,17 @@ test('add a description and update the summary', () => { expect(result).toEqual(expectedOutput) }) +test('apply an overlay to the root object', () => { + const openapiFile = 'test/openapi/town.yaml' + const overlayFile = 'test/overlays/update-root.yaml' + const expectedFile = 'test/expected/town-root-updated.yaml' + const expectedOutput = fs.readFileSync(expectedFile, 'utf8') + + const result = overlayFiles(openapiFile, overlayFile) + + expect(result).toEqual(expectedOutput) +}) + test('remove an example', () => { const openapiFile = 'test/openapi/town.yaml' const overlayFile = 'test/overlays/remove-example.yaml' diff --git a/test/overlays/update-root.yaml b/test/overlays/update-root.yaml new file mode 100644 index 0000000..606ec8f --- /dev/null +++ b/test/overlays/update-root.yaml @@ -0,0 +1,9 @@ +overlay: 1.0.0 +info: + title: Structured Overlay + version: 1.0.0 +actions: +- target: "$" # Root of document + update: + info: + x-overlaid: true