Home Reference Source

core/utils/url.js

import url from 'url';
import qs from 'qs';
import assign from 'lodash/assign';
import isArray from 'lodash//isArray';
import isPlainObject from 'lodash//isPlainObject';
import isString from 'lodash//isString';
import isEmpty from 'lodash//isEmpty';
import { isDefined } from './object';

/**
 * Adapted from https://github.com/lakenen/node-append-query, to fit a non-node runtime.
 */
function serialize(obj, options = {}, prefix) {
  const str = [];
  let useArraySyntax = false;

  if (isArray(obj) && isDefined(prefix)) {
    useArraySyntax = true;
  }

  Object.keys(obj).forEach((prop) => {
    let query;
    const val = obj[prop];

    const key = prefix ?
      `${prefix}[${useArraySyntax ? '' : prop}]` :
      prop;

    if (isDefined(val) === false) {
      if (options.removeNull === true) {
        return;
      }

      query = options.encodeComponents === true ? encodeURIComponent(key) : key;
    } else if (isPlainObject(val)) {
      query = serialize(val, options, key);
    } else {
      query = options.encodeComponents ?
        `${encodeURIComponent(key)}=${encodeURIComponent(val)}` :
        `${key}=${val}`;
    }

    str.push(query);
  });

  return str.join('&');
}

/**
 * @private
 */
export function appendQuery(uri, query, options = {}) {
  const parts = url.parse(uri, true);
  const queryToAppend = isString(query) ? qs.parse(query) : query;
  const parsedQuery = assign({}, parts.query, queryToAppend);
  options = assign({ encodeComponents: true, removeNull: false }, options);
  parts.query = null;
  const queryString = serialize(parsedQuery, options);
  parts.search = isDefined(queryString) && isEmpty(queryString) === false ? `?${queryString}` : null;
  return url.format(parts);
}