index.js
function serialize (node, context, fn, eventTarget) {
  if (!node) return '';
  if ('function' === typeof context) {
    fn = context;
    context = null;
  }
  if (!context) context = null;

  var rtn;
  var nodeType = node.nodeType;

  if (!nodeType && 'number' === typeof node.length) {
    // assume it's a NodeList or Array of Nodes
    rtn = exports.serializeNodeList(node, context, fn);
  } else {

    if ('function' === typeof fn) {
      // one-time "serialize" event listener
      node.addEventListener('serialize', fn, false);
    }

    // emit a custom "serialize" event on `node`, in case there
    // are event listeners for custom serialization of this node
    var e = new CustomEvent('serialize', {
      bubbles: true,
      cancelable: true,
      detail: {
        serialize: null,
        context: context
      }
    });

    e.serializeTarget = node;

    var target = eventTarget || node;
    var cancelled = !target.dispatchEvent(e);

    // `e.detail.serialize` can be set to a:
    //   String - returned directly
    //   Node   - goes through serializer logic instead of `node`
    //   Anything else - get Stringified first, and then returned directly
    var s = e.detail.serialize;
    if (s != null) {
      if ('string' === typeof s) {
        rtn = s;
      } else if ('number' === typeof s.nodeType) {
        // make it go through the serialization logic
        rtn = serialize(s, context, null, target);
      } else {
        rtn = String(s);
      }
    } else if (!cancelled) {
      // default serialization logic
      switch (nodeType) {
        case 1 /* element */:
          rtn = exports.serializeElement(node, context, eventTarget);
          break;
        case 2 /* attribute */:
          rtn = exports.serializeAttribute(node);
          break;
        case 3 /* text */:
          rtn = exports.serializeText(node);
          break;
        case 8 /* comment */:
          rtn = exports.serializeComment(node);
          break;
        case 9 /* document */:
          rtn = exports.serializeDocument(node, context, eventTarget);
          break;
        case 10 /* doctype */:
          rtn = exports.serializeDoctype(node);
          break;
        case 11 /* document fragment */:
          rtn = exports.serializeDocumentFragment(node, context, eventTarget);
          break;
      }
    }

    if ('function' === typeof fn) {
      node.removeEventListener('serialize', fn, false);
    }
  }

  return rtn || '';
}
function serialize (node, context, fn, eventTarget) {
  if (!node) return '';
  if ('function' === typeof context) {
    fn = context;
    context = null;
  }
  if (!context) context = null;

  var rtn;
  var nodeType = node.nodeType;

  if (!nodeType && 'number' === typeof node.length) {
    // assume it's a NodeList or Array of Nodes
    rtn = exports.serializeNodeList(node, context, fn);
  } else {

    if ('function' === typeof fn) {
      // one-time "serialize" event listener
      node.addEventListener('serialize', fn, false);
    }

    // emit a custom "serialize" event on `node`, in case there
    // are event listeners for custom serialization of this node
    var e = new CustomEvent('serialize', {
      bubbles: true,
      cancelable: true,
      detail: {
        serialize: null,
        context: context
      }
    });

    e.serializeTarget = node;

    var target = eventTarget || node;
    var cancelled = !target.dispatchEvent(e);

    // `e.detail.serialize` can be set to a:
    //   String - returned directly
    //   Node   - goes through serializer logic instead of `node`
    //   Anything else - get Stringified first, and then returned directly
    var s = e.detail.serialize;
    if (s != null) {
      if ('string' === typeof s) {
        rtn = s;
      } else if ('number' === typeof s.nodeType) {
        // make it go through the serialization logic
        rtn = serialize(s, context, null, target);
      } else {
        rtn = String(s);
      }
    } else if (!cancelled) {
      // default serialization logic
      switch (nodeType) {
        case 1 /* element */:
          rtn = exports.serializeElement(node, context, eventTarget);
          break;
        case 2 /* attribute */:
          rtn = exports.serializeAttribute(node);
          break;
        case 3 /* text */:
          rtn = exports.serializeText(node);
          break;
        case 8 /* comment */:
          rtn = exports.serializeComment(node);
          break;
        case 9 /* document */:
          rtn = exports.serializeDocument(node, context, eventTarget);
          break;
        case 10 /* doctype */:
          rtn = exports.serializeDoctype(node);
          break;
        case 11 /* document fragment */:
          rtn = exports.serializeDocumentFragment(node, context, eventTarget);
          break;
      }
    }

    if ('function' === typeof fn) {
      node.removeEventListener('serialize', fn, false);
    }
  }

  return rtn || '';
}
function serialize ( node , context , fn , eventTarget ) { if ( ! node ) return '' ; if ( 'function' === typeof context ) { fn = context ; context = null ; } if ( ! context ) context = null ; var rtn ; var nodeType = node . nodeType ; if ( ! nodeType && 'number' === typeof node . length ) { // assume it's a NodeList or Array of Nodes rtn = exports . serializeNodeList ( node , context , fn ) ; } else { if ( 'function' === typeof fn ) { // one-time "serialize" event listener node . addEventListener ( 'serialize' , fn , false ) ; } // emit a custom "serialize" event on `node`, in case there // are event listeners for custom serialization of this node var e = new CustomEvent ( 'serialize' , { bubbles : true , cancelable : true , detail : { serialize : null , context : context } } ) ; e . serializeTarget = node ; var target = eventTarget || node ; var cancelled = ! target . dispatchEvent ( e ) ; // `e.detail.serialize` can be set to a: //   String - returned directly //   Node   - goes through serializer logic instead of `node` //   Anything else - get Stringified first, and then returned directly var s = e . detail . serialize ; if ( s != null ) { if ( 'string' === typeof s ) { rtn = s ; } else if ( 'number' === typeof s . nodeType ) { // make it go through the serialization logic rtn = serialize ( s , context , null , target ) ; } else { rtn = String ( s ) ; } } else if ( ! cancelled ) { // default serialization logic switch ( nodeType ) { case 1 /* element */ : rtn = exports . serializeElement ( node , context , eventTarget ) ; break ; case 2 /* attribute */ : rtn = exports . serializeAttribute ( node ) ; break ; case 3 /* text */ : rtn = exports . serializeText ( node ) ; break ; case 8 /* comment */ : rtn = exports . serializeComment ( node ) ; break ; case 9 /* document */ : rtn = exports . serializeDocument ( node , context , eventTarget ) ; break ; case 10 /* doctype */ : rtn = exports . serializeDoctype ( node ) ; break ; case 11 /* document fragment */ : rtn = exports . serializeDocumentFragment ( node , context , eventTarget ) ; break ; } } if ( 'function' === typeof fn ) { node . removeEventListener ( 'serialize' , fn , false ) ; } } return rtn || '' ; }
Serializes any DOM node. Returns a string.

@param {Node} node - DOM Node to serialize
@param {String} [context] - optional arbitrary "context" string to use (useful for event listeners)
@param {Function} [fn] - optional callback function to use in the "serialize" event for this call
@param {EventTarget} [eventTarget] - optional EventTarget instance to emit the "serialize" event on (defaults to `node`)
return {String}
@public
Serializes any DOM node . Returns a string .