utils.js 19.9 KB
Newer Older
R
Ron 已提交
1
import Im from "immutable"
2
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url"
R
Ron 已提交
3 4 5
import camelCase from "lodash/camelCase"
import upperFirst from "lodash/upperFirst"
import _memoize from "lodash/memoize"
6
import find from "lodash/find"
R
Ron 已提交
7 8 9
import some from "lodash/some"
import eq from "lodash/eq"
import { memoizedSampleFromSchema, memoizedCreateXMLExample } from "core/plugins/samples/fn"
10
import win from "./window"
11
import cssEscape from "css.escape"
R
Ron 已提交
12 13 14 15 16

const DEFAULT_REPONSE_KEY = "default"

export const isImmutable = (maybe) => Im.Iterable.isIterable(maybe)

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
export function isJSONObject (str) {
  try {
    var o = JSON.parse(str)

    // Handle non-exception-throwing cases:
    // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
    // but... JSON.parse(null) returns null, and typeof null === "object",
    // so we must check for that, too. Thankfully, null is falsey, so this suffices:
    if (o && typeof o === "object") {
      return o
    }
  }
  catch (e) {
    // do nothing
  }

  return false
}

R
Ron 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
export function objectify (thing) {
  if(!isObject(thing))
    return {}
  if(isImmutable(thing))
    return thing.toObject()
  return thing
}

export function arrayify (thing) {
  if(!thing)
    return []

  if(thing.toArray)
    return thing.toArray()

  return normalizeArray(thing)
}

export function fromJSOrdered (js) {
  if(isImmutable(js))
    return js // Can't do much here

58 59 60
  if (js instanceof win.File)
    return js

R
Ron 已提交
61 62 63
  return !isObject(js) ? js :
    Array.isArray(js) ?
      Im.Seq(js).map(fromJSOrdered).toList() :
L
Leon Weidauer 已提交
64
      Im.OrderedMap(js).map(fromJSOrdered)
R
Ron 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
}

export function bindToState(obj, state) {
	var newObj = {}
	Object.keys(obj)
  .filter(key => typeof obj[key] === "function")
  .forEach(key => newObj[key] = obj[key].bind(null, state))
	return newObj
}

export function normalizeArray(arr) {
  if(Array.isArray(arr))
    return arr
  return [arr]
}

export function isFn(fn) {
  return typeof fn === "function"
}

export function isObject(obj) {
  return !!obj && typeof obj === "object"
}

export function isFunc(thing) {
  return typeof(thing) === "function"
}

export function isArray(thing) {
  return Array.isArray(thing)
}

// I've changed memoize libs more than once, so I'm using this a way to make that simpler
export const memoize = _memoize

export function objMap(obj, fn) {
  return Object.keys(obj).reduce((newObj, key) => {
    newObj[key] = fn(obj[key], key)
    return newObj
  }, {})
}

export function objReduce(obj, fn) {
  return Object.keys(obj).reduce((newObj, key) => {
    let res = fn(obj[key], key)
    if(res && typeof res === "object")
111
      Object.assign(newObj, res)
R
Ron 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
    return newObj
  }, {})
}

// Redux middleware that exposes the system to async actions (like redux-thunk, but with out system instead of (dispatch, getState)
export function systemThunkMiddleware(getSystem) {
  return ({ dispatch, getState }) => { // eslint-disable-line no-unused-vars
    return next => action => {
      if (typeof action === "function") {
        return action(getSystem())
      }

      return next(action)
    }
  }
}

export function defaultStatusCode ( responses ) {
  let codes = responses.keySeq()
  return codes.contains(DEFAULT_REPONSE_KEY) ? DEFAULT_REPONSE_KEY : codes.filter( key => (key+"")[0] === "2").sort().first()
}


/**
 * Returns an Immutable List, safely
 * @param {Immutable.Iterable} iterable the iterable to get the key from
 * @param {String|[String]} key either an array of keys, or a single key
 * @returns {Immutable.List} either iterable.get(keys) or an empty Immutable.List
 */
export function getList(iterable, keys) {
  if(!Im.Iterable.isIterable(iterable)) {
    return Im.List()
  }
  let val = iterable.getIn(Array.isArray(keys) ? keys : [keys])
  return Im.List.isList(val) ? val : Im.List()
}

/**
 * Adapted from http://github.com/asvd/microlight
 * @copyright 2016 asvd <heliosframework@gmail.com>
 */
