code: function addBinding(constructor, templateInfo, nodeInfo, kind, target, parts, literal) {
    // Create binding metadata and add to nodeInfo
    nodeInfo.bindings = nodeInfo.bindings || [];
    let /** Binding */ binding = { kind, target, parts, literal, isCompound: (parts.length !== 1) };
    nodeInfo.bindings.push(binding);
    // Add listener info to binding metadata
    if (shouldAddListener(binding)) {
      let {event, negate} = binding.parts[0];
      binding.listenerEvent = event || (CaseMap.camelToDashCase(target) + '-changed');
      binding.listenerNegate = negate;
    }
    // Add "propagate" property effects to templateInfo
    let index = templateInfo.nodeInfoList.length;
    for (let i=0; i<binding.parts.length; i++) {
      let part = binding.parts[i];
      part.compoundIndex = i;
      addEffectForBindingPart(constructor, templateInfo, binding, part, index);
    }
  }
docs: -- bindings ---------------------------------------------- 
  Adds binding metadata to the current `nodeInfo`, and binding effects
  for all part dependencies to `templateInfo`.
  
  @param {Function} constructor Class that `_parseTemplate` is currently
  running on
  @param {TemplateInfo} templateInfo Template metadata for current template
  @param {NodeInfo} nodeInfo Node metadata for current template node
  @param {string} kind Binding kind, either 'property', 'attribute', or 'text'
  @param {string} target Target property name
  @param {!Array<!BindingPart>} parts Array of binding part metadata
  @param {string=} literal Literal text surrounding binding parts (specified
  only for 'property' bindings, since these must be initialized as part
  of boot-up)
  @return {void}
  @private