<commit_before>'use strict';

/**
 * The `kss/lib/parse` module is normally accessed via the
 * [`parse()`]{@link module:kss.parse} method of the `kss` module:
 * ```
 * const kss = require('kss');
 * let styleGuide = kss.parse(input, options);
 * ```
 * @private
 * @module kss/lib/parse
 */

const KssStyleGuide = require('./kss_styleguide.js'),
  marked = require('marked'),
  natural = require('natural');

// Create a MarkDown renderer that does not output a wrapping paragraph.
const inlineRenderer = new marked.Renderer();
inlineRenderer.paragraph = function(text) {
  return text;
};

let parse, parseChunk,
  createModifiers, createParameters,
  checkReference, processProperty, hasPrefix;

/**
 * Parse an array/string of documented CSS, or an object of files and their
 * content.
 *
 * File object formatted as `{ "absolute filename": content, ... }`.
 *
 * This is called automatically as part of `traverse` but is publicly
 * accessible as well.
 *
 * @alias module:kss.parse
 * @param  {*}        input    The input to parse
 * @param  {Object}   options  Options to alter the output content. Same as the options in [`traverse()`]{@link module:kss.traverse}.
 * @returns {KssStyleGuide} Returns a `KssStyleGuide` object.
 */
parse = function(input, options) {
  // If supplied a string, just make it an Array.
  if (typeof input === 'string') {
    input = [input];
  }

  let styleGuide = {};

  // Otherwise assume the input supplied is a JSON object, as specified above.
  if (!Array.isArray(input)) {
    let files = input;
    input = [];
    styleGuide.files = [];
    for (let fileName in files) {
      // istanbul ignore else
      if (files.hasOwnProperty(fileName)) {
        input.push(files[fileName]);
        styleGuide.files.push(fileName);
      }
    }
    styleGuide.files.sort();
  }

  // Default parsing options
  if (typeof options.markdown === 'undefined') {
    options.markdown = true;
  }
  if (typeof options.header === 'undefined') {
    options.header = true;
  }
  options.typos = options.typos || false;
  options.custom = options.custom || [];

  // Actually parse the input (parseChunk is the key function here.)
  styleGuide.sections = [];
  for (let i = 0; i < input.length; i++) {
    styleGuide = parseChunk(styleGuide, input[i], options);
  }

  return new KssStyleGuide(styleGuide);
};

/**
 * Take a chunk of text and parse the comments. This is the primary parsing
 * function, and eventually returns a `data` variable to use to create a new
 * instance of `KssStyleGuide`.
 *
 * @private
 * @param  {Object} styleGuide    JSON object containing all of the style guide data.
 * @param  {String} input   Text to be parsed, i.e. a single CSS/LESS/etc. file's content.
 * @param  {Object} options The options passed on from `traverse` or `parse`<commit_msg>Refactor parse() in lib/parse. #139<commit_after>'use strict';

/**
 * The `kss/lib/parse` module is normally accessed via the
 * [`parse()`]{@link module:kss.parse} method of the `kss` module:
 * ```
 * const kss = require('kss');
 * let styleGuide = kss.parse(input, options);
 * ```
 * @private
 * @module kss/lib/parse
 */

const KssStyleGuide = require('./kss_styleguide.js'),
  marked = require('marked'),
  natural = require('natural');

// Create a MarkDown renderer that does not output a wrapping paragraph.
const inlineRenderer = new marked.Renderer();
inlineRenderer.paragraph = function(text) {
  return text;
};

let parse, parseChunk,
  createModifiers, createParameters,
  checkReference, processProperty, hasPrefix;

/**
 * Parse an array/string of documented CSS, or an object of files and their
 * content.
 *
 * File object formatted as `{ "absolute filename": content, ... }`.
 *
 * This is called automatically as part of `traverse` but is publicly
 * accessible as well.
 *
 * @alias module:kss.parse
 * @param  {*}        input    The input to parse
 * @param  {Object}   options  Options to alter the output content. Same as the options in [`traverse()`]{@link module:kss.traverse}.
 * @returns {KssStyleGuide} Returns a `KssStyleGuide` object.
 */
parse = function(input, options) {
  // Default parsing options.
  if (typeof options.markdown === 'undefined') {
    options.markdown = true;
  }
  if (typeof options.header === 'undefined') {
    options.header = true;
  }
  options.typos = options.typos || false;
  options.custom = options.custom || [];

  // Massage our input into a "files" array of Vinyl-like objects.
  let files = [],
    styleGuide = {
      sections: []
    };

  // If supplied a string.
  if (typeof input === 'string') {
    files.push({
      contents: input
    });

  // If supplied an array of strings or objects.
  } else if (Array.isArray(input)) {
    files = input.map(value => {
      return (typeof value === 'string') ? {contents: value} : value;
    });

  // Otherwise assume the input supplied is a JSON object, as specified above.
  } else {
    styleGuide.files = [];
    for (let fileName in input) {
      // istanbul ignore else
      if (input.hasOwnProperty(fileName)) {
        files.push({
          path: fileName,
          contents: input[fileName]
        });
        styleGuide.files.push(fileName);
      }
    }
    styleGuide.files.sort();
  }

  // Actually parse the input (parseChunk is the key function here.)
  for (let file of files) {
    styleGuide = parseChunk(styleGuide, file.contents, options);
  }

  return new KssStyleGuide(styleGuide);
};

/**
 * Take a chunk of text and parse the comments. This is the primary parsing
 * function, and eventually returns a `data` variable to use to create a new
 * instance of `KssStyleGuide`.
 *
 * @private
 * @param  {Object} styleGuide    JSON object containing all of the style guide data.
 * @param  {String} input   Text to be parsed, i.e. a single CSS/LESS/etc. file's content.
 * @param  {Object} options The options passed on from `traverse` or `parse`
{'fraction_non_alphanumeric': 0.128087986463621, 'fraction_numerical': 0.0006768189509306261, 'mean_word_length': 3.2525179856115107, 'pattern_counts': {'":': 2, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1114849', 'n_tokens_mistral': 1779, 'n_tokens_neox': 1734, 'n_words': 607}