{"size": 2480, "ext": "js", "max_stars_repo_path": "src/index.js", "max_stars_repo_name": "mohsen1/json-to-json-schema", "max_stars_repo_stars_event_min_datetime": "2015-11-04T23:43:14.000Z", "max_stars_repo_stars_event_max_datetime": "2021-11-13T04:58:11.000Z", "max_issues_repo_path": "src/index.js", "max_issues_repo_name": "mohsen1/json-to-json-schema", "max_issues_repo_issues_event_min_datetime": "2015-10-29T00:06:35.000Z", "max_issues_repo_issues_event_max_datetime": "2016-08-10T16:06:21.000Z", "max_forks_repo_path": "src/index.js", "max_forks_repo_name": "mohsen1/json-to-json-schema", "max_forks_repo_forks_event_min_datetime": "2015-11-15T22:10:04.000Z", "max_forks_repo_forks_event_max_datetime": "2022-02-03T22:30:19.000Z"}
{"max_stars_count": 33, "max_issues_count": 5, "max_forks_count": 6, "avg_line_length": 21.1965811966, "max_line_length": 104, "alphanum_fraction": 0.5532258065}
'use strict';

import isEqual from 'lodash.isequal';

// Regex used here are all from 
// http://code.tutsplus.com/tutorials/8-regular-expressions-you-should-know--net-6149 
const FORMAT_REGEX = {
  email : /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/,
  url   : /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/,
  ip    : /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ 
};

/*
 * Converts a JSON object to a JSON Schema
 * @param {any} json
 * @param {object} options
 * @returns {object} a json schema
*/
function convert (json, options = {}) {

  if (typeof json === 'function') {
    throw new TypeError('Can not convert a function');
  }

  if (json === undefined) {
    return {};
  }

  // primitives
  if (typeof json === 'string') {

    if (FORMAT_REGEX.url.test(json)){
      return {type: 'string', format: 'url'};
    }

    if (FORMAT_REGEX.email.test(json)){
      return {type:'string', format: 'email'};
    }

    if (FORMAT_REGEX.ip.test(json)){
      return {type:'string', format: 'ip'};
    }

    // TODO: date format
    return {type: 'string'};
  }

  if (typeof json === 'boolean') {
    return {type: 'boolean'};
  }

  if (typeof json === 'number') {
    if (Number.isInteger(json)) {
      return {type: 'integer'};
    } else {
      return {type: 'number'};
    }
  }

  if (json === null) {
    return {type: 'null'};
  }

  if (Array.isArray(json)) {
    let schema = {type: 'array'};

    if (!json.length) {
      schema.items = {};
      return schema;
    }

    let schemas = json.map(convert);

    // if all schemas are the same use that schema for items
    if (schemas.every(s=> isEqual(s, schemas[0]))) {
      schema.items = schemas[0];

    // if there are multiple schemas use oneOf
    } else {
      schema.items = {oneOf: unique(schemas)};
    }

    return schema;
  }

  let schema = {type: 'object'};

  if (!Object.keys(json).length) {
    return schema;
  }

  schema.properties = Object.keys(json).reduce((properties, key) => {
    properties[key] = convert(json[key]);
    return properties;
  }, {});

  return schema;
}

/*
 * Removes duplicates from array using isEqual comparator
 * @param {array}
 * @return {array}
*/
function unique(arr = []) {
  return arr.reduce((result, item) => {

    // result does not contain item
    if (!result.some(i=> isEqual(i, item))) {
      result.push(item);
    }
    return result;
  }, []);
}

export {convert};
