diff --git a/src/overlay.js b/src/overlay.js index 2cbce19..d7df86a 100644 --- a/src/overlay.js +++ b/src/overlay.js @@ -22,9 +22,14 @@ function applyOverlayToOpenAPI(spec, overlay) { 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 (Array.isArray(chunk) && Array.isArray(a.update)) { + // Concat arrays if target and update are both array objects + return chunk.concat(a.update); + } else { + // Deep merge objects using a module (built-in spread operator is only shallow) + const merger = mergician({ appendArrays: true }); + return merger(chunk, a.update); + } }); } catch (ex) { diff --git a/test/expected/town-update-array.yaml b/test/expected/town-update-array.yaml new file mode 100644 index 0000000..8125f8a --- /dev/null +++ b/test/expected/town-update-array.yaml @@ -0,0 +1,72 @@ +openapi: 3.1.0 +info: + version: 1.0.0 + title: Imaginary town +servers: + - url: 'https://example.com' + description: Example server + - url: 'https://example.com/prod' + description: Production 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 29a3a60..d96b05c 100644 --- a/test/overlay.test.js +++ b/test/overlay.test.js @@ -59,6 +59,17 @@ test('remove all description fields', () => { expect(result).toEqual(expectedOutput); }); +test('concatenate lists when target is an array type', () => { + const openapiFile = "test/openapi/town.yaml"; + const overlayFile = "test/overlays/update-array.yaml"; + const expectedFile = "test/expected/town-update-array.yaml"; + const expectedOutput = fs.readFileSync(expectedFile, 'utf8'); + + const result = overlayFiles(openapiFile, overlayFile); + + expect(result).toEqual(expectedOutput); +}); + test('fail to update a primitive string type', () => { const openapiFile = "test/openapi/immutable.yaml"; const overlayFile = "test/overlays/immutable.yaml"; diff --git a/test/overlays/update-array.yaml b/test/overlays/update-array.yaml new file mode 100644 index 0000000..43be651 --- /dev/null +++ b/test/overlays/update-array.yaml @@ -0,0 +1,9 @@ +overlay: 1.0.0 +info: + title: Structured Overlay + version: 1.0.0 +actions: +- target: $.servers + update: + - url: https://example.com/prod + description: Production server