export function highlight (el) {
  const MAX_LENGTH = 5000
  var
    _document = document,
    appendChild = "appendChild",
K
Kyle Shockey 已提交
158
    test = "test"
R
Ron 已提交
159 160 161 162 163 164

  if (!el) return ""
  if (el.textContent.length > MAX_LENGTH) { return el.textContent }

  var reset = function(el) {
    var text = el.textContent,
165
      pos = 0, // current position
R
Ron 已提交
166
      next1 = text[0], // next character
167 168 169 170 171
      chr = 1, // current character
      prev1, // previous character
      prev2, // the one before the previous
      token = // current token content
        el.innerHTML = "", // (and cleaning the node)
R
Ron 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190

    // current token type:
    //  0: anything else (whitespaces / newlines)
    //  1: operator or brace
    //  2: closing braces (after which '/' is division not regex)
    //  3: (key)word
    //  4: regex
    //  5: string starting with "
    //  6: string starting with '
    //  7: xml comment  <!-- -->
    //  8: multiline comment /* */
    //  9: single-line comment starting with two slashes //
    // 10: single-line comment starting with hash #
      tokenType = 0,

    // kept to determine between regex and division
      lastTokenType,
    // flag determining if token is multi-character
      multichar,
K
Kyle Shockey 已提交
191
      node
R
Ron 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210

    // running through characters and highlighting
    while (prev2 = prev1,
      // escaping if needed (with except for comments)
      // pervious character will not be therefore
      // recognized as a token finalize condition
      prev1 = tokenType < 7 && prev1 == "\\" ? 1 : chr
      ) {
      chr = next1
      next1=text[++pos]
      multichar = token.length > 1

      // checking if current token should be finalized
      if (!chr || // end of content
          // types 9-10 (single-line comments) end with a
          // newline
        (tokenType > 8 && chr == "\n") ||
        [ // finalize conditions for other token types
          // 0: whitespaces
211
          /\S/[test](chr), // merged together
R
Ron 已提交
212
          // 1: operators
213
          1, // consist of a single character
R
Ron 已提交
214
          // 2: braces
215
          1, // consist of a single character
R
Ron 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
          // 3: (key)word
          !/[$\w]/[test](chr),
          // 4: regex
          (prev1 == "/" || prev1 == "\n") && multichar,
          // 5: string with "
          prev1 == "\"" && multichar,
          // 6: string with '
          prev1 == "'" && multichar,
          // 7: xml comment
          text[pos-4]+prev2+prev1 == "-->",
          // 8: multiline comment
          prev2+prev1 == "*/"
        ][tokenType]
      ) {
        // appending the token to the result
        if (token) {
          // remapping token type into style
          // (some types are highlighted similarly)
          el[appendChild](
            node = _document.createElement("span")
          ).setAttribute("style", [
            // 0: not formatted
            "color: #555; font-weight: bold;",
            // 1: keywords
            "",
            // 2: punctuation
            "",
            // 3: strings and regexps
            "color: #555;",
            // 4: comments
            ""
          ][
            // not formatted
            !tokenType ? 0 :
              // punctuation
              tokenType < 3 ? 2 :
                // comments
                tokenType > 6 ? 4 :
                  // regex and strings
                  tokenType > 3 ? 3 :
                    // otherwise tokenType == 3, (key)word
                    // (1 if regexp matches, 0 otherwise)
                    + /^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/[test](token)
            ])

          node[appendChild](_document.createTextNode(token))
        }

        // saving the previous token type
        // (skipping whitespaces and comments)
        lastTokenType =
          (tokenType && tokenType < 7) ?
            tokenType : lastTokenType

        // initializing a new token
        token = ""

        // determining the new token type (going up the
        // list until matching a token type start
        // condition)
        tokenType = 11
        while (![
278
          1, //  0: whitespace
R
Ron 已提交
279
                               //  1: operator or braces
280 281 282 283
          /[\/{}[(\-+*=<>:;|\\.,?!&@~]/[test](chr), // eslint-disable-line no-useless-escape
          /[\])]/[test](chr), //  2: closing brace
          /[$\w]/[test](chr), //  3: (key)word
          chr == "/" && //  4: regex
R
Ron 已提交
284 285 286 287 288 289 290 291
            // previous token was an
            // opening brace or an
            // operator (otherwise
            // division, not a regex)
          (lastTokenType < 2) &&
            // workaround for xml
            // closing tags
          prev1 != "<",
292 293
          chr == "\"", //  5: string with "
          chr == "'", //  6: string with '
R
Ron 已提交
294 295
                               //  7: xml comment
          chr+next1+text[pos+1]+text[pos+2] == "<!--",
296 297 298
          chr+next1 == "/*", //  8: multiline comment
          chr+next1 == "//", //  9: single-line comment
          chr == "#" // 10: hash-style comment
R
Ron 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
        ][--tokenType]);
      }

      token += chr
    }
  }

  return reset(el)
}

