docs: function listener(eventName, listenerFn, useCapture) {
      if (useCapture === void 0) { useCapture = false; }
      ngDevMode && assertPreviousIsParent();
      var node = previousOrParentNode;
      var native = node.native;
      ngDevMode && ngDevMode.rendererAddEventListener++;
      // In order to match current behavior, native DOM event listeners must be added for all
      // events (including outputs).
      if (isProceduralRenderer(renderer)) {
          var wrappedListener = wrapListenerWithDirtyLogic(viewData, listenerFn);
          var cleanupFn = renderer.listen(native, eventName, wrappedListener);
          storeCleanupFn(viewData, cleanupFn);
      }
      else {
          var wrappedListener = wrapListenerWithDirtyAndDefault(viewData, listenerFn);
          native.addEventListener(eventName, wrappedListener, useCapture);
          var cleanupInstances = getCleanup(viewData);
          cleanupInstances.push(wrappedListener);
          if (firstTemplatePass) {
              getTViewCleanup(viewData).push(eventName, node.tNode.index, cleanupInstances.length - 1, useCapture);
          }
      }
      var tNode = node.tNode;
      if (tNode.outputs === undefined) {
          // if we create TNode here, inputs must be undefined so we know they still need to be
          // checked
          tNode.outputs = generatePropertyAliases(node.tNode.flags, 1 /* Output */);
      }
      var outputs = tNode.outputs;
      var outputData;
      if (outputs && (outputData = outputs[eventName])) {
          createOutput(outputData, listenerFn);
      }
  }