diff --git a/src/core/plugins/spec/selectors.js b/src/core/plugins/spec/selectors.js index f8fa9a38..78eb44e1 100644 --- a/src/core/plugins/spec/selectors.js +++ b/src/core/plugins/spec/selectors.js @@ -46,9 +46,31 @@ export const specResolvedSubtree = (state, path) => { return state.getIn(["resolvedSubtrees", ...path], undefined) } +const mergerFn = (oldVal, newVal) => { + if(Map.isMap(oldVal) && Map.isMap(newVal)) { + if(newVal.get("$$ref")) { + // resolver artifacts indicated that this key was directly resolved + // so we should drop the old value entirely + return newVal + } + + return Map().mergeWith( + mergerFn, + oldVal, + newVal + ) + } + + return newVal +} + export const specJsonWithResolvedSubtrees = createSelector( state, - spec => Map().merge(spec.get("json"), spec.get("resolvedSubtrees")) + spec => Map().mergeWith( + mergerFn, + spec.get("json"), + spec.get("resolvedSubtrees") + ) ) // Default Spec ( as an object ) @@ -369,7 +391,7 @@ export function contentTypeValues(state, pathMethod) { // Get the consumes/produces by path export function operationConsumes(state, pathMethod) { pathMethod = pathMethod || [] - return state.getIn(["meta", ...pathMethod, "consumes"], fromJS({})) + return specJsonWithResolvedSubtrees(state).getIn(["paths", ...pathMethod, "consumes"], fromJS({})) } // Get the currently selected produces value for an operation diff --git a/test/core/plugins/spec/selectors.js b/test/core/plugins/spec/selectors.js index a11699ef..db4fb7ff 100644 --- a/test/core/plugins/spec/selectors.js +++ b/test/core/plugins/spec/selectors.js @@ -1,7 +1,13 @@ /* eslint-env mocha */ import expect from "expect" import { fromJS } from "immutable" -import { parameterValues, contentTypeValues, operationScheme } from "corePlugins/spec/selectors" +import { + parameterValues, + contentTypeValues, + operationScheme, + specJsonWithResolvedSubtrees, + operationConsumes +} from "corePlugins/spec/selectors" describe("spec plugin - selectors", function(){ @@ -238,6 +244,34 @@ describe("spec plugin - selectors", function(){ }) + describe("operationConsumes", function(){ + it("should return the operationConsumes for an operation", function(){ + // Given + let state = fromJS({ + json: { + paths: { + "/one": { + get: { + consumes: [ + "application/xml", + "application/something-else" + ] + } + } + } + } + }) + + // When + let contentTypes = operationConsumes(state, [ "/one", "get" ]) + // Then + expect(contentTypes.toJS()).toEqual([ + "application/xml", + "application/something-else" + ]) + }) + }) + describe("operationScheme", function(){ it("should return the correct scheme for a remote spec that doesn't specify a scheme", function(){ @@ -277,4 +311,54 @@ describe("spec plugin - selectors", function(){ }) + + describe("specJsonWithResolvedSubtrees", function(){ + + it("should return a correctly merged tree", function(){ + // Given + let state = fromJS({ + json: { + definitions: { + Asdf: { + $ref: "#/some/path", + randomKey: "this should be removed b/c siblings of $refs must be removed, per the specification", + description: "same for this key" + }, + Fgsfds: { + $ref: "#/another/path" + }, + OtherDef: { + description: "has no refs" + } + } + }, + resolvedSubtrees: { + definitions: { + Asdf: { + type: "object", + $$ref: "#/some/path" + } + } + } + }) + + // When + let result = specJsonWithResolvedSubtrees(state) + // Then + expect(result.toJS()).toEqual({ + definitions: { + Asdf: { + type: "object", + $$ref: "#/some/path" + }, + Fgsfds: { + $ref: "#/another/path" + }, + OtherDef: { + description: "has no refs" + } + } + }) + }) + }) })