web/browser-cookie/BrowserCookie.ts

import { ICookie, ICookieSet } from './types';

interface IndexableValue {
  [key: string]: string;
}

/**
 * 브라우져(document) 쿠키
 * @class BrowserCookie
 * @implements {ICookie}
 */
export class BrowserCookie implements ICookie {
  /**
   * 쿠키에 넣을 값 encode
   * @param {string} value
   * @returns {string}
   */
  encode(value: string): string {
    return encodeURIComponent(value);
  }

  /**
   * 쿠키에 꺼내는 값 decode
   * @param {string} value
   * @returns {string}
   */
  decode(value: string): string {
    return decodeURIComponent(value);
  }

  /**
   * document 쿠키 값 반환
   * @returns {string}
   */
  getCookies(): string {
    return document.cookie;
  }

  /**
   * document 에 쿠키 값 지정
   * @param {(string | any)} cookie
   */
  setCookies(cookie: string | any) {
    document.cookie = cookie;
  }

  /**
   * 쿠키 중 name 에 해당하는 값이 있는지 여부
   * @param {string} name
   * @returns {boolean}
   */
  has(name: string): boolean {
    if (typeof document === 'undefined') return false;
    name = this.encode(name);
    const regexp = new RegExp('(?:^' + name + '|;\\s*' + name + ')=(.*?)(?:;|$)', 'g');
    return regexp.test(this.getCookies());
  }

  /**
   * 쿠키 중 name 에 해당하는 값 반환
   * @param {string} name
   * @returns {string}
   */
  get(name: string): string {
    if (this.has(name)) {
      name = this.encode(name);
      const regexp = new RegExp('(?:^' + name + '|;\\s*' + name + ')=(.*?)(?:;|$)', 'g');
      const result = regexp.exec(this.getCookies());
      return this.decode(result[1]);
    } else {
      return;
    }
  }

  /**
   * 모든 쿠키값을 key&value 로 반환
   * @returns {IndexableValue}
   */
  getAll(): IndexableValue {
    const all: any = {};
    const cookies: string = this.getCookies();
    if (cookies && cookies != '') {
      const split = cookies.split(';');
      for (const str of split) {
        const cookieItem = str.split('=');
        cookieItem[0] = cookieItem[0].replace(/^ /, '');
        all[this.decode(cookieItem[0])] = this.decode(cookieItem[1]);
      }
    }
    return all;
  }

  /**
   * 쿠키에 값 넣기
   * @param {ICookieSet} options
   * @returns {void}
   */
  set(options: ICookieSet): void {
    if (!options || !options.name || options.value === undefined) return;
    const { name, value, expires = 0, path = '/', domain = '', secure = false } = options;
    const maker = [];
    maker.push(`${this.encode(name)}=${this.encode(value)};`);
    if (expires) {
      if (typeof expires === 'number') {
        const dtExpires = new Date(new Date().getTime() + expires * 1000);
        maker.push(`expires=${dtExpires.toUTCString()};`);
      } else {
        maker.push(`expires=${expires.toUTCString()};`);
      }
    }

    maker.push(`path=${path};`);
    if (domain) maker.push(`domain=${domain};`);
    if (secure) maker.push(`secure=${secure};`);
    this.setCookies(maker.join(''));
  }

  /**
   * 쿠키 중 일치하는 값 제거
   * @param {string} name
   * @param {string} [path]
   * @param {string} [domain]
   */
  delete(name: string, path?: string, domain?: string): void {
    this.set({
      name,
      value: '',
      path,
      domain,
      expires: -1,
    });
  }

  /**
   * 일치하는 모든 쿠키 제거
   * @param {string} [path]
   * @param {string} [domain]
   */
  deleteAll(path?: string, domain?: string): void {
    const cookies: any = this.getAll();
    for (const cookieName of Object.keys(cookies)) {
      this.delete(cookieName, path, domain);
    }
  }
}