/**
 * Take an immutable map, and convert to a list.
 * Where the keys are merged with the value objects
 * @param {Immutable.Map} map, the map to convert
 * @param {String} key the key to use, when merging the `key`
 * @returns {Immutable.List}
 */
export function mapToList(map, keyNames="key", collectedKeys=Im.Map()) {
  if(!Im.Map.isMap(map) || !map.size) {
    return Im.List()
  }

  if(!Array.isArray(keyNames)) {
    keyNames = [ keyNames ]
  }

  if(keyNames.length < 1) {
    return map.merge(collectedKeys)
  }

  // I need to avoid `flatMap` from merging in the Maps, as well as the lists
  let list = Im.List()
  let keyName = keyNames[0]
  for(let entry of map.entries()) {
    let [key, val] = entry
    let nextList = mapToList(val, keyNames.slice(1), collectedKeys.set(keyName, key))
    if(Im.List.isList(nextList)) {
      list = list.concat(nextList)
    } else {
      list = list.push(nextList)
    }
  }

  return list
}

// PascalCase, aka UpperCamelCase
export function pascalCase(str) {
  return upperFirst(camelCase(str))
}

// Remove the ext of a filename, and pascalCase it
export function pascalCaseFilename(filename) {
  return pascalCase(filename.replace(/\.[^./]*$/, ""))
}

// Check if ...
// - new props
// - If immutable, use .is()
// - if in explicit objectList, then compare using _.eq
// - else use ===
export const propChecker = (props, nextProps, objectList=[], ignoreList=[]) => {

  if(Object.keys(props).length !== Object.keys(nextProps).length) {
    return true
  }

  return (
    some(props, (a, name) => {
      if(ignoreList.includes(name)) {
        return false
      }
      let b = nextProps[name]

      if(Im.Iterable.isIterable(a)) {
        return !Im.is(a,b)
      }

      // Not going to compare objects
      if(typeof a === "object" && typeof b === "object") {
        return false
      }

      return a !== b
    })
    || objectList.some( objectPropName => !eq(props[objectPropName], nextProps[objectPropName])))
}

387 388 389 390 391 392 393 394 395 396 397 398
export const validateMaximum = ( val, max ) => {
  if (val > max) {
    return "Value must be less than Maximum"
  }
}

export const validateMinimum = ( val, min ) => {
  if (val < min) {
    return "Value must be greater than Minimum"
  }
}

399
export const validateNumber = ( val ) => {
400
  if (!/^-?\d+(\.?\d+)?$/.test(val)) {
K
Kyle Shockey 已提交
401 402 403 404
    return "Value must be a number"
  }
}

405
export const validateInteger = ( val ) => {
406
  if (!/^-?\d+$/.test(val)) {
407
    return "Value must be an integer"
K
Kyle Shockey 已提交
408 409
  }
}
R
Ron 已提交
410

411
export const validateFile = ( val ) => {
O
Owen Conti 已提交
412
  if ( val && !(val instanceof win.File) ) {
413 414 415 416
    return "Value must be a file"
  }
}

417 418 419 420 421 422 423 424 425 426 427 428
export const validateBoolean = ( val ) => {
  if ( !(val === "true" || val === "false" || val === true || val === false) ) {
    return "Value must be a boolean"
  }
}

export const validateString = ( val ) => {
  if ( val && typeof val !== "string" ) {
    return "Value must be a string"
  }
}

H
HelderSepu 已提交
429
export const validateDateTime = (val) => {
H
HelderSepu 已提交
430
    if (isNaN(Date.parse(val))) {
H
HelderSepu 已提交
431 432 433 434 435
        return "Value must be a DateTime"
    }
}

export const validateGuid = (val) => {
436
    if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}[)}]?$/.test(val)) {
H
HelderSepu 已提交
437 438 439 440
        return "Value must be a Guid"
    }
}

441 442 443 444 445 446 447 448 449 450 451 452
export const validateMaxLength = (val, max) => {
  if (val.length > max) {
      return "Value must be less than MaxLength"
  }
}

