<commit_before>window.Twine = {}
Twine.shouldDiscardEvent = {}

# Map of node binding ids to objects that describe a node's bindings.
elements = {}

# The number of nodes bound since the last call to Twine.reset().
# Used to determine the next binding id.
nodeCount = 0

# Storage for all bindable data, provided by the caller of Twine.reset().
rootContext = null

keypathRegex = /^[a-z]\w*(\.[a-z]\w*|\[\d+\])*$/i # Tests if a string is a pure keypath.
refreshQueued = false
rootNode = null

currentBindingCallbacks = null

# Cleans up all existing bindings and sets the root node and context.
Twine.reset = (newContext, node = document.documentElement) ->
  for key of elements
    if bindings = elements[key]?.bindings
      obj.teardown() for obj in bindings when obj.teardown

  elements = {}

  rootContext = newContext
  rootNode = node
  rootNode.bindingId = nodeCount = 1

  this

Twine.bind = (node = rootNode, context = Twine.context(node)) ->
  bind(context, node, true)

Twine.afterBound = (callback) ->
  if currentBindingCallbacks
    currentBindingCallbacks.push(callback)
  else
    callback()

bind = (context, node, forceSaveContext) ->
  currentBindingCallbacks = []
  if node.bindingId
    Twine.unbind(node)

  for type, binding of Twine.bindingTypes when definition = node.getAttribute(type)
    element = {bindings: []} unless element  # Defer allocation to prevent GC pressure
    fn = binding(node, context, definition, element)
    element.bindings.push(fn) if fn

  if newContextKey = node.getAttribute('context')
    keypath = keypathForKey(newContextKey)
    if keypath[0] == '$root'
      context = rootContext
      keypath = keypath.slice(1)
    context = getValue(context, keypath) || setValue(context, keypath, {})

  if element || newContextKey || forceSaveContext
    (element ?= {}).childContext = context
    elements[node.bindingId ?= ++nodeCount] = element

  callbacks = currentBindingCallbacks

  # IE and Safari don't support node.children for DocumentFragment and SVGElement nodes.
  # If the element supports children we continue to traverse the children, otherwise
  # we stop traversing that subtree.
  # https://developer.mozilla.org/en-US/docs/Web/API/ParentNode.children
  # As a result, Twine are unsupported within DocumentFragment and SVGElement nodes.
  bind(context, childNode) for childNode in (node.children || [])
  Twine.count = nodeCount

  for callback in callbacks || []
    callback()
  currentBindingCallbacks = null
<commit_msg>support data-attributes<commit_after>window.Twine = {}
Twine.shouldDiscardEvent = {}

# Map of node binding ids to objects that describe a node's bindings.
elements = {}

# The number of nodes bound since the last call to Twine.reset().
# Used to determine the next binding id.
nodeCount = 0

# Storage for all bindable data, provided by the caller of Twine.reset().
rootContext = null

keypathRegex = /^[a-z]\w*(\.[a-z]\w*|\[\d+\])*$/i # Tests if a string is a pure keypath.
refreshQueued = false
rootNode = null

currentBindingCallbacks = null

# Cleans up all existing bindings and sets the root node and context.
Twine.reset = (newContext, node = document.documentElement) ->
  for key of elements
    if bindings = elements[key]?.bindings
      obj.teardown() for obj in bindings when obj.teardown

  elements = {}

  rootContext = newContext
  rootNode = node
  rootNode.bindingId = nodeCount = 1

  this

Twine.bind = (node = rootNode, context = Twine.context(node)) ->
  bind(context, node, true)

Twine.afterBound = (callback) ->
  if currentBindingCallbacks
    currentBindingCallbacks.push(callback)
  else
    callback()

bind = (context, node, forceSaveContext) ->
  currentBindingCallbacks = []
  if node.bindingId
    Twine.unbind(node)

  for type, binding of Twine.bindingTypes when definition = (node.getAttribute(type) || node.getAttribute("data-#{type}"))
    element = {bindings: []} unless element  # Defer allocation to prevent GC pressure
    fn = binding(node, context, definition, element)
    element.bindings.push(fn) if fn

  if newContextKey = node.getAttribute('context')
    keypath = keypathForKey(newContextKey)
    if keypath[0] == '$root'
      context = rootContext
      keypath = keypath.slice(1)
    context = getValue(context, keypath) || setValue(context, keypath, {})

  if element || newContextKey || forceSaveContext
    (element ?= {}).childContext = context
    elements[node.bindingId ?= ++nodeCount] = element

  callbacks = currentBindingCallbacks

  # IE and Safari don't support node.children for DocumentFragment and SVGElement nodes.
  # If the element supports children we continue to traverse the children, otherwise
  # we stop traversing that subtree.
  # https://developer.mozilla.org/en-US/docs/Web/API/ParentNode.children
  # As a result, Twine are unsupported within DocumentFragment and SVGElement nodes.
  bind(context, childNode) for childNode in (node.children || [])
  Twine.count = nodeCount

  for callback in callbacks || []
    callback()
  currentBindingCallbacks = null

{'fraction_non_alphanumeric': 0.10323605320627358, 'fraction_numerical': 0.0015882469724042088, 'mean_word_length': 3.9635467980295567, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 2, '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': '6873033', 'n_tokens_mistral': 1516, 'n_tokens_neox': 1459, 'n_words': 474}