Source: cookie.js

/**
 * 本模块提供 cookie 读写方法。
 * @module cookie
 */

import { isDate } from './internal/core';
import { addToDate } from './internal/timeunit';

/**
 * 写入 cookie。
 * @author luoliquan
 * @param {string} key cookie 键。
 * @param {string} value cookie 值。
 * @param {Object} [options] 参数。
 *   @param {string} [options.domain] 所在域。
 *   @param {string} [options.path] 所在路径。
 *   @param {(Date|number|string)} [options.expires] 过期时间。
 *     为日期类型时表示绝对时间;
 *     为数字(单位毫秒)时表示相对时间(当前时间+相对值);
 *     为字符串时表示相对时间(当前时间+相对值),支持格式包括(%表示数字):
 *       %secs,
 *       %mins,
 *       %hours,
 *       %days,
 *       %months,
 *       %years。
 *   @param {boolean} [options.secure] 是否只在 https 连接中有效。
 *   @param {string} [options.sameSite] 访问限制:Lax、Strict 或 None。
 * @example
 * cookie.set('a', '1')
 * cookie.set('b', '2', {
 *   expires: '6months', // 180 天
 *   domain: '.polyv.net',
 *   path: '/'
 * });
 */
export function set(key, value, options) {
  options = options || {};

  let content = encodeURIComponent(key) + '=' + encodeURIComponent(value);
  if (options.expires != null) {
    content += '; expires=' + (
      isDate(options.expires) ?
        options.expires :
        addToDate(new Date(), options.expires)
    ).toUTCString();
  }
  if (options.path) { content += '; path=' + options.path; }
  if (options.domain) { content += '; domain=' + options.domain; }
  if (options.secure === true) { content += '; secure'; }
  if (options.sameSite) {
    const sameSite = String(options.sameSite).toLowerCase();
    if (['lax', 'strict', 'none'].indexOf(sameSite) !== -1) {
      content += '; samesite=' + sameSite;
    }
  }

  document.cookie = content;
}

/**
 * 读取 cookie。
 * @author luoliquan
 * @param {string} name cookie 名。
 * @return {string} cookie 值。
 * @example
 * cookie.get('a');
 */
export function get(key) {
  key = '; ' + encodeURIComponent(key) + '=';
  const cookie = '; ' + document.cookie;

  let beginPos = cookie.indexOf(key);
  if (beginPos === -1) { return null; }
  beginPos += key.length;

  let endPos = cookie.indexOf(';', beginPos);
  if (endPos === -1) { endPos = cookie.length; }

  return decodeURIComponent(cookie.substring(beginPos, endPos));
}

// iOS 9 下设置过期不会马上生效,先设为空
const shouldSetEmptyBeforeRemove = (function() {
  // 兼容 Node 端(主要针对同构应用)引入
  if (typeof document === 'undefined') { return false; }

  const TEST_KEY = '__jraiser__test__cookie__';
  document.cookie = TEST_KEY + '=1';
  document.cookie = TEST_KEY + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
  return !!get(TEST_KEY);
})();

/**
 * 移除 cookie。
 * @author luoliquan
 * @param {string} name cookie 名。
 * @param {Object} [options] 参数。
 *   @param {string} [options.domain] 所在域。
 *   @param {string} [options.path] 所在路径。
 * @example
 * remove('a');
 * remove('b' {
 *   domain: '.polyv.net',
 *   path: '/abc'
 * })
 */
export function remove(name, options) {
  if (shouldSetEmptyBeforeRemove) { set(name, '', options); }

  options = options || {};
  // 让其过期即为删除
  options.expires = new Date(0);
  set(name, '', options);
}