Skip to content
Snippets Groups Projects
index.js 7.56 MiB
Newer Older
Romain CREY's avatar
Romain CREY committed
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

const {
  BaseKonnector,
  log,
  errors,
  addData,
  hydrateAndFilter,
  cozyClient
} = __webpack_require__(1)

const rp = __webpack_require__(1307)
const moment = __webpack_require__(1339)
__webpack_require__(1476)

moment.locale('fr') // set the language
moment.tz.setDefault('Europe/Paris') // set the timezone

const manualExecution =
  process.env.COZY_JOB_MANUAL_EXECUTION === 'true' ? true : false

const startDate = manualExecution
  ? moment().subtract(5, 'day').format('MM/DD/YYYY')
  : moment().subtract(5, 'day').format('MM/DD/YYYY')

const endDate = moment().format('MM/DD/YYYY')
// const timeRange = ['day', 'month', 'year']
const rangeDate = {
  day: {
    doctype: 'com.grandlyon.egl.day',
    keys: ['year', 'month', 'day']
    doctype: 'com.grandlyon.egl.month',
    keys: ['year', 'month']
    doctype: 'com.grandlyon.egl.year',
    keys: ['year']
Romain CREY's avatar
Romain CREY committed

module.exports = new BaseKonnector(start)
Romain CREY's avatar
Romain CREY committed

// The start function is run by the BaseKonnector instance only when it got all the account
// information (fields). When you run this connector yourself in "standalone" mode or "dev" mode,
// the account information come from ./konnector-dev-config.json file
async function start(fields, cozyParameters) {
  try {
    // resetting data for demo only
    // await resetData()
    // const baseUrl = fields.eglBaseURL
    // const apiAuthKey = fields.eglAPIAuthKey
    const baseUrl = cozyParameters.secret.eglBaseURL
    const apiAuthKey = cozyParameters.secret.eglAPIAuthKey
    log('info', 'Authenticating ...')
Romain CREY's avatar
Romain CREY committed
    const response = await authenticate(
      fields.login,
      fields.password,
      baseUrl,
      apiAuthKey
    )
    log('info', 'Successfully logged in')

    const eglData = await getData(response, baseUrl, apiAuthKey)
    if (eglData) {
      log('info', 'Process egl daily data')
      const processedLoadData = await processData(
        eglData,
        rangeDate.day.doctype,
        rangeDate.day.keys
      log('info', 'Agregate egl load data for month and year')
      await agregateMonthAndYearData(processedLoadData)
    } else {
      log('info', 'No data found')
Romain CREY's avatar
Romain CREY committed
  } catch (error) {
    throw new Error(error.message)
Romain CREY's avatar
Romain CREY committed
  }
}
/**
 * Parse data
 * Remove existing data from DB using hydrateAndFilter
 * Store filtered data
 * Return the list of filtered data
 */
async function processData(data, doctype, filterKeys) {
  // const formatedData = await formateData(data)
  log('info', 'processData - data formated')
  // Remove data for existing days into the DB
  console.log(data)
  const filteredData = await hydrateAndFilter(data, doctype, {
    keys: filterKeys
  })
  console.log(filteredData)
  log('info', 'processData - data filtered')
  // Store new day data
  await storeData(filteredData, doctype, filterKeys)
  return filteredData
}

/**
 * Agregate data from daily data to monthly and yearly data
 */
async function agregateMonthAndYearData(data) {
  // Sum year and month values into object with year or year-month as keys
  if (data && data.length !== 0) {
    let monthData = {}
    let yearData = {}

    data.forEach(element => {
      element.year + '-' + element.month in monthData
        ? (monthData[element.year + '-' + element.month] += element.load)
        : (monthData[element.year + '-' + element.month] = element.load)
      element.year in yearData
        ? (yearData[element.year] += element.load)
        : (yearData[element.year] = element.load)
    })
    // Agregation for Month data
    const agregatedMonthData = await buildAgregatedData(
      monthData,
      'com.grandlyon.egl.month'
    )
    await storeData(agregatedMonthData, 'com.grandlyon.egl.month', [
      'year',
      'month'
    ])
    // Agregation for Year data
    const agregatedYearData = await buildAgregatedData(
      yearData,
      'com.grandlyon.egl.year'
    )
    await storeData(agregatedYearData, 'com.grandlyon.egl.year', ['year'])
  }
}

/**
 * Retrieve and remove old data for a specific doctype
 * Return an Array of agregated data
 */
async function buildAgregatedData(data, doctype) {
  log('info', 'entering buildAgregatedData')
  let agregatedData = []
  for (let [key, value] of Object.entries(data)) {
    const data = await buildDataFromKey(doctype, key, value)
    const oldValue = await resetInProgressAggregatedData(data, doctype)
    log('info', 'Dataload + oldvalue is ' + data.load + ' + ' + oldValue)
    data.load += oldValue
    agregatedData.push(data)
  }
  return agregatedData
}

// async function processData(timeStep, response, baseUrl, apiAuthKey) {
//   const doctype = rangeDate[timeStep].doctype;
//   const loadProfile = await getData(response, baseUrl, apiAuthKey);
//   log("info", "Saving data to Cozy");
//   if (doctype === rangeDate.day.doctype) {
//     await storeData(loadProfile, rangeDate.day.doctype, rangeDate.day.keys);
//   } else if (doctype === rangeDate.month.doctype) {
//     await resetInProgressAggregatedData(rangeDate.month.doctype);
//     const monthlyData = processMonthlyAggregation(loadProfile, rangeDate.month);
//     log("info", "Saving monthly data");
//     await storeData(monthlyData, rangeDate.month.doctype, rangeDate.month.keys);
//   } else if (doctype === rangeDate.year.doctype) {
//     await resetInProgressAggregatedData(rangeDate.year.doctype);
//     const yearlyData = processYearAggregation(
//       loadProfile,
//       rangeDate.year.doctype
//     );
//     log("info", "Saving yearly data");
//     await storeData(yearlyData, rangeDate.year.doctype, rangeDate.year.keys);
//   } else {
//     throw new Error("Unkonw range type: " + doctype);
//   }
// }

Romain CREY's avatar
Romain CREY committed
async function authenticate(login, password, baseUrl, apiAuthKey) {
  const authRequest = {
    method: 'POST',
    uri: baseUrl + '/connect.aspx',
Romain CREY's avatar
Romain CREY committed
    headers: {
      AuthKey: apiAuthKey,
      'Content-Type': 'application/x-www-form-urlencoded'
Romain CREY's avatar
Romain CREY committed
    },
    form: {
      login: login,
      pass: password
    },
    json: true
  }
  const response = await rp(authRequest)
Yoan VALLET's avatar
Yoan VALLET committed
  if (response.codeRetour === 100) {
    return response
Yoan VALLET's avatar
Yoan VALLET committed
  } else {
    throw new Error(errors.LOGIN_FAILED)
Romain CREY's avatar
Romain CREY committed
  }
}

async function getData(response, baseUrl, apiAuthKey) {
  log('info', 'Start date : ' + startDate)
  log('info', 'End date : ' + endDate)
Romain CREY's avatar
Romain CREY committed
  const dataRequest = {
    method: 'POST',
    uri: baseUrl + '/getAllAgregatsByAbonnement.aspx',
Romain CREY's avatar
Romain CREY committed
    headers: {
      AuthKey: apiAuthKey,
      'Content-Type': 'application/x-www-form-urlencoded'
Romain CREY's avatar
Romain CREY committed
    },
    form: {
      token: response.resultatRetour.token,
      num_abt: response.resultatRetour.num_abt,
      date_debut: startDate,
      date_fin: endDate
    },
    json: true
Romain CREY's avatar
Romain CREY committed
  try {
    const responseEgl = await rp(dataRequest)
Yoan VALLET's avatar
Yoan VALLET committed
    switch (responseEgl.codeRetour) {
Romain CREY's avatar
Romain CREY committed
      case 100:
        return format(responseEgl)
Romain CREY's avatar
Romain CREY committed
      case -2:
        throw new Error(errors.LOGIN_FAILED)
Romain CREY's avatar
Romain CREY committed
      case -1:
        throw new Error(errors.VENDOR_DOWN)
Romain CREY's avatar
Romain CREY committed
      default:
        throw new Error(errors.UNKNOWN_ERROR)
Romain CREY's avatar
Romain CREY committed
    }
  } catch (error) {
    throw new Error(errors.VENDOR_DOWN)
Romain CREY's avatar
Romain CREY committed
  }
}

function format(response) {
  log('info', 'origin response size is : ' + response.resultatRetour.length)
  log('info', 'Raw value: ' )
  console.log(response.resultatRetour)
Yoan VALLET's avatar
Yoan VALLET committed
  const data = response.resultatRetour
  .slice(1)
  .filter(value => value.ValeurIndex)
  log('info', 'Filterd value: ')
  console.log(data)
  const dataLen = data.length
  log('info', 'filtered size is : ' + dataLen)
Yoan VALLET's avatar
Yoan VALLET committed
  const mapData = data.map((value, index) => {
    const time = moment(value.DateReleve, moment.ISO_8601)
    if (index !== 0 && index < dataLen) {
      log('info', 'index: ' + value.ValeurIndex)
      log('info', 'index precedent: ' +  data[index - 1].ValeurIndex)
Yoan VALLET's avatar
Yoan VALLET committed
      return {
        load: value.ValeurIndex - data[index - 1].ValeurIndex,
        year: parseInt(time.format('YYYY')),
        month: parseInt(time.format('M')),
        day: parseInt(time.format('D')),
Yoan VALLET's avatar
Yoan VALLET committed
        hour: 0,
        minute: 0,
        type: value.TypeAgregat
Yoan VALLET's avatar
Yoan VALLET committed
    } else {
      return {
        load: null,
        year: parseInt(time.format('YYYY')),
        month: parseInt(time.format('M')),
        day: parseInt(time.format('D')),
Yoan VALLET's avatar
Yoan VALLET committed
        hour: 0,
        minute: 0,
        type: value.TypeAgregat
Yoan VALLET's avatar
Yoan VALLET committed
    }
  })
  const res = [...mapData].filter(v => v.load !== null)
  return res
// function processYearAggregation(data, doctype) {
//   log("info", "Start aggregation for : " + doctype);
//   const grouped = data.reduce(reduceYearFunction, {});
//   return Object.values(grouped);
// }

// function processMonthlyAggregation(data, range) {
//   log("info", "Start aggregation for : " + range.doctype);
//   // Filter by year
//   const tmpData = groupBy(data, "year");
//   const keys = Object.keys(tmpData);
//   var dataToStore = [];
//   // Monthly aggregation
//   for (const index in keys) {
//     // Get daily data of a year
//     var monthlyData = tmpData[keys[index]];
//     // Monthly aggregation
//     var aggregatedData = monthlyData.reduce(reduceMonthFunction, {});
//     // Store it
//     dataToStore = dataToStore.concat(Object.values(aggregatedData));
//   }
//   return dataToStore;
// }

// function groupBy(xs, key) {
//   return xs.reduce(function(rv, x) {
//     (rv[x[key]] = rv[x[key]] || []).push(x);
//     return rv;
//   }, {});
// }

// function reduceYearFunction(acc, x) {
//   var id = acc[x.year];
//   if (id) {
//     id.load += x.load;
//   } else {
//     acc[x.year] = x;
//   }
//   return acc;
// }

// function reduceMonthFunction(acc, x) {
//   var id = acc[x.month];
//   if (id) {
//     id.load += x.load;
//   } else {
//     acc[x.month] = x;
//   }
//   return acc;
// }

/**
 * Save data in the right doctype db and prevent duplicated keys
 */
async function storeData(data, doctype, filterKeys) {
  log('info', 'Store into ' + doctype)
  log('info', 'Store into keys : ' + filterKeys)
  data.map(v => {
      log("info", "Saving data " + v.load + " for " + v.day + "/" + v.month + "/" + v.year);
  });
  const filteredDocuments = await hydrateAndFilter(data, doctype, {
    keys: filterKeys
  })
  return await addData(filteredDocuments, doctype)
}

/**
 * Format an entry for DB storage
 * using key and value
 * For year doctype: key = "YYYY"
 * For month doctype: key = "YYYY-MM"
 */
async function buildDataFromKey(doctype, key, value) {
  let year, month, day, hour
  if (doctype === 'com.grandlyon.egl.year') {
    year = key
    month = 1
    day = 0
    hour = 0
  } else if (doctype === 'com.grandlyon.egl.month') {
    const split = key.split('-')
    year = split[0]
    month = split[1]
    day = 0
    hour = 0
  } else {
    const split = key.split('-')
    year = split[0]
    month = split[1]
    day = split[2]
    hour = split[3]
  return {
    load: Math.round(value * 10000) / 10000,
    year: parseInt(year),
    month: parseInt(month),
    day: parseInt(day),
    hour: parseInt(hour),
    minute: 0
/**
 * Function handling special case.
 * The temporary aggregated data need to be remove in order for the most recent one te be saved.
Yoan VALLET's avatar
Yoan VALLET committed
 * ex for com.grandlyon.egl.month :
 * { load: 76.712, month: 2020, ... } need to be replace by
 * { load: 82.212, month: 2020, ... } after egl data reprocess
async function resetInProgressAggregatedData(data, doctype) {
  // /!\ Warning: cannot use mongo queries because not supported for dev by cozy-konnectors-libs
  log('info', 'Remove aggregated data for ' + doctype)
  const result = await cozyClient.data.findAll(doctype)
  if (result && result.length > 0) {
    // Filter data to remove
    var filtered = []
    if (doctype === 'com.grandlyon.egl.year') {
      // Yearly case
      filtered = result.filter(function(el) {
        return el.year == data.year
      })
    } else if (doctype === 'com.grandlyon.egl.month') {
      filtered = result.filter(function(el) {
        return el.year == data.year && el.month == data.month
      })
    } else {
      // Hourly case
      filtered = result.filter(function(el) {
        return (
          el.year == data.year &&
          el.month == data.month &&
          el.day == data.day &&
          el.hour == data.hour
        )
      })
    }
    // Remove data
    let sum = 0.0
    for (const doc of filtered) {
      sum += doc.load
      log('info', 'Removing this entry for ' + doc.load)
      await cozyClient.data.delete(doctype, doc)
    return sum
Romain CREY's avatar
Romain CREY committed
  }
  return 0.0
Romain CREY's avatar
Romain CREY committed
}


/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

const log = __webpack_require__(2).namespace('cozy-konnector-libs');
Romain CREY's avatar
Romain CREY committed

const requestFactory = __webpack_require__(22);
Romain CREY's avatar
Romain CREY committed

const hydrateAndFilter = __webpack_require__(369);
Romain CREY's avatar
Romain CREY committed

const categorization = __webpack_require__(1162);
Romain CREY's avatar
Romain CREY committed

module.exports = {
  BaseKonnector: __webpack_require__(1222),
  CookieKonnector: __webpack_require__(1300),
  cozyClient: __webpack_require__(485),
  errors: __webpack_require__(1228),
Romain CREY's avatar
Romain CREY committed
  log,
  saveFiles: __webpack_require__(1224),
  saveBills: __webpack_require__(1223),
  saveIdentity: __webpack_require__(1266),
  linkBankOperations: __webpack_require__(1245),
  addData: __webpack_require__(1244),
Romain CREY's avatar
Romain CREY committed
  hydrateAndFilter,
  htmlToPDF: __webpack_require__(1301).htmlToPDF,
  createCozyPDFDocument: __webpack_require__(1301).createCozyPDFDocument,
Romain CREY's avatar
Romain CREY committed
  filterData: deprecate(hydrateAndFilter, 'Use hydrateAndFilter now. filterData will be removed in cozy-konnector-libs@4'),
  updateOrCreate: __webpack_require__(1265),
Romain CREY's avatar
Romain CREY committed
  request: deprecate(requestFactory, 'Use requestFactory instead of request. It will be removed in cozy-konnector-libs@4'),
  requestFactory,
  retry: __webpack_require__(1225),
  wrapIfSentrySetUp: __webpack_require__(1267).wrapIfSentrySetUp,
  Document: __webpack_require__(1302),
  signin: __webpack_require__(1262),
  submitForm: __webpack_require__(1262),
  scrape: __webpack_require__(1304),
  mkdirp: __webpack_require__(1227),
  normalizeFilename: __webpack_require__(1305),
  utils: __webpack_require__(484),
  solveCaptcha: __webpack_require__(1306),
Romain CREY's avatar
Romain CREY committed
  createCategorizer: categorization.createCategorizer,
  categorize: categorization.categorize,
  manifest: __webpack_require__(833)
Romain CREY's avatar
Romain CREY committed
};

function deprecate(wrapped, message) {
  return function () {
    log('warn', message);
    return wrapped.apply(this, arguments);
  };
}

/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

const { filterLevel, filterSecrets } = __webpack_require__(3)
const Secret = __webpack_require__(4)
const { LOG_LEVEL } = process.env
Romain CREY's avatar
Romain CREY committed
let level = LOG_LEVEL || 'debug'
const format = __webpack_require__(5)
Romain CREY's avatar
Romain CREY committed
const filters = [filterLevel, filterSecrets]

const filterOut = function() {
  for (const filter of filters) {
    if (filter.apply(null, arguments) === false) {
      return true
    }
  }
  return false
}

/**
 * Use it to log messages in your konnector. Typical types are
 *
 * - `debug`
 * - `warning`
 * - `info`
 * - `error`
 * - `ok`
 *
 *
 * @example
 *
 * They will be colored in development mode. In production mode, those logs are formatted in JSON to be interpreted by the stack and possibly sent to the client. `error` will stop the konnector.
 *
 * ```js
 * logger = log('my-namespace')
 * logger('debug', '365 bills')
 * // my-namespace : debug : 365 bills
 * logger('info', 'Page fetched')
 * // my-namespace : info : Page fetched
 * ```
 * @param  {string} type
 * @param  {string} message
 * @param  {string} label
 * @param  {string} namespace
 */
function log(type, message, label, namespace) {
  if (filterOut(level, type, message, label, namespace)) {
    return
  }
  // eslint-disable-next-line no-console
  console.log(format(type, message, label, namespace))
}

log.addFilter = function(filter) {
  return filters.push(filter)
}

log.setLevel = function(lvl) {
  level = lvl
}

// Short-hands
const methods = ['debug', 'info', 'warn', 'error', 'ok', 'critical']
methods.forEach(level => {
  log[level] = function(message, label, namespace) {
    return log(level, message, label, namespace)
  }
})

module.exports = log

log.setNoRetry = obj => {
  if (obj) obj.no_retry = true
  else obj = { no_retry: true }
  return obj.no_retry
}
log.Secret = Secret
log.namespace = function(namespace) {
  return function(type, message, label, ns = namespace) {
    log(type, message, label, ns)
  }
}


/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {

const levels = {
  secret: 0,
  debug: 10,
  info: 20,
  warn: 30,
  error: 40,
  ok: 50,
  critical: 50
const Secret = __webpack_require__(4)
const filterSecrets = function(level, type, message) {
  if (type !== 'secret' && message instanceof Secret) {
    throw new Error('You should log a secret with log.secret')
  }
}

const filterLevel = function(level, type) {
  return levels[type] >= levels[level]
}

module.exports = {
  filterSecrets,
  filterLevel
}


/***/ }),
/* 4 */
/***/ (function(module, exports) {

const Secret = function(data) {
  Object.assign(this, data)
  return this
Romain CREY's avatar
Romain CREY committed
}

Secret.prototype.toString = function() {
  throw new Error('Cannot convert Secret to string')
}

module.exports = Secret


/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

const prodFormat = __webpack_require__(6)
const devFormat = __webpack_require__(8)

switch ("none") {
  case 'production':
    module.exports = prodFormat
    break
  case 'development':
    module.exports = devFormat
    break
  case 'standalone':
    module.exports = devFormat
    break
  case 'test':
    module.exports = devFormat
    break
  default:
    module.exports = prodFormat
}


/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

const stringify = __webpack_require__(7)

const LOG_LENGTH_LIMIT = 64 * 1024 - 1

Romain CREY's avatar
Romain CREY committed
function prodFormat(type, message, label, namespace) {
  const log = { time: new Date(), type, label, namespace }

  if (typeof message === 'object') {
    if (message && message.no_retry) {
      log.no_retry = message.no_retry
    }
    if (message && message.message) {
      log.message = message.message
    }
  } else {
    log.message = message
  }

  // properly display error messages
  if (log.message && log.message.stack) {
    log.message = log.message.stack
  }

  // cut the string to avoid a fail in the stack
  let result = log
  try {
    result = stringify(log).substr(0, LOG_LENGTH_LIMIT)
  } catch (err) {
    // eslint-disable-next-line no-console
    console.log(err.message, 'cozy-logger: Failed to convert message to JSON')
  }
  return result
}

module.exports = prodFormat


/***/ }),
/* 7 */
/***/ (function(module, exports) {

exports = module.exports = stringify
exports.getSerialize = serializer

function stringify(obj, replacer, spaces, cycleReplacer) {
  return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces)
}

function serializer(replacer, cycleReplacer) {
  var stack = [], keys = []

  if (cycleReplacer == null) cycleReplacer = function(key, value) {
    if (stack[0] === value) return "[Circular ~]"
    return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]"
  }

  return function(key, value) {
    if (stack.length > 0) {
      var thisPos = stack.indexOf(this)
      ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
      ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
      if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value)
    }
    else stack.push(value)

    return replacer == null ? value : replacer.call(this, key, value)
  }
}


/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {

const util = __webpack_require__(9)
const chalk = __webpack_require__(10)

if (util && util.inspect && util.inspect.defaultOptions) {
  util.inspect.defaultOptions.maxArrayLength = null
  util.inspect.defaultOptions.depth = 2
  util.inspect.defaultOptions.colors = true
}

const type2color = {
  debug: 'cyan',
  warn: 'yellow',
  info: 'blue',
  error: 'red',
  ok: 'green',
  secret: 'red',
  critical: 'red'
}

Romain CREY's avatar
Romain CREY committed
function devFormat(type, message, label, namespace) {
  let formatmessage = message

  if (typeof formatmessage !== 'string') {
    formatmessage = util.inspect(formatmessage)
  }

  let formatlabel = label ? ` : "${label}" ` : ''
  let formatnamespace = namespace ? chalk.magenta(`${namespace}: `) : ''

  let color = type2color[type]
  let formattype = color ? chalk[color](type) : type

  return `${formatnamespace}${formattype}${formatlabel} : ${formatmessage}`
}

module.exports = devFormat
Romain CREY's avatar
Romain CREY committed


/***/ }),
/* 9 */
/***/ (function(module, exports) {

module.exports = require("util");
Romain CREY's avatar
Romain CREY committed

/***/ }),
/* 10 */
Romain CREY's avatar
Romain CREY committed
/***/ (function(module, exports, __webpack_require__) {

"use strict";

const escapeStringRegexp = __webpack_require__(11);
const ansiStyles = __webpack_require__(12);
const stdoutColor = __webpack_require__(18).stdout;
Romain CREY's avatar
Romain CREY committed

const template = __webpack_require__(21);
Romain CREY's avatar
Romain CREY committed

const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');

// `supportsColor.level` → `ansiStyles.color[name]` mapping
const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];

// `color-convert` models to exclude from the Chalk API due to conflicts and such
const skipModels = new Set(['gray']);

const styles = Object.create(null);

function applyOptions(obj, options) {
	options = options || {};

	// Detect level if not set manually
	const scLevel = stdoutColor ? stdoutColor.level : 0;
	obj.level = options.level === undefined ? scLevel : options.level;
	obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0;
}

function Chalk(options) {
	// We check for this.template here since calling `chalk.constructor()`
	// by itself will have a `this` of a previously constructed chalk object
	if (!this || !(this instanceof Chalk) || this.template) {
		const chalk = {};
		applyOptions(chalk, options);

		chalk.template = function () {
			const args = [].slice.call(arguments);
			return chalkTag.apply(null, [chalk.template].concat(args));
		};

		Object.setPrototypeOf(chalk, Chalk.prototype);
		Object.setPrototypeOf(chalk.template, chalk);

		chalk.template.constructor = Chalk;

		return chalk.template;
	}

	applyOptions(this, options);
}

// Use bright blue on Windows as the normal blue color is illegible
if (isSimpleWindowsTerm) {
	ansiStyles.blue.open = '\u001B[94m';
}

for (const key of Object.keys(ansiStyles)) {
	ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');

	styles[key] = {
		get() {
			const codes = ansiStyles[key];
			return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key);
		}
	};
}

styles.visible = {
	get() {
		return build.call(this, this._styles || [], true, 'visible');
	}
};

ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g');
for (const model of Object.keys(ansiStyles.color.ansi)) {
	if (skipModels.has(model)) {
		continue;
	}

	styles[model] = {
		get() {
			const level = this.level;
			return function () {
				const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments);
				const codes = {
					open,
					close: ansiStyles.color.close,
					closeRe: ansiStyles.color.closeRe
				};
				return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
			};
		}
	};
}

ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g');
for (const model of Object.keys(ansiStyles.bgColor.ansi)) {
	if (skipModels.has(model)) {
		continue;
	}

	const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
	styles[bgModel] = {
		get() {
			const level = this.level;
			return function () {
				const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments);
				const codes = {
					open,
					close: ansiStyles.bgColor.close,
					closeRe: ansiStyles.bgColor.closeRe
				};
				return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
			};
		}
	};
}

const proto = Object.defineProperties(() => {}, styles);

function build(_styles, _empty, key) {
	const builder = function () {
		return applyStyle.apply(builder, arguments);
	};

	builder._styles = _styles;
	builder._empty = _empty;

	const self = this;

	Object.defineProperty(builder, 'level', {
		enumerable: true,
		get() {
			return self.level;
		},
		set(level) {
			self.level = level;
		}
	});

	Object.defineProperty(builder, 'enabled', {
		enumerable: true,
		get() {
			return self.enabled;
		},
		set(enabled) {
			self.enabled = enabled;
		}
	});