<commit_before>
{last, find} = require './helpers'

$ = require './symbols'

HTML_ELEMENTS = require('./htmlelements')

stringEscape = require './stringescape'

entityDecode = require './entitydecode'

module.exports = exports = serialise = (parseTree) ->
  new Serialiser().serialise(parseTree)

class Serialiser
  serialise: (parseTree) ->
    if parseTree.children and
    parseTree.children.length and
    parseTree.children[0].type is $.CJSX_PRAGMA
      @domObject = parseTree.children[0].value
    else
      @domObject = 'React.DOM'

    @serialiseNode(parseTree)

  serialiseNode: (node) ->
    unless nodeSerialisers[node.type]?
      throw new Error("unknown parseTree node type #{node.type}")

    serialised = nodeSerialisers[node.type].call(this, node)

    unless typeof serialised is 'string' or serialised is null
      throw new Error("serialiser #{node.type} didn\'t return a string")

    serialised

  serialiseSpreadAndPairAttributes: (children) ->
    assigns = []
    pairAttrsBuffer = []

    flushPairs = =>
      if pairAttrsBuffer.length
        serialisedChild = @serialiseAttributePairs(pairAttrsBuffer)
        assigns.push(serialisedChild) if serialisedChild # skip null
        pairAttrsBuffer = [] # reset buffer

    if firstNonWhitespaceChild(children)?.type is $.CJSX_ATTR_SPREAD
      assigns.push('{}')

    for child, childIndex in children
      if child.type is $.CJSX_ATTR_SPREAD
        flushPairs()
        assigns.push(child.value)
      else
        pairAttrsBuffer.push(child)

      flushPairs()

    "Object.assign(#{assigns.join(', ')})"

  serialiseAttributePairs: (children) ->
    # whitespace (particularly newlines) must be maintained
    # to ensure line number parity

    # sort children into whitespace and semantic (non whitespace) groups
    # this seems wrong :\
    [whitespaceChildren, semanticChildren] = children.reduce((partitionedChildren, child) ->
      if child.type is $.CJSX_WHITESPACE
        partitionedChildren[0].push child
      else
        partitionedChildren[1].push child
      partitionedChildren
    , [[],[]])

    indexOfLastSemanticChild = children.lastIndexOf(last(semanticChildren))

    isBeforeLastSemanticChild = (childIndex) ->
      childIndex < indexOfLastSemanticChild

    if semanticChildren.length
      serialisedChildren = for child, childIndex in children
        serialisedChild = @serialiseNode child
        if child.type is $.CJSX_WHITESPACE
          if containsNewlines(serialisedChild)
            if isBeforeLastSemanticChild(childIndex)
              # escaping newlines within attr object helps avoid
              # parse errors in tags which span multiple lines
              serialisedChild.replace('\n',' \\\n')
            else
              # but escaped newline at end of attr object is not allowed
              serialisedChild
          else
            null # whitespace without newlines is not significant
        else if isBeforeLastSemanticChild(childIndex)
          serialisedChild+', '
        else
          serialisedChild

      '{'+serialisedChildren.join('')+'}'
    else
      null

genericBranchSerialiser = (node) ->
  node.children
    .map((child) => @serialiseNode child)
    .join('')

genericLeafSerialiser = (node) -> node.value

nodeSerialisers =
  ROOT: genericBranchSerialiser

  CJSX_PRAGMA: -> null

  CJSX_EL: (node) ->
    serialisedChildren = []
    accumulatedWhitespace = ''

    for child in node.children
      serialisedChild = @serialiseNode child
      if child? # filter empty text nodes
        if WHITESPACE_ONLY.test serialisedChild
          accumulatedWhitespace += serialisedChild
        else
          serialisedChildren.push(accumulatedWhitespace + serialisedChild)
          accumulatedWhitespace = ''

    if serialisedChildren.length
      serialisedChildren[serialisedChildren.length-1] += accumulatedWhitespace
      accumulatedWhitespace = ''

    prefix = 'React.createElement('
    prefix += if HTML_ELEMENTS[node.value]? then @domObject+'.' else ''
    prefix+node.value+', '+serialisedChildren.join(', ')+')'

  CJSX_ESC: (node) ->
    childrenSerialised = node.children
      .map((child) => @serialiseNode child)
      .join('')
    '('+childrenSerialised+')'

  CJSX_ATTRIBUTES: (node) ->
    if node.children.some((child) -> child.type is $.CJSX_ATTR_SPREAD)
      @serialiseSpreadAndPairAttributes(node.children)
    else
      @serialiseAttributePairs(node.children) or 'null'

  CJSX_ATTR_PAIR: (node) ->
    node.children
      .map((child) => @serialiseNode child)
      .join(': ')

  CJSX_ATTR_SPREAD: (node) ->
    node.value

  # leaf nodes
  CS: genericLeafSerialiser
  CS_COMMENT: genericLeafSerialiser
  CS_HEREDOC: genericLeafSerialiser
  CS_STRING: genericLeafSerialiser<commit_msg>clean up element serialiser<commit_after>
{last, find} = require './helpers'

$ = require './symbols'

HTML_ELEMENTS = require('./htmlelements')

