<commit_before># Astract Syntax Tree location data
# ---------------------------------

testAstLocationData = (code, expected) ->
  ast = CoffeeScript.compile code, ast: yes
  testAstNodeLocationData ast.expressions[0], expected

testAstNodeLocationData = (node, expected, path = '') ->
  extendPath = (additionalPath) ->
    return additionalPath unless path
    "#{path}.#{additionalPath}"
  ok node?, "Missing expected node at '#{path}'"
  testSingleNodeLocationData node, expected, path if expected.range?
  for own key, expectedChild of expected when key not in ['start', 'end', 'range', 'loc']
    if Array.isArray expectedChild
      ok Array.isArray(node[key]), "Missing expected array at '#{extendPath key}'"
      for expectedItem, index in expectedChild
        testAstNodeLocationData node[key][index], expectedItem, extendPath "#{key}[#{index}]"
    else if typeof expectedChild is 'object'
      testAstNodeLocationData node[key], expectedChild, extendPath key

testSingleNodeLocationData = (node, expected, path) ->
  pathStr = if path then " at '#{path}'" else ''
  # Even though it’s not part of the location data, check the type to ensure
  # that we’re testing the node we think we are.
  if expected.type?
    eq node.type, expected.type, \
      "Expected AST node type #{reset}#{node.type}#{red} to equal #{reset}#{expected.type}#{red}"

  eq node.start, expected.start, \
    "Expected location start #{reset}#{node.start}#{red} to equal #{reset}#{expected.start}#{red}#{pathStr}"
  eq node.end, expected.end, \
    "Expected location end #{reset}#{node.end}#{red} to equal #{reset}#{expected.end}#{red}#{pathStr}"
  arrayEq node.range, expected.range, \
    "Expected location range #{reset}#{JSON.stringify node.range}#{red} to equal #{reset}#{JSON.stringify expected.range}#{red}#{pathStr}"
  eq node.loc.start.line, expected.loc.start.line, \
    "Expected location start line #{reset}#{node.loc.start.line}#{red} to equal #{reset}#{expected.loc.start.line}#{red}#{pathStr}"
  eq node.loc.start.column, expected.loc.start.column, \
    "Expected location start column #{reset}#{node.loc.start.column}#{red} to equal #{reset}#{expected.loc.start.column}#{red}#{pathStr}"
  eq node.loc.end.line, expected.loc.end.line, \
    "Expected location end line #{reset}#{node.loc.end.line}#{red} to equal #{reset}#{expected.loc.end.line}#{red}#{pathStr}"
  eq node.loc.end.column, expected.loc.end.column, \
    "Expected location end column #{reset}#{node.loc.end.column}#{red} to equal #{reset}#{expected.loc.end.column}#{red}#{pathStr}"

test "AST location data as expected for NumberLiteral node", ->
  testAstLocationData '42',
    type: 'NumericLiteral'
    start: 0
    end: 2
    range: [0, 2]
    loc:
      start:
        line: 1
        column: 0
      end:
        line: 1
        column: 2

test "AST location data as expected for InfinityLiteral node", ->
  testAstLocationData 'Infinity',
    type: 'Identifier'
    start: 0<commit_msg>Make error message for location AST paths connect the path to the property we're comparing<commit_after># Astract Syntax Tree location data
# ---------------------------------

testAstLocationData = (code, expected) ->
  ast = CoffeeScript.compile code, ast: yes
  testAstNodeLocationData ast.expressions[0], expected

testAstNodeLocationData = (node, expected, path = '') ->
  extendPath = (additionalPath) ->
    return additionalPath unless path
    "#{path}.#{additionalPath}"
  ok node?, "Missing expected node at '#{path}'"
  testSingleNodeLocationData node, expected, path if expected.range?
  for own key, expectedChild of expected when key not in ['start', 'end', 'range', 'loc']
    if Array.isArray expectedChild
      ok Array.isArray(node[key]), "Missing expected array at '#{extendPath key}'"
      for expectedItem, index in expectedChild
        testAstNodeLocationData node[key][index], expectedItem, extendPath "#{key}[#{index}]"
    else if typeof expectedChild is 'object'
      testAstNodeLocationData node[key], expectedChild, extendPath(key)

testSingleNodeLocationData = (node, expected, path = '') ->
  # Even though it’s not part of the location data, check the type to ensure
  # that we’re testing the node we think we are.
  if expected.type?
    eq node.type, expected.type, \
      "Expected AST node type #{reset}#{node.type}#{red} to equal #{reset}#{expected.type}#{red}"

  eq node.start, expected.start, \
    "Expected #{path}.start: #{reset}#{node.start}#{red} to equal #{reset}#{expected.start}#{red}"
  eq node.end, expected.end, \
    "Expected #{path}.end: #{reset}#{node.end}#{red} to equal #{reset}#{expected.end}#{red}"
  arrayEq node.range, expected.range, \
    "Expected #{path}.range: #{reset}#{JSON.stringify node.range}#{red} to equal #{reset}#{JSON.stringify expected.range}#{red}"
  eq node.loc.start.line, expected.loc.start.line, \
    "Expected #{path}.loc.start.line: #{reset}#{node.loc.start.line}#{red} to equal #{reset}#{expected.loc.start.line}#{red}"
  eq node.loc.start.column, expected.loc.start.column, \
    "Expected #{path}.loc.start.column: #{reset}#{node.loc.start.column}#{red} to equal #{reset}#{expected.loc.start.column}#{red}"
  eq node.loc.end.line, expected.loc.end.line, \
    "Expected #{path}.loc.end.line: #{reset}#{node.loc.end.line}#{red} to equal #{reset}#{expected.loc.end.line}#{red}"
  eq node.loc.end.column, expected.loc.end.column, \
    "Expected #{path}.loc.end.column: #{reset}#{node.loc.end.column}#{red} to equal #{reset}#{expected.loc.end.column}#{red}"

test "AST location data as expected for NumberLiteral node", ->
  testAstLocationData '42',
    type: 'NumericLiteral'
    start: 0
    end: 2
    range: [0, 2]
    loc:
      start:
        line: 1
        column: 0
      end:
        line: 1
        column: 2

test "AST location data as expected for InfinityLiteral node", ->
  testAstLocationData 'Infinity',
    type: 'Identifier'
    start: 0
{'fraction_non_alphanumeric': 0.16260987153482082, 'fraction_numerical': 0.004056795131845842, 'mean_word_length': 3.8981788079470197, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, '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': '3392703', 'n_tokens_mistral': 1837, 'n_tokens_neox': 1875, 'n_words': 506}