export const validateMinLength = (val, min) => {
  if (val.length < min) {
      return "Value must be greater than MinLength"
  }
}

H
HelderSepu 已提交
453
export const validatePattern = (val, rxPattern) => {
H
HelderSepu 已提交
454
  var patt = new RegExp(rxPattern)
H
HelderSepu 已提交
455 456 457 458 459
  if (!patt.test(val)) {
      return "Value must follow pattern " + rxPattern
  }
}

R
Ron 已提交
460
// validation of parameters before execute
461
export const validateParam = (param, isXml, isOAS3 = false) => {
R
Ron 已提交
462 463 464
  let errors = []
  let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
  let required = param.get("required")
O
Owen Conti 已提交
465

466
  let paramDetails = isOAS3 ? param.get("schema") : param
467 468 469

  if(!paramDetails) return errors

O
Owen Conti 已提交
470 471 472 473 474 475
  let maximum = paramDetails.get("maximum")
  let minimum = paramDetails.get("minimum")
  let type = paramDetails.get("type")
  let format = paramDetails.get("format")
  let maxLength = paramDetails.get("maxLength")
  let minLength = paramDetails.get("minLength")
H
HelderSepu 已提交
476
  let pattern = paramDetails.get("pattern")
477

R
Ron 已提交
478

479 480 481 482 483 484
  /*
    If the parameter is required OR the parameter has a value (meaning optional, but filled in)
    then we should do our validation routine.
    Only bother validating the parameter if the type was specified.
  */
  if ( type && (required || value) ) {
H
HelderSepu 已提交
485 486
    // These checks should evaluate to true if there is a parameter
    let stringCheck = type === "string" && value
487 488 489
    let arrayCheck = type === "array" && Array.isArray(value) && value.length
    let listCheck = type === "array" && Im.List.isList(value) && value.count()
    let fileCheck = type === "file" && value instanceof win.File
H
HelderSepu 已提交
490
    let booleanCheck = type === "boolean" && (value || value === false)
491 492
    let numberCheck = type === "number" && (value || value === 0)
    let integerCheck = type === "integer" && (value || value === 0)
H
HelderSepu 已提交
493 494 495 496 497

    if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
      errors.push("Required field is not provided")
      return errors
    }
498

H
HelderSepu 已提交
499 500 501 502
    if (pattern) {
      let err = validatePattern(value, pattern)
      if (err) errors.push(err)
    }
503

H
HelderSepu 已提交
504
    if (maxLength || maxLength === 0) {
505 506 507 508 509 510 511 512 513
      let err = validateMaxLength(value, maxLength)
      if (err) errors.push(err)
    }

    if (minLength) {
      let err = validateMinLength(value, minLength)
      if (err) errors.push(err)
    }

514
    if (maximum || maximum === 0) {
515 516 517 518
      let err = validateMaximum(value, maximum)
      if (err) errors.push(err)
    }

519
    if (minimum || minimum === 0) {
520 521 522
      let err = validateMinimum(value, minimum)
      if (err) errors.push(err)
    }
523

524
    if ( type === "string" ) {
H
HelderSepu 已提交
525 526 527 528 529 530 531
      let err
      if (format === "date-time") {
          err = validateDateTime(value)
      } else if (format === "uuid") {
          err = validateGuid(value)
      } else {
          err = validateString(value)
532
      }
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
      if (!err) return errors
      errors.push(err)
    } else if ( type === "boolean" ) {
      let err = validateBoolean(value)
      if (!err) return errors
      errors.push(err)
    } else if ( type === "number" ) {
      let err = validateNumber(value)
      if (!err) return errors
      errors.push(err)
    } else if ( type === "integer" ) {
      let err = validateInteger(value)
      if (!err) return errors
      errors.push(err)
    } else if ( type === "array" ) {
      let itemType

      if ( !value.count() ) { return errors }

552
      itemType = paramDetails.getIn(["items", "type"])
553 554 555 556 557 558 559 560 561 562 563

      value.forEach((item, index) => {
        let err

        if (itemType === "number") {
          err = validateNumber(item)
        } else if (itemType === "integer") {
          err = validateInteger(item)
        } else if (itemType === "string") {
          err = validateString(item)
        }
564

565 566 567 568 569 570 571 572 573
        if ( err ) {
          errors.push({ index: index, error: err})
        }
      })
    } else if ( type === "file" ) {
      let err = validateFile(value)
      if (!err) return errors
      errors.push(err)
    }
R
Ron 已提交
574 575 576 577 578 579 580 581 582 583 584 585 586 587
  }

  return errors
}