stringEscape = require './stringescape'

entityDecode = require './entitydecode'

module.exports = exports = serialise = (parseTree) ->
  new Serialiser().serialise(parseTree)

class Serialiser
  serialise: (parseTree) ->
    if parseTree.children and
    parseTree.children.length and
    parseTree.children[0].type is $.CJSX_PRAGMA
      @domObject = parseTree.children[0].value
    else
      @domObject = 'React.DOM'

    @serialiseNode(parseTree)

  serialiseNode: (node) ->
    unless nodeSerialisers[node.type]?
      throw new Error("unknown parseTree node type #{node.type}")

    serialised = nodeSerialisers[node.type].call(this, node)

    unless typeof serialised is 'string' or serialised is null
      throw new Error("serialiser #{node.type} didn\'t return a string")

    serialised

  serialiseSpreadAndPairAttributes: (children) ->
    assigns = []
    pairAttrsBuffer = []

    flushPairs = =>
      if pairAttrsBuffer.length
        serialisedChild = @serialiseAttributePairs(pairAttrsBuffer)
        assigns.push(serialisedChild) if serialisedChild # skip null
        pairAttrsBuffer = [] # reset buffer

    if firstNonWhitespaceChild(children)?.type is $.CJSX_ATTR_SPREAD
      assigns.push('{}')

    for child, childIndex in children
      if child.type is $.CJSX_ATTR_SPREAD
        flushPairs()
        assigns.push(child.value)
      else
        pairAttrsBuffer.push(child)

      flushPairs()

    "Object.assign(#{assigns.join(', ')})"

  serialiseAttributePairs: (children) ->
    # whitespace (particularly newlines) must be maintained
    # to ensure line number parity

    # sort children into whitespace and semantic (non whitespace) groups
    # this seems wrong :\
    [whitespaceChildren, semanticChildren] = children.reduce((partitionedChildren, child) ->
      if child.type is $.CJSX_WHITESPACE
        partitionedChildren[0].push child
      else
        partitionedChildren[1].push child
      partitionedChildren
    , [[],[]])

    indexOfLastSemanticChild = children.lastIndexOf(last(semanticChildren))

    isBeforeLastSemanticChild = (childIndex) ->
      childIndex < indexOfLastSemanticChild

    if semanticChildren.length
      serialisedChildren = for child, childIndex in children
        serialisedChild = @serialiseNode child
        if child.type is $.CJSX_WHITESPACE
          if containsNewlines(serialisedChild)
            if isBeforeLastSemanticChild(childIndex)
              # escaping newlines within attr object helps avoid
              # parse errors in tags which span multiple lines
              serialisedChild.replace('\n',' \\\n')
            else
              # but escaped newline at end of attr object is not allowed
              serialisedChild
          else
            null # whitespace without newlines is not significant
        else if isBeforeLastSemanticChild(childIndex)
          serialisedChild+', '
        else
          serialisedChild

      '{'+serialisedChildren.join('')+'}'
    else
      null

genericBranchSerialiser = (node) ->
  node.children
    .map((child) => @serialiseNode child)
    .join('')

genericLeafSerialiser = (node) -> node.value

nodeSerialisers =
  ROOT: genericBranchSerialiser

  CJSX_PRAGMA: -> null

  CJSX_EL: (node) ->
    serialisedChildren = []
    accumulatedWhitespace = ''

    for child in node.children
      serialisedChild = @serialiseNode child
      if child? # filter empty text nodes
        if WHITESPACE_ONLY.test serialisedChild
          accumulatedWhitespace += serialisedChild
        else
          serialisedChildren.push(accumulatedWhitespace + serialisedChild)
          accumulatedWhitespace = ''

    if serialisedChildren.length
      serialisedChildren[serialisedChildren.length-1] += accumulatedWhitespace
      accumulatedWhitespace = ''

    if HTML_ELEMENTS[node.value]?
      prefix = @domObject+'.'
    else
      prefix = ''
    "React.createElement(#{prefix}#{node.value}, #{serialisedChildren.join(', ')})"

  CJSX_ESC: (node) ->
    childrenSerialised = node.children
      .map((child) => @serialiseNode child)
      .join('')
    '('+childrenSerialised+')'

  CJSX_ATTRIBUTES: (node) ->
    if node.children.some((child) -> child.type is $.CJSX_ATTR_SPREAD)
      @serialiseSpreadAndPairAttributes(node.children)
    else
      @serialiseAttributePairs(node.children) or 'null'

  CJSX_ATTR_PAIR: (node) ->
    node.children
      .map((child) => @serialiseNode child)
      .join(': ')

  CJSX_ATTR_SPREAD: (node) ->
    node.value

  # leaf nodes
  CS: genericLeafSerialiser
  CS_COMMENT: genericLeafSerialiser
  CS_HEREDOC: genericLeafSerialiser
  CS_STRING: genericLeafSerialiser
{'fraction_non_alphanumeric': 0.09816207184628237, 'fraction_numerical': 0.0010442773600668337, 'mean_word_length': 3.054614733276884, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 43, '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': '6500840', 'n_tokens_mistral': 2837, 'n_tokens_neox': 2758, 'n_words': 632}