<commit_before>import { parse as coffeeScriptParse } from 'coffee-script-redux';
import traverse from './traverse';
import Scope from './Scope';
import buildLineAndColumnMap from './buildLineAndColumnMap';

/**
 * Parses a CoffeeScript program and cleans up and annotates the AST.
 *
 * @param {string} source
 * @returns {Object} An AST from CoffeeScriptRedux with `scope` and `parent`.
 */
export default function parse(source) {
  const ast = coffeeScriptParse(source, { raw: true }).toBasicObject();
  const map = buildLineAndColumnMap(source);

  traverse(ast, function(node) {
    attachScope(node);
    fixRange(node, map, source);
  });

  return ast;
}

/**
 * @param {Object} node
 * @private
 */
function attachScope(node) {
  switch (node.type) {
    case 'Program':
      node.scope = new Scope();
      break;

    case 'Function':
    case 'BoundFunction':
      node.scope = new Scope(node.parent.scope);
      break;

    default:
      node.scope = node.parent.scope;
      break;
  }

  node.scope.processNode(node);
}

/**
 * @param {Object} node
 * @param {LineAndColumnMap} map
 * @param {string} source
 * @private
 */
function fixRange(node, map, source) {
  if (!node.range && node.type === 'ConcatOp') { return; }

  if (!('raw' in node)) {
    if (node.parent && node.parent.type === 'While' && node.parent.condition === node) {
      // Ignore `while` condition without raw
      return;
    } else if (node.type === 'LogicalNotOp' && node.parent.type === 'Conditional' && node.parent.condition === node) {
      node.raw = node.expression.raw;
      node.range = node.expression.range;
    } else {
      throw new Error(
        'BUG! Could not fix range for ' + node.type +
        ' because it has no raw value'
      );
    }
  }

  const fixed = map.getOffset(node.line - 1, node.column - 1);
  if (source.slice(fixed, fixed + node.raw.length) === node.raw) {
    node.range = [fixed, fixed + node.raw.length];
  }

  if (!node.range || node.raw !== source.slice(node.range[0], node.range[1])) {
    if (node.parent && node.parent.step === node) {
      // Ignore invalid `step` parameters, they're autogenerated if left out.
      return;
    }

    throw new Error(
      'BUG! Could not fix range for ' + node.type +
      ' at line ' + node.line + ', column ' + node.column
    );
  }
}<commit_msg>Use the dasherized form of this word.<commit_after>import { parse as coffeeScriptParse } from 'coffee-script-redux';
import traverse from './traverse';
import Scope from './Scope';
import buildLineAndColumnMap from './buildLineAndColumnMap';

/**
 * Parses a CoffeeScript program and cleans up and annotates the AST.
 *
 * @param {string} source
 * @returns {Object} An AST from CoffeeScriptRedux with `scope` and `parent`.
 */
export default function parse(source) {
  const ast = coffeeScriptParse(source, { raw: true }).toBasicObject();
  const map = buildLineAndColumnMap(source);

  traverse(ast, function(node) {
    attachScope(node);
    fixRange(node, map, source);
  });

  return ast;
}

/**
 * @param {Object} node
 * @private
 */
function attachScope(node) {
  switch (node.type) {
    case 'Program':
      node.scope = new Scope();
      break;

    case 'Function':
    case 'BoundFunction':
      node.scope = new Scope(node.parent.scope);
      break;

    default:
      node.scope = node.parent.scope;
      break;
  }

  node.scope.processNode(node);
}

/**
 * @param {Object} node
 * @param {LineAndColumnMap} map
 * @param {string} source
 * @private
 */
function fixRange(node, map, source) {
  if (!node.range && node.type === 'ConcatOp') { return; }

  if (!('raw' in node)) {
    if (node.parent && node.parent.type === 'While' && node.parent.condition === node) {
      // Ignore `while` condition without raw
      return;
    } else if (node.type === 'LogicalNotOp' && node.parent.type === 'Conditional' && node.parent.condition === node) {
      node.raw = node.expression.raw;
      node.range = node.expression.range;
    } else {
      throw new Error(
        'BUG! Could not fix range for ' + node.type +
        ' because it has no raw value'
      );
    }
  }

  const fixed = map.getOffset(node.line - 1, node.column - 1);
  if (source.slice(fixed, fixed + node.raw.length) === node.raw) {
    node.range = [fixed, fixed + node.raw.length];
  }

  if (!node.range || node.raw !== source.slice(node.range[0], node.range[1])) {
    if (node.parent && node.parent.step === node) {
      // Ignore invalid `step` parameters, they're auto-generated if left out.
      return;
    }

    throw new Error(
      'BUG! Could not fix range for ' + node.type +
      ' at line ' + node.line + ', column ' + node.column
    );
  }
}
{'fraction_non_alphanumeric': 0.15201192250372578, 'fraction_numerical': 0.0017032148179689163, 'mean_word_length': 2.9052369077306732, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '3993159', 'n_tokens_mistral': 1510, 'n_tokens_neox': 1471, 'n_words': 412}