export const getSampleSchema = (schema, contentType="", config={}) => {
  if (/xml/.test(contentType)) {
    if (!schema.xml || !schema.xml.name) {
      schema.xml = schema.xml || {}

      if (schema.$$ref) {
        let match = schema.$$ref.match(/\S*\/(\S+)$/)
        schema.xml.name = match[1]
      } else if (schema.type || schema.items || schema.properties || schema.additionalProperties) {
K
Kyle Shockey 已提交
588
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- XML example cannot be generated -->"
R
Ron 已提交
589 590 591 592 593 594 595 596 597
      } else {
        return null
      }
    }
    return memoizedCreateXMLExample(schema, config)
  }

  return JSON.stringify(memoizedSampleFromSchema(schema, config), null, 2)
}
598

W
Will Marshall 已提交
599
export const parseSearch = () => {
600
  let map = {}
601 602 603 604
  let search = win.location.search

  if(!search)
    return {}
605 606

  if ( search != "" ) {
K
Kyle Shockey 已提交
607
    let params = search.substr(1).split("&")
608 609

    for (let i in params) {
K
Kyle Shockey 已提交
610 611
      i = params[i].split("=")
      map[decodeURIComponent(i[0])] = decodeURIComponent(i[1])
612 613 614
    }
  }

K
Kyle Shockey 已提交
615
  return map
K
Kyle Shockey 已提交
616
}
A
Anna Bodnia 已提交
617 618

export const btoa = (str) => {
S
shockey 已提交
619
  let buffer
A
Anna Bodnia 已提交
620 621

  if (str instanceof Buffer) {
S
shockey 已提交
622
    buffer = str
A
Anna Bodnia 已提交
623
  } else {
S
shockey 已提交
624
    buffer = new Buffer(str.toString(), "utf-8")
A
Anna Bodnia 已提交
625 626
  }

S
shockey 已提交
627
  return buffer.toString("base64")
A
Anna Bodnia 已提交
628
}
A
Anna Bodnia 已提交
629 630 631 632 633

export const sorters = {
  operationsSorter: {
    alpha: (a, b) => a.get("path").localeCompare(b.get("path")),
    method: (a, b) => a.get("method").localeCompare(b.get("method"))
634
  },
K
Kyle Shockey 已提交
635
  tagsSorter: {
636
    alpha: (a, b) => a.localeCompare(b)
A
Anna Bodnia 已提交
637 638
  }
}
639 640 641 642 643 644

export const buildFormData = (data) => {
  let formArr = []

  for (let name in data) {
    let val = data[name]
A
build  
Anna Bodnia 已提交
645
    if (val !== undefined && val !== "") {
646 647 648 649 650
      formArr.push([name, "=", encodeURIComponent(val).replace(/%20/g,"+")].join(""))
    }
  }
  return formArr.join("&")
}
651

652 653 654 655 656 657
// Is this really required as a helper? Perhaps. TODO: expose the system of presets.apis in docs, so we know what is supported
export const shallowEqualKeys = (a,b, keys) => {
  return !!find(keys, (key) => {
    return eq(a[key], b[key])
  })
}
658

659
export function sanitizeUrl(url) {
660 661 662 663
  if(typeof url !== "string" || url === "") {
    return ""
  }

664 665 666
  return braintreeSanitizeUrl(url)
}

667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
export function getAcceptControllingResponse(responses) {
  if(!Im.OrderedMap.isOrderedMap(responses)) {
    // wrong type!
    return null
  }

  if(!responses.size) {
    // responses is empty
    return null
  }

  const suitable2xxResponse = responses.find((res, k) => {
    return k.startsWith("2") && Object.keys(res.get("content") || {}).length > 0
  })

  // try to find a suitable `default` responses
  const defaultResponse = responses.get("default") || Im.OrderedMap()
  const defaultResponseMediaTypes = (defaultResponse.get("content") || Im.OrderedMap()).keySeq().toJS()
  const suitableDefaultResponse = defaultResponseMediaTypes.length ? defaultResponse : null

  return suitable2xxResponse || suitableDefaultResponse
}
689

K
Kyle Shockey 已提交
690
export const createDeepLinkPath = (str) => typeof str == "string" || str instanceof String ? str.trim().replace(/\s/g, "_") : ""
691
export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) )
G
Greg Thompson 已提交
692 693

export const getExtensions = (defObj) => defObj.filter((v, k) => /^x-/.test(k))