* WIP: trigger resolution of Path Item $ref on spec load * fix(dev-server): don't open localhost in a browser * preserve key order when merging specJson with specResolvedSubtrees * remove stray `debugger`bubble
@@ -19,9 +19,8 @@ | |||
"build-core": "webpack --config webpack-dist.config.js --colors", | |||
"build-standalone": "webpack --config webpack-dist-standalone.config.js --colors", | |||
"predev": "npm install", | |||
"dev": "npm-run-all --parallel hot-server open-localhost", | |||
"dev": "npm-run-all --parallel hot-server", | |||
"watch": "webpack --config webpack-watch.config.js --watch --progress", | |||
"open-localhost": "node -e 'require(\"open\")(\"http://localhost:3200\")'", | |||
"hot-server": "webpack-dev-server --host 0.0.0.0 --config webpack-hot-dev-server.config.js --inline --hot --progress --content-base dev-helpers/", | |||
"deps-license": "license-checker --production --csv --out $npm_package_config_deps_check_dir/licenses.csv && license-checker --development --csv --out $npm_package_config_deps_check_dir/licenses-dev.csv", | |||
"deps-size": "webpack -p --config webpack.check.js --json | webpack-bundle-size-analyzer >| $npm_package_config_deps_check_dir/sizes.txt", | |||
@@ -105,7 +105,8 @@ export default class OperationContainer extends PureComponent { | |||
toggleShown =() => { | |||
let { layoutActions, tag, operationId, isShown } = this.props | |||
if(!isShown) { | |||
const resolvedSubtree = this.getResolvedSubtree() | |||
if(!isShown && resolvedSubtree === undefined) { | |||
// transitioning from collapsed to expanded | |||
this.requestResolvedSubtree() | |||
} | |||
@@ -54,7 +54,7 @@ const mergerFn = (oldVal, newVal) => { | |||
return newVal | |||
} | |||
return Map().mergeWith( | |||
return OrderedMap().mergeWith( | |||
mergerFn, | |||
oldVal, | |||
newVal | |||
@@ -66,7 +66,7 @@ const mergerFn = (oldVal, newVal) => { | |||
export const specJsonWithResolvedSubtrees = createSelector( | |||
state, | |||
spec => Map().mergeWith( | |||
spec => OrderedMap().mergeWith( | |||
mergerFn, | |||
spec.get("json"), | |||
spec.get("resolvedSubtrees") | |||
@@ -109,7 +109,7 @@ export const semver = createSelector( | |||
) | |||
export const paths = createSelector( | |||
spec, | |||
specJsonWithResolvedSubtrees, | |||
spec => spec.get("paths") | |||
) | |||
@@ -1,3 +1,5 @@ | |||
import get from "lodash/get" | |||
export const updateSpec = (ori, {specActions}) => (...args) => { | |||
ori(...args) | |||
specActions.parseToJson(...args) | |||
@@ -5,7 +7,21 @@ export const updateSpec = (ori, {specActions}) => (...args) => { | |||
export const updateJsonSpec = (ori, {specActions}) => (...args) => { | |||
ori(...args) | |||
specActions.invalidateResolvedSubtreeCache() | |||
// Trigger resolution of any path-level $refs. | |||
const [json] = args | |||
const pathItems = get(json, ["paths"]) | |||
const pathItemKeys = Object.keys(pathItems) | |||
pathItemKeys.forEach(k => { | |||
const val = get(pathItems, [k]) | |||
if(val.$ref) { | |||
specActions.requestResolvedSubtree(["paths", k]) | |||
} | |||
}) | |||
} | |||
// Log the request ( just for debugging, shouldn't affect prod ) | |||
@@ -1,6 +1,7 @@ | |||
/* eslint-env mocha */ | |||
import expect from "expect" | |||
import { fromJS } from "immutable" | |||
import { fromJSOrdered } from "core/utils" | |||
import { | |||
parameterValues, | |||
contentTypeValues, | |||
@@ -9,6 +10,8 @@ import { | |||
operationConsumes | |||
} from "corePlugins/spec/selectors" | |||
import Petstore from "./assets/petstore.json" | |||
describe("spec plugin - selectors", function(){ | |||
describe("parameterValue", function(){ | |||
@@ -311,7 +314,6 @@ describe("spec plugin - selectors", function(){ | |||
}) | |||
describe("specJsonWithResolvedSubtrees", function(){ | |||
it("should return a correctly merged tree", function(){ | |||
@@ -360,5 +362,93 @@ describe("spec plugin - selectors", function(){ | |||
} | |||
}) | |||
}) | |||
it("should preserve initial map key ordering", function(){ | |||
// Given | |||
let state = fromJSOrdered({ | |||
json: Petstore, | |||
resolvedSubtrees: { | |||
paths: { | |||
"/pet/{petId}": { | |||
post: { | |||
tags: [ | |||
"pet" | |||
], | |||
summary: "Updates a pet in the store with form data", | |||
description: "", | |||
operationId: "updatePetWithForm", | |||
consumes: [ | |||
"application/x-www-form-urlencoded" | |||
], | |||
produces: [ | |||
"application/xml", | |||
"application/json" | |||
], | |||
parameters: [ | |||
{ | |||
name: "petId", | |||
"in": "path", | |||
description: "ID of pet that needs to be updated", | |||
required: true, | |||
type: "integer", | |||
format: "int64" | |||
}, | |||
{ | |||
name: "name", | |||
"in": "formData", | |||
description: "Updated name of the pet", | |||
required: false, | |||
type: "string" | |||
}, | |||
{ | |||
name: "status", | |||
"in": "formData", | |||
description: "Updated status of the pet", | |||
required: false, | |||
type: "string" | |||
} | |||
], | |||
responses: { | |||
"405": { | |||
description: "Invalid input" | |||
} | |||
}, | |||
security: [ | |||
{ | |||
petstore_auth: [ | |||
"write:pets", | |||
"read:pets" | |||
] | |||
} | |||
], | |||
__originalOperationId: "updatePetWithForm" | |||
} | |||
} | |||
} | |||
} | |||
}) | |||
// When | |||
let result = specJsonWithResolvedSubtrees(state) | |||
// Then | |||
const correctOrder = [ | |||
"/pet", | |||
"/pet/findByStatus", | |||
"/pet/findByTags", | |||
"/pet/{petId}", | |||
"/pet/{petId}/uploadImage", | |||
"/store/inventory", | |||
"/store/order", | |||
"/store/order/{orderId}", | |||
"/user", | |||
"/user/createWithArray", | |||
"/user/createWithList", | |||
"/user/login", | |||
"/user/logout", | |||
"/user/{username}" | |||
] | |||
expect(state.getIn(["json", "paths"]).keySeq().toJS()).toEqual(correctOrder) | |||
expect(result.getIn(["paths"]).keySeq().toJS()).toEqual(correctOrder) | |||
}) | |||
}) | |||
}) |