code: function virtualDOMfromNode(node, shadowId) {
  	const vNodeCache = {};
  	const vNode = {
  		shadowId: shadowId,
  		children: [],
  		actualNode: node,
  		_isHidden: null, // will be populated by axe.utils.isHidden
  		get isFocusable() {
  			if (!vNodeCache._isFocusable) {
  				vNodeCache._isFocusable = axe.commons.dom.isFocusable(node);
  			}
  			return vNodeCache._isFocusable;
  		},
  		get tabbableElements() {
  			if (!vNodeCache._tabbableElements) {
  				vNodeCache._tabbableElements = axe.commons.dom.getTabbableElements(
  					this
  				);
  			}
  			return vNodeCache._tabbableElements;
  		}
  	};
  	axe._cache.nodeMap.set(node, vNode);
  	return vNode;
  }
docs: This implemnts the flatten-tree algorithm specified:
  Originally here https://drafts.csswg.org/css-scoping/#flat-tree
  Hopefully soon published here: https://www.w3.org/TR/css-scoping-1/#flat-tree
  
  Some notable information:
  ****** NOTE: as of Chrome 59, this is broken in Chrome so that tests fail completely
  ****** removed functionality for now
  1. <slot> elements do not have boxes by default (i.e. they do not get rendered and
  their CSS properties are ignored)
  2. <slot> elements can be made to have a box by overriding the display property
  which is 'contents' by default
  3. Even boxed <slot> elements do not show up in the accessibility tree until
  they have a tabindex applied to them OR they have a role applied to them AND
  they have a box (this is observed behavior in Safari on OS X, I cannot find
  the spec for this)
   
  Wrap the real node and provide list of the flattened children
  
  @param node {Node} - the node in question
  @param shadowId {String} - the ID of the shadow DOM to which this node belongs
  @return {Object} - the wrapped node