'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = parse;

var _doctrine;

function _load_doctrine() {
  return _doctrine = _interopRequireDefault(require('doctrine'));
}

var _exampleTagParser;

function _load_exampleTagParser() {
  return _exampleTagParser = _interopRequireDefault(require('./example-tag-parser'));
}

var _utils;

function _load_utils() {
  return _utils = require('../utils');
}

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function formatTag(tag) {
  delete tag.title;
  if (!tag.type) return tag;
  var formattedType = (_doctrine || _load_doctrine()).default.type.stringify(tag.type);
  if (tag.type.type === (_doctrine || _load_doctrine()).default.type.Syntax.TypeApplication) {
    // Doctrine adds a dot after the generic type for historical reasons.
    // see here for more info: https://github.com/eslint/doctrine/issues/185
    formattedType = formattedType.replace('.<', '<');
  }
  tag.type = formattedType;

  return tag;
}


function extractDataRegex(doc, doclets, filePath) {
  var commentsAst = (_doctrine || _load_doctrine()).default.parse(doc.trim(), { unwrap: true, recoverable: true });
  if (!commentsAst) return;

  var args = [];
  var description = commentsAst.description;
  var returns = {};
  var isStatic = false;
  var access = 'public';
  var examples = [];
  var properties = [];
  var name = '';
  var render = '';

  commentsAst.tags.forEach(function (tag) {
    switch (tag.title) {
      case 'desc':
      case 'description':
        description = tag.description;
        break;
      case 'name':
        name = tag.name;
        break;
      case 'param':
      case 'arg':
      case 'argument':
        args.push(formatTag(tag));
        break;
      case 'returns':
      case 'return':
        returns = formatTag(tag);
        break;
      case 'static':
        isStatic = true;
        break;
      case 'private':
      case 'protected':
        access = tag.title;
        break;
      case 'access':
        access = tag.access;
        break;
      case 'example':
        examples.push((0, (_exampleTagParser || _load_exampleTagParser()).default)(tag.description));
        break;
      case 'property':
        properties.push(formatTag(tag));
        break;
      case 'render':
        render = tag.description;
        break;
      default:
        break;
    }
  });

  var doclet = {
    name, // todo: find the function/method name by regex
    description,
    args,
    returns,
    access,
    examples,
    render,
    properties,
    static: isStatic,
    filePath: (0, (_utils || _load_utils()).pathNormalizeToLinux)(filePath)
  };
  doclets.push(doclet);
}

function parse(data, filePath) {
  var doclets = [];
  try {
    /**
     * [ \t]*  => can start with any number of tabs
     * \/\*\*  => must start with exact `/**`
     * \s*     => may follow with any number of white spaces
     * [^*]*   => anything except star may repeat
     * ([^\*]|(\*(?!\/)))* => may follow with stars as long as there is no "/" after the star
     * \*\/ => must finish with a star and then \.
     * This was taken as a combination of:
     * https://stackoverflow.com/questions/35905181/regex-for-jsdoc-comments
     * https://github.com/neogeek/jsdoc-regex/blob/master/index.js
     */
    var jsdocRegex = /[ \t]*\/\*\*\s*\n([^*]|(\*(?!\/)))*\*\//g;
    var docs = data.match(jsdocRegex);
    // populate doclets array
    docs.forEach(function (doc) {
      return extractDataRegex(doc, doclets, filePath);
    });
  } catch (e) {
    // never mind, ignore the doc of this source
  }

  return doclets.filter(function (doclet) {
    return doclet.access === 'public';
  });
}