[
  {
    "path": ".babelrc",
    "content": "{\n  \"plugins\": [\n    \"transform-react-jsx\",\n    \"@babel/plugin-proposal-class-properties\",\n  ],\n  \"presets\": [\n      \"@babel/flow\",\n      \"@babel/preset-env\",\n      \"@babel/preset-react\"\n  ]\n}\n"
  },
  {
    "path": ".flowconfig",
    "content": "[ignore]\n\n[include]\n\n[libs]\n\n[lints]\n\n[options]\n\n[strict]\n"
  },
  {
    "path": ".gitignore",
    "content": "# dependencies\n/node_modules\nyarn.lock\n"
  },
  {
    "path": "README.md",
    "content": "## React fiber\nreact-fiber is my self-study project help me understand how react work. In fact, all \u001dcodebase re-implement each step , so it looks similar to the source code of react. Though, I think it's still smaller and easier to understand than when you actually read the react source code. I hope it helpful for people who want to start learn how react fiber work.\n\n## Something you should read and learn before start read source code\n\n#### Keyword, Algorithms and Data Structure Used\n- Single linked list, Circular linked list\n- Simple stack and queue\n- Recursive\n- Structural sharing\n- [Reconciliation](https://reactjs.org/docs/reconciliation.html)\n- Scheduler\n- Bitwise Operators\n- JSX\n- DOM\n###### And more\n- [React Components, Elements, and Instances](https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html)\n- [Design Principles](https://reactjs.org/docs/design-principles.html)\n- [React Fiber resources](https://github.com/koba04/react-fiber-resources)\n- [The how and why on React’s usage of linked list in Fiber to walk the component’s tree](https://medium.com/react-in-depth/the-how-and-why-on-reacts-usage-of-linked-list-in-fiber-67f1014d0eb7)\n- [In-depth explanation of state and props update in React\n](https://medium.com/react-in-depth/in-depth-explanation-of-state-and-props-update-in-react-51ab94563311)\n###### Recommend\n- [Lin Clark - A Cartoon Intro to Fiber - React Conf 2017\n](https://www.youtube.com/watch?v=ZCuYPiUIONs)\n- [A look inside React Fiber\n](https://makersden.io/blog/look-inside-fiber/)\n- [Build your own React Fiber](https://engineering.hexacta.com/didact-fiber-incremental-reconciliation-b2fe028dcaec)\n- [React Fiber Architecture @acdlite](https://github.com/acdlite/react-fiber-architecture) and [React Fiber Architecture @SaeedMalikx](https://github.com/SaeedMalikx/React-Fiber-Architecture)\n\n\n## Overview\n\n### Fiber tree\n![](https://cdn-images-1.medium.com/max/1600/1*cLqBZRht7RgR9enHet_0fQ.png)\n\n[Inside Fiber: in-depth overview of the new reconciliation algorithm in React](https://medium.com/react-in-depth/inside-fiber-in-depth-overview-of-the-new-reconciliation-algorithm-in-react-e1c04700ef6e)\n### Keyword\n  ```\n  work (unitOfWork): A component, node element => fiber\n\n  current: Current fiber what is displayed on browser\n\n  WIP (workInProgress): New fiber tree we will build\n\n  fiber: {\n    type: string | Function ('div', 'span', function Button)\n    instanceNode: HTMLElement (div, span)\n    return: fiber (parent of fiber)\n    child: fiber (child of fiber)\n    sibling: fiber (sibling of fiber)\n\n    alternate: link current - WIP and WIP - current\n    effectTag: number (give we know what will happen this fiber)\n\n  }\n\n  requestIdleCallback\n\n  main function:\n    createWorkInProgress()\n    beginWork()\n    reconcileChildren()\n    completeWork()\n    commitWork()\n  ```\n\n### Process of first render\n  ```\n  Render -> Reconciler -> Scheduler ->\n  Begin Work (build fiber tree) -> ChildReconciler(create child and effectTag) -> if work has child we will continue to run beginWork -> no child ->              \n  Complete Work (build list effect, mark tag and create instanceNode) -> sibling has child -> turn back Begin Work -> no child -> Complete Work -> no sibling -> has a new tree with effect tag ->\n  Commit Work : It will base on list effect tag to commit each fiber (Placement, Update, Delete, Lifecycle)\n\n  // In first render current fiber is null.\n  // current is workInProgress when commit\n  ```\n### Process when update\n  ```\n  Do something ->\n  Get current Fiber what corresponding to the component ->\n  Recursive to find Root ->\n  Clone fiber from root to component has update ->\n  Begin Work from this fiber (it's maybe clone fiber when children of component use memo, pure component or use shouldComponentUpdate) ->\n  Complete Work ->\n  Commit Work\n  ```\n\n### About With(Hook v16.7)\n  ```\n  Hooks are stored as a linked list on the fiber's prevState field of fiber.\n  current tree - current hook <=> WIP - WIP hook\n\n  ```\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\" dir=\"ltr\">\n  <head>\n    <meta charset=\"utf-8\">\n    <title></title>\n  </head>\n  <body>\n    <div id=\"root\">\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "index.js",
    "content": "/** @jsx h */\nimport { h } from './src/core/h';\nimport { withState } from './src/core/with-state';\nimport { lifeCycle } from './src/core/life-cycle';\nimport { render } from './src/dom';\n\nlet list = []\n\nfor (let i = 0; i < 5; i++) {\n  list = [\n    ...list,\n    {\n      name: 'tung',\n      age: 10,\n      id: i,\n    }\n  ]\n}\n\nconst User = ({ user, update, remove }) => {\n  lifeCycle({\n    mounted() {\n      console.log('mounted User')\n      return () => console.log('unmounted User')\n    }\n  })\n  return (\n    <div>\n      <p>Name: {user.name}</p>\n      <p>Age: {user.age}</p>\n      <button onClick={() => remove(user.id)}>Delete</button>\n      <button onClick={() => update(user.id)}>Update</button>\n    </div>\n  )\n}\n\nconst Test = ({ title }) => {\n  const [count, dispatch] = withState(1);\n  const [users, setUsers] = withState(list);\n\n  function add() {\n    const newUsers = [...users, { name: 'teng', age: 12, id: users.length }];\n    setUsers(newUsers);\n  }\n  function update(id) {\n    const newUsers = users.map(u => u.id === id ? {...u, name: 'aaaa', age: 15} : u);\n    setUsers(newUsers);\n  }\n  function remove(id) {\n    const newUsers = users.filter(u => u.id !== id);\n    setUsers(newUsers);\n  }\n  return (\n    <div>\n      <button onClick={add}>Add</button>\n      <p>{count}</p>\n      {users.map(user =>\n        <User\n          user={user}\n          update={update}\n          remove={remove}\n        />\n      )}\n    </div>\n  )\n\n}\n\nrender(<Test title='Hello'/>, document.getElementById('root'));\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-fiber-implement\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"start\": \"webpack-dev-server --content-base dist\",\n    \"build\": \"webpack\"\n  },\n  \"author\": \"tungtbt\",\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.1.5\",\n    \"@babel/core\": \"^7.1.6\",\n    \"@babel/plugin-proposal-class-properties\": \"^7.1.0\",\n    \"@babel/preset-env\": \"^7.1.6\",\n    \"@babel/preset-flow\": \"^7.0.0\",\n    \"@babel/preset-react\": \"^7.0.0\",\n    \"babel-loader\": \"^8.0.4\",\n    \"babel-plugin-transform-react-jsx\": \"^6.24.1\",\n    \"extract-text-webpack-plugin\": \"^3.0.2\",\n    \"flow-bin\": \"^0.86.0\",\n    \"html-webpack-plugin\": \"^3.2.0\",\n    \"replace-bundle-webpack-plugin\": \"^1.0.0\",\n    \"webpack\": \"^4.26.0\",\n    \"webpack-cli\": \"^3.1.2\",\n    \"webpack-dev-server\": \"^3.1.10\"\n  }\n}\n"
  },
  {
    "path": "src/core/h.js",
    "content": "// @flow\nimport { isNil, isFunction } from '../shared/validate';\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\n\n\nconst hasSymbol = typeof Symbol === 'function' && Symbol.for;\n\nexport const REACT_ELEMENT_TYPE = hasSymbol\n  ? Symbol.for('react.element')\n  : 0xeac7;\nexport const REACT_FRAGMENT_TYPE = hasSymbol\n  ? Symbol.for('react.fragment')\n  : 0xeacb;\n\nconst RESERVED_PROPS = {\n  key: true,\n  ref: true,\n};\n\nfunction hasValidKey(options) {\n  return options.key !== undefined;\n}\n\nfunction VNode(type, props, key) {\n  const vnode = {\n    $$typeof: REACT_ELEMENT_TYPE,\n\n    type: type,\n    props: props,\n    key: key,\n  }\n\n  return vnode;\n}\n\nexport function h(type, options, children) {\n  let propName;\n  const props = {};\n  let key = null;\n  if (!isNil(options)) {\n    if (hasValidKey(options)) {\n      key = '' + options.key;\n    }\n    for (propName in options) {\n      // Why use hasOwnProperty.call instead of someObj.hasOwnProperty?\n      // 1.hasOwnProperty is defined on the object as something else\n      // 2.The object in question is being used as a map and doesn't inherit from Object.prototype, so it doesn't have hasOwnProperty:\n      if (hasOwnProperty.call(options, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {\n        props[propName] = options[propName];\n      }\n    }\n  }\n  // Children can be more than one argument, and those are transferred onto\n  // the newly allocated props object.\n  // if createElement has 5 params number of children will be 3\n  const childrenLength = arguments.length - 2;\n  if (childrenLength === 1) {\n    props.children = children;\n  } else if (childrenLength > 1) {\n    // create Array empty has childrenLength element\n    const childArray = Array(childrenLength);\n    for (let i = 0; i < childrenLength; i++) {\n      // create array child\n      childArray[i] = arguments[i + 2];\n    }\n    props.children = childArray;\n  }\n\n  // Resolve default props\n  if (type && type.defaultProps) {\n    const defaultProps = type.defaultProps;\n    for (propName in defaultProps) {\n      if (props[propName] === undefined) {\n        props[propName] = defaultProps[propName];\n      }\n    }\n  }\n\n  return VNode(type, props, key);\n}\n"
  },
  {
    "path": "src/core/life-cycle.js",
    "content": "import { withLifeCycle } from '../fiber/f-with';\nimport {\n  Update as UpdateEffect,\n  Passive\n} from '../shared/effect-tag';\nimport {\n  NoEffect as NoHookEffect,\n  UnmountSnapshot,\n  UnmountMutation,\n  MountMutation,\n  MountLayout,\n  UnmountPassive,\n  MountPassive,\n} from '../shared/with-effect';\n\nexport const lifeCycle = ({mounted, destroyed, updated}) => {\n  return withLifeCycle(UpdateEffect | Passive, UnmountPassive | MountPassive, {mounted, destroyed, updated});\n}\n"
  },
  {
    "path": "src/core/with-state.js",
    "content": "import { withReducer } from '../fiber/f-with';\n\nexport function withState(initialState) {\n  return withReducer(initialState);\n}\n"
  },
  {
    "path": "src/dom/config.js",
    "content": "import createElement from './utils/createElement';\nimport { createTextNode, setTextContent, resetTextContent } from './utils/textElement';\nimport { appendChildToContainer, appendInitialChild, appendChild } from './utils/append';\nimport { removeChildFromContainer, removeChild } from './utils/remove';\nimport { insertInContainerBefore, insertBefore } from './utils/insert';\nimport { isDocumentNode } from './utils/validate';\n\nconst CHILDREN = 'children';\n\n// Assumes there is no parent namespace.\n\nconst randomKey = Math.floor((Math.random() * 100) + 1);\n\nconst internalInstanceKey = '__reactInternalInstance$' + randomKey;\nconst internalEventHandlersKey = '__reactEventHandlers$' + randomKey;\n\nexport function precacheFiberNode(hostInst, node) {\n  node[internalInstanceKey] = hostInst;\n}\nexport function getFiberCurrentPropsFromNode(node) {\n  return node[internalEventHandlersKey] || null;\n}\n\nexport function updateFiberProps(node, props) {\n  node[internalEventHandlersKey] = props;\n}\n\nexport function createDomNodeInstance(\n  type,\n  props,\n  rootContainerInstance,\n  hostContext,\n  internalInstanceHandle) {\n  let parentNamespace;\n  parentNamespace = hostContext;\n  const domElement = createElement(\n    type,\n    props,\n    rootContainerInstance,\n    parentNamespace,\n  );\n  precacheFiberNode(internalInstanceHandle, domElement);\n  updateFiberProps(domElement, props);\n  return domElement;\n}\n\nfunction ensureListeningTo(rootContainerElement, eventName, callback) {\n  const isDocumentOrFragment = isDocumentNode(rootContainerElement);\n  const dom = isDocumentOrFragment\n      ? rootContainerElement.ownerDocument\n      : rootContainerElement;\n  dom.addEventListener('click', callback, false);\n}\n\nfunction setInitialDOMProperties(\n  tag,\n  domElement,\n  rootContainerElement,\n  nextProps,\n  isCustomComponentTag\n) {\n  for (const propKey in nextProps) {\n    if (!nextProps.hasOwnProperty(propKey)) {\n      continue;\n    }\n    const nextProp = nextProps[propKey];\n    if (propKey === CHILDREN) {\n      if (typeof nextProp === 'string') {\n        // Avoid setting initial textContent when the text is empty. In IE11 setting\n        // textContent on a <textarea> will cause the placeholder to not\n        // show within the <textarea> until it has been focused and blurred again.\n        // https://github.com/facebook/react/issues/6731#issuecomment-254874553\n        const canSetTextContent = tag !== 'textarea' || nextProp !== '';\n        if (canSetTextContent) {\n          setTextContent(domElement, nextProp)\n        }\n      } else if (typeof nextProp === 'number') {\n        setTextContent(domElement, '' + nextProp)\n      }\n    } else if (propKey[0] === 'o' && propKey[1] === 'n') {\n      ensureListeningTo(domElement, propKey, nextProp)\n    }\n  }\n}\n\nexport function setInitialProperties(\n  domElement,\n  tag,\n  rawProps,\n  rootContainerElement,\n) {\n  let isCustomComponentTag = false;\n  let props;\n  switch (tag) {\n    case 'iframe':\n    default:\n      props = rawProps;\n  }\n\n  // assertValidProps(tag, props);\n  setInitialDOMProperties(\n    tag,\n    domElement,\n    rootContainerElement,\n    props,\n    isCustomComponentTag,\n  );\n}\n\n\nexport function finalizeInitialChildren(\n  domElement,\n  type,\n  props,\n  rootContainerInstance,\n  hostContext\n) {\n  setInitialProperties(domElement, type, props, rootContainerInstance)\n  return false\n}\n\nexport function createTextInstance(\n  text,\n  rootContainerInstance,\n  internalInstanceHandle\n) {\n  const textNode = createTextNode(text, rootContainerInstance);\n  precacheFiberNode(internalInstanceHandle, textNode);\n  return textNode;\n}\n\nfunction updateDOMProperties(\n  domElement,\n  updatePayload,\n  wasCustomComponentTag,\n  isCustomComponentTag\n) {\n  for (let i = 0; i < updatePayload.length; i++) {\n    const propKey = updatePayload[i];\n    const propValue = updatePayload[i + 1];\n    if (propKey === CHILDREN) {\n      setTextContent(domElement, propValue);\n    }\n  }\n}\n\n// Apply the diff\nexport function updateProperties(\n  domElement,\n  updatePayload,\n  tag,\n  lastRawProps,\n  nextRawProps,\n) {\n  const wasCustomComponentTag = false;\n  const isCustomComponentTag = false;\n  // Apply the diff.\n  updateDOMProperties(\n    domElement,\n    updatePayload,\n    wasCustomComponentTag,\n    isCustomComponentTag,\n  )\n}\n\nexport function commitUpdate(\n  domElement,\n  updatePayload,\n  type,\n  oldProps,\n  newProps,\n  internalInstanceHandle\n) {\n  // g('domElement', domElement)\n  // Update the props handle so that we know which props are the ones with\n  // with current event handlers.\n  updateFiberProps(domElement, newProps);\n  // Apple the diff to the DOM node\n  updateProperties(domElement, updatePayload, type, oldProps, newProps);\n\n}\n\nexport function commitTextUpdate(\n  textInstance,\n  oldText,\n  newText,\n) {\n  textInstance.nodeValue = newText;\n}\n\nexport function prepareUpdate(\n  domElement,\n  type,\n  oldProps,\n  newProps,\n  rootContainerInstance,\n) {\n  return diffProperties(\n    domElement,\n    type,\n    oldProps,\n    newProps,\n    rootContainerInstance,\n  )\n}\n\nfunction diffProperties(\n  domElement,\n  tag,\n  lastRawProps,\n  nextRawProps,\n  rootContainerElement\n) {\n  let updatePayload = null;\n  let lastProps = lastRawProps;\n  let nextProps = nextRawProps;\n\n  // it's like remove event listener because add event listener not orverride old function\n  if (typeof lastProps.onClick === 'function' && typeof nextProps.onClick === 'function') {\n    removeEvent(domElement, lastProps.onClick);\n  }\n\n  let propKey;\n\n  for (propKey in lastProps) {\n    if (\n      nextProps.hasOwnProperty(propKey) ||\n      !lastProps.hasOwnProperty(propKey) ||\n      lastProps[propKey] == null\n    ) {\n      continue;\n    }\n  }\n  for (propKey in nextProps) {\n    const nextProp = nextProps[propKey];\n    const lastProp = lastProps != null ? lastProps[propKey] : undefined;\n    if (\n      !nextProps.hasOwnProperty(propKey) ||\n      nextProp === lastProp ||\n      (nextProp == null && lastProp == null)\n    ) {\n      continue;\n    }\n\n    if (propKey === CHILDREN) {\n      if (lastProp !== nextProp && (typeof nextProp === 'string' || typeof nextProp === 'number')) {\n        (updatePayload = updatePayload || []).push(propKey, '' + nextProp);\n      }\n    } else if (propKey[0] === 'o' && propKey[1] === 'n') {\n      ensureListeningTo(domElement, propKey, nextProp)\n      if (!updatePayload && lastProp !== nextProp) {\n        // This is a special case. If any listener updates we need to ensure\n        // that the \"current\" props pointer gets updated so we need a commit\n        // to update this element.\n        updatePayload = [];\n      }\n    } else {\n      // For any other property we always add it to the queue and then we\n      // filter it out using the whitelist during the commit.\n      (updatePayload = updatePayload || []).push(propKey, nextProp);\n    }\n  }\n\n  return updatePayload;\n\n\n\n}\n\nfunction removeEvent(element, callback) {\n  element.removeEventListener('click', callback);\n}\n\nexport {\n  createTextNode,\n  setTextContent,\n  resetTextContent,\n\n  appendChildToContainer,\n  appendInitialChild,\n  appendChild,\n\n  removeChildFromContainer,\n  removeChild,\n\n  insertInContainerBefore,\n  insertBefore,\n}\n"
  },
  {
    "path": "src/dom/constants.js",
    "content": "const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\nconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n\nconst Namespaces = {\n  html: HTML_NAMESPACE,\n  svg: SVG_NAMESPACE,\n};\nexport const TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\nexport const DOCUMENT_NODE = 9;\n\nconst CHILDREN = 'children';\n"
  },
  {
    "path": "src/dom/index.js",
    "content": "import {\n  createContainer,\n  updateContainer\n} from '../fiber/reconciler';\n\nclass Root {\n  constructor(container) {\n    const root = createContainer(container);\n    this._root = root;\n  }\n\n  render(el) {\n    updateContainer(el, this._root);\n  }\n}\n\nexport function render(el, container) {\n  let root = container._rootContainer;\n  if (!root) {\n    root = container._rootContainer = new Root(container);\n    root.render(el);\n  }\n\n}\n"
  },
  {
    "path": "src/dom/utils/append.js",
    "content": "import { isCommentNode } from './validate';\n\nfunction appendInitialChild(parent, child) {\n  parent.appendChild(child);\n}\n\nfunction appendChild(parent, child) {\n  parent.appendChild(child);\n}\n\nfunction appendChildToContainer(\n  container,\n  child\n) {\n  let parentNode;\n  if (isCommentNode(container)) {\n    parentNode = container.parentNode;\n    parentNode.insertBefore(child, container)\n  } else {\n    parentNode = container;\n    parentNode.appendChild(child);\n  }\n}\n\nexport {\n  appendChildToContainer,\n  appendInitialChild,\n  appendChild,\n}\n"
  },
  {
    "path": "src/dom/utils/createElement.js",
    "content": "import getDocumentByElement from './getDocumentByElement';\n\n/**\n* @param {string} type\n* @param {object} props\n* @param {HTMLElement} rootContainerElement\n* @param {string} parentNamespace\n* @return {HTMLElement}\n*/\nfunction createElement(type, props, rootContainerElement, parentNamespace) {\n  const ownerDocument = getDocumentByElement(rootContainerElement);\n  let element;\n  if (typeof props.is === 'string') {\n    element = ownerDocument.createElement(type, {is: props.is});\n  } else {\n    element = ownerDocument.createElement(type);\n    if (type === 'select' && props.multiple) {\n      const node = element;\n      node.multiple = true;\n    }\n  }\n  return element;\n\n}\n\nexport default createElement;\n"
  },
  {
    "path": "src/dom/utils/getDocumentByElement.js",
    "content": "import { isDocumentNode } from './validate';\n\n/**\n* @param {HTMLElement} element\n* @return {Document}\n*/\nfunction getDocumentByElement(element) {\n  return isDocumentNode(element) ? element : element.ownerDocument;\n}\n\nexport default getDocumentByElement;\n"
  },
  {
    "path": "src/dom/utils/insert.js",
    "content": "import { isCommentNode } from './validate';\n\nfunction insertBefore(parent, child, beforeChild) {\n  parent.insertBefore(child, beforeChild);\n}\n\nfunction insertInContainerBefore(container, child, beforeChild) {\n  if (isCommentNode(container)) {\n    container.parentNode.insertBefore(child, beforeChild);\n  } else {\n    container.insertBefore(child, beforeChild);\n  }\n}\n\nexport {\n  insertInContainerBefore,\n  insertBefore\n}\n"
  },
  {
    "path": "src/dom/utils/remove.js",
    "content": "import { isCommentNode } from './validate';\n\nexport function removeChildFromContainer(container, child) {\n  \n  if (isCommentNode(container)) {\n    container.parentNode.removeChild(child);\n  } else {\n    container.removeChild(child);\n  }\n}\n\nexport function removeChild(parentInstance, child) {\n  parentInstance.removeChild(child);\n}\n"
  },
  {
    "path": "src/dom/utils/textElement.js",
    "content": "import getDocumentByElement from './getDocumentByElement';\nimport { isTextNode } from './validate';\n\nfunction resetTextContent(element) {\n  setTextContent(element, '');\n}\n\nfunction setTextContent(node, text) {\n  if (text) {\n    let firstChild = node.firstChild;\n\n    if (\n      firstChild &&\n      firstChild === node.lastChild &&\n      isTextNode(firstChild)\n    ) {\n      firstChild.nodeValue = text;\n      return;\n    }\n  }\n  node.textContent = text;\n}\n\nfunction createTextNode(text, element) {\n  const value = typeof text === 'object' ? JSON.stringify(text) : text;\n  return getDocumentByElement(element).createTextNode(value);\n}\n\nexport {\n  createTextNode,\n  setTextContent,\n  resetTextContent,\n}\n"
  },
  {
    "path": "src/dom/utils/validate.js",
    "content": "import { DOCUMENT_NODE, TEXT_NODE, COMMENT_NODE } from '../constants';\n\nfunction isDocumentNode(el) {\n  return el.nodeType === DOCUMENT_NODE;\n}\n\nfunction isTextNode(el) {\n  return el.nodeType === TEXT_NODE;\n}\n\nfunction isCommentNode(el) {\n  return el.nodeType === COMMENT_NODE;\n}\n\nexport {\n  isDocumentNode,\n  isTextNode,\n  isCommentNode,\n};\n"
  },
  {
    "path": "src/fiber/begin-work.js",
    "content": "import type {FNode} from 'f-node';\n\nimport {Root, DNode, FComponent, Text, Fragment} from '../shared/tag';\nimport { isObject } from '../shared/validate';\nimport {PerformedWork} from '../shared/effect-tag';\nimport {reconcileChildren, cloneChildFNodes} from './children';\nimport {pushHostContainer} from './host-context';\nimport {prepareWithState, finishedWith} from './f-with';\nimport {updateRootRender} from './root-render';\nimport * as Status from '../shared/status-work';\nimport shallowEqual from '../shared/shallowEqual';\n\n// test\n\nexport function saveProps(WIP: FNode, props: any): void {\n  WIP.prevProps = props;\n}\n\nexport function saveState(WIP: FNode, state: any): void {\n  WIP.prevState = state;\n}\n\nfunction shouldSetTextContent(type, props) {\n  return type === 'textarea' ||\n    typeof props.children === 'string' ||\n    typeof props.children === 'number' ||\n    typeof props.dangerouslySetInnerHTML === 'object'\n      && props.dangerouslySetInnerHTML !== null\n      && typeof props.dangerouslySetInnerHTML.__html === 'string';\n}\n\nfunction pushHostRootContext(WIP: FNode): void {\n  const root = WIP.instanceNode;\n  pushHostContainer(WIP, root.containerInfo);\n}\n\nfunction updateRoot(current: FNode | null, WIP: FNode): FNode | null {\n  pushHostRootContext(WIP);\n\n  const rootRender = WIP.rootRender;\n  const nextProps = WIP.props;\n  const prevState = WIP.prevState;\n  const prevChild = prevState !== null\n    ? prevState.element\n    : null;\n  // processUpdateQueue(WIP, updateQueue, nextProps, null);\n  updateRootRender(WIP, rootRender, nextProps, null)\n  const nextState = WIP.prevState;\n  const nextChildren = nextState.element;\n\n  reconcileChildren(current, WIP, nextChildren);\n  return WIP.child;\n}\n\nfunction updateDomNode(current: FNode | null, WIP: FNode): FNode | null {\n\n  const type = WIP.type;\n  const nextProps = WIP.props;\n  const prevProps = current !== null\n    ? current.prevProps\n    : null;\n  let nextChildren = nextProps.children;\n  reconcileChildren(current, WIP, nextChildren);\n  saveProps(WIP, nextProps);\n  return WIP.child;\n}\n\nfunction updateFunctionComponent(current: FNode | null, WIP: FNode, status): FNode | null {\n  const Component = WIP.type;\n  const unresolvedProps = WIP.props;\n  const nextProps = resolveDefaultProps(Component, unresolvedProps);\n  if (current !== null && status === Status.NoWork) {\n    const prevProps = current.prevProps;\n    if (shallowEqual(prevProps, nextProps) && current.ref === WIP.ref) {\n      cloneChildFNodes(current, WIP);\n      return WIP.child;\n    }\n  }\n\n  let nextChildren;\n  prepareWithState(current, WIP);\n\n  nextChildren = Component(nextProps);\n\n  nextChildren = finishedWith(Component, nextProps, nextChildren);\n  WIP.effectTag |= PerformedWork;\n  reconcileChildren(current, WIP, nextChildren);\n  return WIP.child;\n}\n\nfunction updateTextNode(current, WIP) {\n  const nextProps = WIP.props;\n  saveProps(WIP, nextProps);\n  return null;\n}\n\nfunction updateFragment(current, WIP) {\n  const nextChildren = WIP.props;\n  reconcileChildren(current, WIP, nextChildren);\n  return WIP.child;\n}\n\nfunction resolveDefaultProps(Component: Function, baseProps: any) {\n  if (Component && Component.defaultProps) {\n    // Resolve default props. Taken from ReactElement\n    const props = Object.assign({}, baseProps);\n    const defaultProps = Component.defaultProps;\n    for (let propName in defaultProps) {\n      if (props[propName] === undefined) {\n        props[propName] = defaultProps[propName];\n      }\n    }\n    return props;\n  }\n  return baseProps;\n}\n\n/**\n* @param {FNode} current\n* @param {FNode} WIP\n* @return {FNode | null}\n*/\n\nexport function beginWork(current: FNode | null, WIP: FNode): FNode | null {\n  const status = WIP.status;\n  if (current !== null) {\n    const oldProps = current.prevProps;\n    const newProps = WIP.props;\n    if (oldProps === newProps && WIP.status === Status.NoWork) {\n      // we just push root to stack\n      if (WIP.tag === Root) {\n        pushHostRootContext(WIP);\n      }\n      // clone this fiber and return child\n      cloneChildFNodes(current, WIP);\n      return WIP.child;\n    }\n  }\n  // reset WIP\n  WIP.status = Status.NoWork;\n\n  if (WIP.tag === Root) {\n    return updateRoot(current, WIP);\n  } else if (WIP.tag === DNode) {\n    return updateDomNode(current, WIP);\n  } else if (WIP.tag === FComponent) {\n    return updateFunctionComponent(current, WIP, status)\n  } else if (WIP.tag === Text) {\n    return updateTextNode(current, WIP);\n  } else if (WIP.tag === Fragment) {\n    return updateFragment(current, WIP);\n  } else\n    return null;\n}\n"
  },
  {
    "path": "src/fiber/children.js",
    "content": "import type { Fiber } from './Fiber';\nimport { REACT_ELEMENT_TYPE } from '../core/h';\nimport {\n  createWIP,\n  createFNodeFromElement,\n  createFNodeFromFragment,\n  createFNode,\n} from './f-node';\nimport {\n  Root,\n  DNode,\n  FComponent,\n  Text,\n  Fragment,\n} from '../shared/Tag';\nimport { isArray } from '../shared/validate';\nimport { NoEffect, Placement, Deletion } from '../shared/effect-tag';\n\nfunction ChildReconciler(shouldTrackSideEffects) {\n  function deleteChild(returnFNode, childToDelete) {\n    if (!shouldTrackSideEffects) {\n      return;\n    }\n\n    const last = returnFNode.linkedList.last;\n    if (last !== null) {\n      last.next = childToDelete;\n      returnFNode.linkedList.last = childToDelete;\n    } else {\n      returnFNode.linkedList.first = returnFNode.linkedList.last = childToDelete;\n    }\n    childToDelete.next = null;\n    childToDelete.effectTag = Deletion;\n  }\n  function deleteRemainingChildren(returnFNode, currentFirstChild) {\n    if (!shouldTrackSideEffects) {\n      return null;\n    }\n\n    let childToDelete = currentFirstChild;\n    while (childToDelete !== null) {\n      deleteChild(returnFNode, childToDelete);\n      childToDelete = childToDelete.sibling;\n    }\n    return null;\n  }\n  function placeChild(newFNode, lastPlacedIndex, newIndex) {\n    newFNode.index = newIndex;\n    if (!shouldTrackSideEffects) {\n      // Noop.\n      return lastPlacedIndex;\n    }\n\n    const current = newFNode.alternate;\n    if (current !== null) {\n      const oldIndex = current.index;\n      if (oldIndex < lastPlacedIndex) {\n        // this is a move\n        newFNode.effectTag = Placement;\n        return lastPlacedIndex;\n      } else {\n        // this item can stay in place\n        return oldIndex;\n      }\n    } else {\n      // this is an insertion.\n      newFNode.effectTag = Placement;\n      return lastPlacedIndex;\n    }\n  }\n\n  function placeSingleChild(newFNode) {\n    // This is simpler for the single child case. We only need to do a\n    // placement for inserting new children.\n    if (shouldTrackSideEffects && newFNode.alternate === null) {\n      newFNode.effectTag = Placement;\n    }\n    return newFNode;\n  }\n\n  function useFNode(fiber, props) {\n    let clone = createWIP(fiber, props);\n    clone.index = 0;\n    clone.sibling = null;\n    return clone;\n  }\n\n  function createFNodeFromText(content) {\n    let fiber = createFNode(Text, content, null)\n    return fiber;\n  }\n\n\n  function createChild(\n    returnFNode,\n    newChild,\n  ) {\n      if (typeof newChild === 'string' || typeof newChild === 'number') {\n        // Text nodes don't have keys. If the previous node is implicitly keyed\n        // we can continue to replace it without aborting even if it is not a text\n        // node.\n        const created = createFNodeFromText(\n          '' + newChild,\n        );\n        created.return = returnFNode;\n        return created;\n      }\n\n      if (typeof newChild === 'object' && newChild !== null) {\n        if (newChild.$$typeof) {\n          const created = createFNodeFromElement(newChild);\n          created.return = returnFNode;\n          return created;\n        }\n      }\n\n      if (isArray(newChild)) {\n        const created = createFNodeFromFragment(\n          newChild,\n          null,\n        );\n        created.return = returnFNode;\n        return created;\n      }\n      return null;\n  }\n\n  function updateTextNode(returnFNode, current, textContent) {\n    if (current !== null && current.tag !== Text) {\n      // Insert\n      const created = createFNodeFromText(textContent);\n      created.return = returnFNode;\n      return created\n    } else {\n      // Update\n      const existing = useFNode(current, textContent);\n      existing.return = returnFNode;\n      return existing;\n    }\n  }\n\n  function updateElement(\n    returnFNode,\n    current,\n    element\n  ) {\n    if (current !== null && current.elementType === element.type) {\n      // Move based on index\n      const existing = useFNode(current, element.props);\n      existing.return = returnFNode;\n      return existing;\n    } else {\n      // Insert\n      const created = createFNodeFromElement(\n        element,\n      );\n      created.return = returnFNode;\n      return created;\n    }\n  }\n\n  function updateFragment(returnFNode, current, fragment) {\n    if (current === null || current.tag !== Fragment) {\n      // insert\n      const created = createFNodeFromFragment(fragment, null);\n      created.return = returnFNode;\n      return created;\n    } else {\n      // Update\n      const existing = useFNode(current, fragment);\n      existing.return = returnFNode;\n      return existing;\n    }\n  }\n\n  function updateSlot(returnFNode, oldFiber, newChild) {\n    const key = oldFiber !== null ? oldFiber.key : null;\n    if (typeof newChild === 'string' || typeof newChild === 'number') {\n      // Text nodes don't have keys. If the previous node is implicitly keyed\n      // we can continue to replace it without aborting even if it is not a text\n      // node.\n      if (key !== null) {\n        return null;\n      }\n      return updateTextNode(\n        returnFNode,\n        oldFiber,\n        '' + newChild,\n      );\n    }\n    if (typeof newChild === 'object' && newChild !== null) {\n      switch (newChild.$$typeof) {\n        case REACT_ELEMENT_TYPE: {\n          if (newChild.key === key) {\n            return updateElement(returnFNode, oldFiber, newChild);\n          } else {\n            return null;\n          }\n        }\n\n      }\n      if (isArray(newChild)) {\n        if (key !== null) {\n            return null;\n        }\n        return updateFragment(returnFNode, oldFiber, newChild);\n      }\n    }\n    return null;\n  }\n\n  function mapRemainingChildren(returnFNode, currentFirstChild) {\n    // Add the remaining children to a temporary map so that we can find them by\n    // keys quickly. Implicit (null) keys get added to this set with their index\n    // instead.\n    const existingChildren: Map<string | number, Fiber> = new Map();\n    let existingChild = currentFirstChild;\n    while (existingChild !== null) {\n          if (existingChild.key !== null) {\n            existingChildren.set(existingChild.key, existingChild);\n          } else {\n            existingChildren.set(existingChild.index, existingChild);\n          }\n          existingChild = existingChild.sibling;\n        }\n    return existingChildren;\n\n  }\n\n  function reconcileChildrenArray(returnFNode, currentFirstChild, newChildren) {\n      let resultingFirstChild = null;\n      let previousnewFNode = null;\n\n      let oldFiber = currentFirstChild; // null\n      let lastPlacedIndex = 0;\n      let newIdx = 0;\n      let nextOldFiber = null;\n\n      for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {\n        if (oldFiber.index > newIdx) {\n          nextOldFiber = oldFiber;\n          oldFiber = null;\n        } else {\n          nextOldFiber = oldFiber.sibling;\n        }\n        const newFNode = updateSlot(returnFNode, oldFiber, newChildren[newIdx]);\n        if (newFNode === null) {\n          // TODO: This breaks on empty slots like null children. That's\n          // unfortunate because it triggers the slow path all the time. We need\n          // a better way to communicate whether this was a miss or null,\n          // boolean, undefined, etc.\n          if (oldFiber === null) {\n            oldFiber = nextOldFiber;\n          }\n          break;\n        }\n        lastPlacedIndex = placeChild(newFNode, lastPlacedIndex, newIdx);\n\n        if (previousnewFNode === null) {\n          resultingFirstChild = newFNode;\n        } else {\n          previousnewFNode.sibling = newFNode;\n        }\n        previousnewFNode = newFNode;\n        oldFiber = nextOldFiber;\n      }\n\n      if (newIdx === newChildren.length) {\n        // We've reached the end of the new children. We can delete the rest.\n        deleteRemainingChildren(returnFNode, oldFiber);\n        return resultingFirstChild;\n      }\n\n      if (oldFiber === null) {\n        // If we don't have any more existing children we can choose a fast path\n        // since the rest will all be insertions.\n        for (; newIdx < newChildren.length; newIdx++) {\n          const newFNode = createChild(\n            returnFNode,\n            newChildren[newIdx],\n          );\n          // if newFNode === null continue\n          if (!newFNode) {\n            continue;\n          }\n          lastPlacedIndex = placeChild(newFNode, lastPlacedIndex, newIdx);\n          // we will set relation ship here\n          if (previousnewFNode === null) {\n            // TODO: Move out of the loop. This only happens for the first run.\n            resultingFirstChild = newFNode;\n          } else {\n            previousnewFNode.sibling = newFNode;\n          }\n          previousnewFNode = newFNode\n        }\n        return resultingFirstChild;\n      }\n      // Add all children to a key map for quick lookups.\n      const existingChildren = mapRemainingChildren(returnFNode, oldFiber);\n\n      // Keep scanning and use the map to restore deleted items as moves.\n      return resultingFirstChild;\n\n  }\n\n  function reconcileSingleTextNode(returnFNode, currentFirstChild, textContent) {\n    // There's no need to check for keys on text nodes since we don't have a\n    // way to define them.\n    if (currentFirstChild !== null && currentFirstChild.tag === Text) {\n      // We already have an existing node so let's just update it and delete\n      // the rest.\n      deleteRemainingChildren(returnFNode, currentFirstChild.sibling);\n      var existing = useFNode(currentFirstChild, textContent);\n      existing.return = returnFNode;\n      return existing;\n    }\n    // The existing first child is not a text node so we need to create one\n    // and delete the existing ones.\n    deleteRemainingChildren(returnFNode, currentFirstChild);\n    let created = createFNodeFromText(textContent);\n    created.return = returnFNode;\n    return created;\n  }\n\n  function reconcileSingleElement(returnFNode, currentFirstChild, el) {\n    let key = el.key;\n    let child = currentFirstChild;\n    while (child !== null) {\n      if (child.key === key) {\n        if (child.type === el.type) {\n          // if we had a child we use exactly it\n          deleteRemainingChildren(returnFNode, child.sibling);\n          let existing = useFNode(child, el.props);\n          existing.return = returnFNode;\n          return existing\n        } else {\n          deleteRemainingChildren(returnFNode, child);\n          break;\n        }\n      }\n      child = child.sibling;\n    }\n    // create a fiber from this child and set the parent\n    const created = createFNodeFromElement(el);\n    // created.ref = coerceRef(returnFNode, currentFirstChild, element);\n    created.return = returnFNode;\n    return created;\n  }\n\n  function reconcileChilds(returnFNode, currentFirstChild, newChild) {\n    const isObject = typeof newChild === 'object' && newChild !== null;\n\n    if (isObject) {\n      if (newChild.$$typeof) {\n        // after find a child we will set effectTag is Placement ... it's mean we will create it\n        return placeSingleChild(reconcileSingleElement(returnFNode, currentFirstChild, newChild));\n      }\n    }\n    if (typeof newChild === 'string' || typeof newChild === 'number') {\n      // after find a child we will set effectTag is Placement ... it's mean we will create it\n      return placeSingleChild(reconcileSingleTextNode(returnFNode, currentFirstChild, '' + newChild));\n    }\n    if (isArray(newChild)) {\n        return reconcileChildrenArray(returnFNode, currentFirstChild, newChild);\n    }\n    return deleteRemainingChildren(returnFNode, currentFirstChild);\n  }\n\n  return reconcileChilds;\n}\n\n\n\nexport const reconcileChilds = ChildReconciler(true);\nexport const mountChilds = ChildReconciler(false);\n\nexport function cloneChildFNodes(\n  current,\n  WIP\n) {\n  if (WIP.child === null) {\n    return;\n  }\n  let currentChild = WIP.child;\n  let newChild = createWIP(currentChild, currentChild.props);\n  WIP.child = newChild;\n\n  newChild.return = WIP;\n  while (currentChild.sibling !== null) {\n    currentChild = currentChild.sibling;\n    newChild = newChild.sibling = createWIP(\n      currentChild,\n      currentChild.props\n    );\n    newChild.return = WIP;\n  }\n  newChild.sibling = null;\n}\n\nexport function reconcileChildren(current, WIP, nextChild) {\n  if (current === null) {\n    WIP.child = mountChilds(WIP, null, nextChild);\n  } else {\n    WIP.child = reconcileChilds(WIP, current.child, nextChild);\n  }\n}\n"
  },
  {
    "path": "src/fiber/commit-work.js",
    "content": "import {\n  resetTextContent,\n  appendChild,\n  appendChildToContainer,\n  insertInContainerBefore,\n  insertBefore,\n  commitUpdate,\n  commitTextUpdate,\n  removeChildFromContainer,\n  removeChild,\n} from '../dom/config';\nimport {\n  Root,\n  DNode,\n  Text,\n  FComponent\n} from '../shared/tag';\nimport {\n  ContentReset,\n  Placement\n} from '../shared/effect-tag';\n\nfunction isHostParent(fiber) {\n  return (\n    fiber.tag === DNode ||\n    fiber.tag === Root\n  );\n}\n\nfunction getHostparentFNode(fiber) {\n  let parent = fiber.return;\n  while (parent !== null) {\n    if (isHostParent(parent)) {\n      return parent;\n    }\n    parent = parent.return;\n  }\n}\n\nfunction getHostSibling(fiber) {\n  // We're going to search forward into the tree until we find a sibling host\n  // node. Unfortunately, if multiple insertions are done in a row we have to\n  // search past them. This leads to exponential search for the next sibling.\n  // TODO: Find a more efficient way to do this.\n  let node = fiber;\n  siblings: while (true) {\n    // If we didn't find anything, let's try the next sibling.\n    while (node.sibling === null) {\n      if (node.return === null || isHostParent(node.return)) {\n        return null;\n      }\n      node = node.return;\n    }\n    node.sibling.return = node.return;\n    node = node.sibling;\n    while (node.tag !== DNode && node.tag !== Text) {\n      // If it is not host node and, we might have a host node inside it.\n      // Try to search down until we find one.\n      if (node.effectTag & Placement) {\n        // If we don't have a child, try the siblings instead.\n        continue siblings;\n      }\n      // If we don't have a child, try the siblings instead.\n      // We also skip portals because they are not part of this host tree.\n      if (node.child === null || node.tag === HostPortal) {\n        continue siblings;\n      } else {\n        node.child.return = node;\n        node = node.child;\n      }\n    }\n    // Check if this host node is stable or about to be placed.\n    if (!(node.effectTag & Placement)) {\n      // Found it!\n      return node.instanceNode;\n    }\n  }\n}\n\nexport function commitPlacement(finishedWork) {\n  // Recursively insert all host nodes into the parent.\n  const parentFNode = getHostparentFNode(finishedWork);\n\n  // Note: these two variables *must* always be updated together.\n  let parent;\n  let isContainer;\n\n  switch (parentFNode.tag) {\n    case DNode:\n      parent = parentFNode.instanceNode;\n      isContainer = false;\n      break;\n    case Root:\n      parent = parentFNode.instanceNode.containerInfo;\n      isContainer = true;\n      break;\n    default:\n      console.log('Invalid host parent')\n\n  }\n  if (parentFNode.effectTag & ContentReset) {\n    // Reset the text content of the parent before doing any insertions\n    resetTextContent(parent);\n    // Clear ContentReset from the effect tag\n    parentFNode.effectTag &= ~ContentReset;\n  }\n\n  const before = getHostSibling(finishedWork);\n  let node = finishedWork;\n  while (true) {\n    if (node.tag === DNode || node.tag === Text) {\n      if (before) {\n        if (isContainer) {\n          insertInContainerBefore(parent, node.instanceNode, before)\n        } else {\n          insertBefore(parent, node.instanceNode, before);\n        }\n      } else {\n        if (isContainer) {\n          appendChildToContainer(parent, node.instanceNode);\n        } else {\n          appendChild(parent, node.instanceNode);\n        }\n      }\n    } else if (node.child !== null) {\n      node.child.return = node;\n      node = node.child;\n      continue;\n    }\n    if (node === finishedWork) {\n      return;\n    }\n    while (node.sibling === null) {\n      if (node.return === null || node.return === finishedWork) {\n        return;\n      }\n      node = node.return;\n    }\n    node.sibling.return = node.return;\n    node = node.sibling\n  }\n}\n\nfunction safelyDetachRef(current) {\n  const ref = current.ref;\n  if (ref.current !== null) {\n\n  } else {\n    ref.current = null;\n  }\n\n}\n\n// User-originating errors (lifecycles and refs) should not interrupt\n// deletion, so don't let them throw. Host-originating errors should\n// interrupt deletion, so it's okay\nfunction commitUnmount(current) {\n  switch (current.tag) {\n    case FComponent: {\n      const lifeCycle = current.lifeCycle;\n      if (lifeCycle !== null) {\n        const lastEffect = lifeCycle.lastEffect;\n        if (lastEffect !== null) {\n          const firstEffect = lastEffect.next;\n          let effect= firstEffect;\n          do {\n            const destroyed = effect.destroyed;\n            if (!!destroyed && destroyed !== null) {\n              destroyed();\n            }\n            effect = effect.next;\n          } while (effect !== firstEffect);\n        }\n      }\n    }\n    case DNode: {\n      // safelyDetachRef(current);\n      return;\n    }\n  }\n}\n\n\nfunction commitNestedUnmounts(root) {\n  // While we're inside a removed host node we don't want to call\n  // removeChild on the inner nodes because they're removed by the top\n  // call anyway. We also want to call componentWillUnmount on all\n  // composites before this host node is removed from the tree. Therefore\n  // we do an inner loop while we're still inside the host node.\n  let node = root;\n  while (true) {\n    commitUnmount(node);\n    // Visit children because they may contain more composite or host nodes.\n    // Skip portals because commitUnmount() currently visits them recursively.\n    if (node.child !== null) {\n      node.child.return = node;\n      node = node.child;\n      continue;\n    }\n    if (node === root) {\n      return;\n    }\n    while (node.sibling === null) {\n      if (node.return === null || node.return === root) {\n        return;\n      }\n      node = node.return;\n    }\n    node.sibling.return = node.return;\n    node = node.sibling;\n  }\n}\n\nfunction unmountHostComponents(current) {\n  // We only have the top Fiber that was deleted but we need recurse down its\n  // children to find all the terminal nodes.\n  let node = current;\n\n  // Each iteration, currentParent is populated with node's host parent if not\n  // currentParentIsValid.\n  let currentParentIsValid = false;\n  // Note: these two variables *must* always be updated together.\n  let currentParent;\n  let currentParentIsContainer;\n\n  while (true) {\n    if (!currentParentIsValid) {\n      let parent = node.return;\n      findParent: while (true) {\n        switch (parent.tag) {\n          case DNode:\n            currentParent = parent.instanceNode;\n            currentParentIsContainer = false;\n            break findParent;\n          case Root:\n            currentParent = parent.instanceNode.containerInfo;\n            currentParentIsContainer = true;\n            break findParent;\n        }\n        parent = parent.return;\n      }\n      currentParentIsValid = true;\n    }\n\n    if (node.tag === DNode || node.tag === Text) {\n      commitNestedUnmounts(node);\n      // After all the children have unmounted, it is now safe to remove the\n      // node from the tree.\n      if (currentParentIsContainer) {\n        removeChildFromContainer(currentParent, node.instanceNode);\n      } else {\n        removeChild(currentParent, node.instanceNode);\n      }\n    } else {\n      commitUnmount(node);\n      // Visit children because we may find more host components below.\n      if (node.child !== null) {\n        node.child.return = node;\n        node = node.child;\n        continue;\n      }\n    }\n\n    if (node === current) {\n      return;\n    }\n\n    while (node.sibling === null) {\n      if (node.return === null || node.return === current) {\n        return;\n      }\n      node = node.return;\n    }\n    node.sibling.return = node.return;\n    node = node.sibling;\n  }\n\n}\n\nfunction detachFiber(current) {\n  // Cut off the return pointers to disconnect it from the tree. Ideally, we\n  // should clear the child pointer of the parent alternate to let this\n  // get GC:ed but we don't know which for sure which parent is the current\n  // one so we'll settle for GC:ing the subtree of this child. This child\n  // itself will be GC:ed when the parent updates the next time.\n  current.return = null;\n  current.child = null;\n  if (current.alternate) {\n    current.alternate.child = null;\n    current.alternate.return = null;\n  }\n}\n\nexport function commitDeletion(current) {\n  unmountHostComponents(current);\n  detachFiber(current);\n}\n\n\nexport function commitWork(\n  current,\n  finishedWork,\n) {\n  switch (finishedWork.tag) {\n    case FComponent:{\n      return;\n    }\n    case DNode: {\n      const instance = finishedWork.instanceNode;\n      if (instance !== null) {\n        // Commit the work prepared earlier.\n        const newProps = finishedWork.prevProps;\n        // For hydration we reuse the update path but we treat the oldProps\n        // as the newProps. The updatePayload will contain the real change in\n        // this case.\n        const oldProps = current !== null ? current.prevProps : newProps;\n        const type = finishedWork.type;\n        // TODO: Type the updateQueue to be specific to host components.\n        const updatePayload = finishedWork.updateQueue;\n        finishedWork.updateQueue = null;\n        if (updatePayload !== null) {\n          commitUpdate(\n            instance,\n            updatePayload,\n            type,\n            oldProps,\n            newProps,\n            finishedWork,\n          );\n        }\n      }\n      return;\n    }\n    case Text: {\n      const textInstance = finishedWork.instanceNode;\n      const newText = finishedWork.prevProps;\n      const oldText = current !== null ? current.prevProps : newText;\n      commitTextUpdate(textInstance, oldText, newText);\n      return;\n    }\n    case Root: {\n      return;\n    }\n    default:\n      console.error('Errrrorrrrr!!!')\n  }\n}\n\nexport function commitPassiveWithEffects(finishedWork) {\n  commitWithEffectList(128, 0, finishedWork);\n  commitWithEffectList(0, 64, finishedWork);\n}\n\nexport function commitWithEffectList(unmountTag, mountTag, finishedWork) {\n  const lifeCycle = finishedWork.lifeCycle;\n  let lastEffect = lifeCycle !== null ? lifeCycle.lastEffect : null;\n  if (lastEffect !== null) {\n    let firstEffect = lastEffect.next;\n    let effect = firstEffect;\n    do {\n      if ((effect.tag & unmountTag) !== 0) {\n        let destroyed = effect.destroyed;\n        effect.destroyed = null;\n        if (destroyed !== null && typeof destroyed === 'function') {\n          destroyed();\n        }\n      }\n      if ((effect.tag & mountTag) !== 0) {\n        const mounted = effect.mounted;\n        let destroyed = mounted();\n        if (typeof destroyed !== 'function') {\n          destroyed = null;\n        }\n        effect.destroyed = destroyed;\n      }\n      effect = effect.next;\n    } while (effect !== firstEffect);\n  }\n\n}\n"
  },
  {
    "path": "src/fiber/complete-work.js",
    "content": "// Then it build a list of effects.\n// This list will contain all the fibers from the work-in-progress sub-tree\n// that have any effectTag\n// (it also contains the fibers from the old sub-tree with the DELETION effectTag).\nimport {\n  Root,\n  DNode,\n  Text,\n  FComponent,\n  Fragment\n} from '../shared/tag';\nimport { Placement, Update } from '../shared/effect-tag';\n\nimport {\n  getRootHostContainer,\n  popHostContainer\n} from './host-context'\n\nimport {\n  createTextInstance,\n  createDomNodeInstance,\n  appendInitialChild,\n  finalizeInitialChildren,\n  prepareUpdate,\n} from '../dom/config';\n\n\nfunction markUpdate(WIP) {\n  // Tag the fiber with an update effect. This turns a Placement into\n  // a PlacementAndUpdate.\n  WIP.effectTag |= Update;\n}\n\nexport function updateHostContainer(WIP) {\n}\n\nexport function updateHostComponent(\n  current,\n  WIP,\n  type,\n  newProps,\n  rootContainerInstance\n) {\n  // If we have an alternate, that means this is an update and we need to\n  // schedule a side-effect to do the updates.\n  const oldProps = current.prevProps;\n  if (oldProps === newProps) {\n    // In mutation mode, this is sufficient for a bailout because\n    // we won't touch this node even if children changed.\n    return;\n  }\n\n    // If we get updated because one of our children updated, we don't\n    // have newProps so we'll have to reuse them.\n    // TODO: Split the update API as separate for the props vs. children.\n    // Even better would be if children weren't special cased at all tho.\n    const instance = WIP.instanceNode;\n    // TODO: Experiencing an error where oldProps is null. Suggests a host\n    // component is hitting the resume path. Figure out why. Possibly\n    // related to `hidden`.\n    const updatePayload = prepareUpdate(\n      instance,\n      type,\n      oldProps,\n      newProps,\n      rootContainerInstance,\n    );\n\n    // // TODO: Type this specific to this type of component.\n    WIP.updateQueue = WIP;\n    // If the update payload indicates that there is a change or if there\n    // is a new ref we mark this as an update. All the work is done in commitWork.\n    if (updatePayload) {\n      markUpdate(WIP);\n    }\n\n}\n\nexport function updateHostText(\n  current,\n  WIP,\n  oldText,\n  newText\n) {\n  if (oldText !== newText) {\n      markUpdate(WIP);\n  }\n}\n\nfunction appendAllChildren(\n  parent,\n  WIP\n) {\n  let node = WIP.child;\n  while (node !== null) {\n    if (node.tag === DNode || node.tag === Text) {\n      appendInitialChild(parent, node.instanceNode);\n    } else if (node.child !== null) {\n      node.child.return = node;\n      node = node.child;\n      continue;\n    }\n    if (node === WIP) {\n      return;\n    }\n    while (node.sibling === null) {\n      if (node.return === null || node.return === WIP) {\n        return;\n      }\n      node = node.return;\n    }\n    node.sibling.return = node.return;\n    node = node.sibling;\n  }\n}\n\nexport function completeWork(\n  current,\n  WIP,\n) {\n  // after beginWork work we props is new props\n  const newProps = WIP.props;\n  switch (WIP.tag) {\n    case Root: {\n      popHostContainer(WIP);\n      // const fiberRoot = WIP.instanceNode;\n      if (current === null || current.child === null) {\n        WIP.effectTag &= ~Placement;\n      }\n      // updateHostContainer(WIP);\n      return null;\n    }\n    case FComponent: {\n      return null;\n    }\n    case DNode: {\n      const rootContainerInstance = getRootHostContainer();\n      const type = WIP.type;\n      if (current !== null && WIP.instanceNode !== null) {\n        updateHostComponent(\n          current,\n          WIP,\n          type,\n          newProps,\n          rootContainerInstance,\n        );\n      } else {\n        if (!newProps) {\n          break;\n        }\n\n        // const currentHostContext = getHostContext();\n        const currentHostContext = {\n          namespace: \"http://www.w3.org/1999/xhtml\"\n        }\n        // create instance of element or fiber.. instance will be like document.createElement('div')\n        let instance = createDomNodeInstance(\n          type,\n          newProps,\n          rootContainerInstance,\n          currentHostContext,\n          WIP,\n        );\n        appendAllChildren(instance, WIP);\n        // this function to set property to element\n        finalizeInitialChildren(instance, type, newProps, rootContainerInstance, currentHostContext);\n        // and set state node\n        WIP.instanceNode = instance;\n\n      }\n      return null;\n    }\n    case Text: {\n      const newText = newProps;\n      // that means it rendered\n      if (current !== null && WIP.instanceNode !== null) {\n        let oldText = current.prevProps;\n        updateHostText(current, WIP, oldText, newText);\n      } else {\n        if (typeof newText !== 'string') {\n          return null;\n        }\n        const rootContainerInstance = getRootHostContainer();\n        WIP.instanceNode = createTextInstance(newText, rootContainerInstance, WIP);\n      }\n      return null;\n    }\n    case Fragment: {\n      return null;\n    }\n    default:\n      return null;\n  }\n}\n"
  },
  {
    "path": "src/fiber/f-life-cycle.js",
    "content": "let firstCallbackNode = null;\n\nfunction flushFirstCallback() {\n  let flushedNode = firstCallbackNode;\n\n  let next = firstCallbackNode.next;\n  if (firstCallbackNode === next) {\n    // This is the last callback in the list.\n    firstCallbackNode = null;\n    next = null;\n  } else {\n    let lastCallbackNode = firstCallbackNode.previous;\n    firstCallbackNode = lastCallbackNode.next = next;\n    next.previous = lastCallbackNode;\n  }\n  flushedNode.next = flushedNode.previous = null;\n\n  const callback = flushedNode.callback;\n  let continuationCallback;\n\n  continuationCallback = callback();\n\n}\n\n\nexport function callLifeCycle(callback) {\n  const newNode = {\n    callback: callback,\n    next: null,\n    previous: null,\n  }\n  if (firstCallbackNode === null) {\n    firstCallbackNode = newNode.next = newNode.previous = newNode;\n    flushFirstCallback();\n  } else {\n    let next = null;\n    let node = firstCallbackNode;\n\n    do {\n      next = node;\n    } while (node !== firstCallbackNode);\n\n    if (next === null) {\n      next = firstCallbackNode;\n    } else if (next === firstCallbackNode) {\n      firstCallbackNode = newNode;\n      flushFirstCallback();\n    }\n\n    let previous = next.previous;\n    previous.next = next.previous = newNode;\n    newNode.next = next;\n    newNode.previous = previous;\n  }\n\n}\n"
  },
  {
    "path": "src/fiber/f-node.js",
    "content": "// @flow\nimport type { VNodeElement, Container } from '../shared/types';\nimport * as Tag from '../shared/tag';\nimport * as Status from '../shared/status-work';\nimport { isString, isFunction } from '../shared/validate';\nimport { LinkedList } from '../structures/linked-list';\n\nexport type FNode = {\n  // tag is what we know what is this fiber like root, function component or text ...\n  tag: number,\n  key: string | null,\n  // type of element like button, div\n  elementType: string | null,\n  // it like element type\n  type: string | null,\n  // instanceNode is dom element\n  instanceNode: any,\n  // parent of node\n  return: FNode | null,\n  // child of node\n  child: FNode | null,\n  // sibling of node\n  sibling: FNode | null,\n  // index is index of array children element\n  // Eg: [f1, f2, f3] index of f2 is 1\n  index: number,\n  // props is pending props wait to work\n  props: any,\n  prevProps: any,\n  prevState: any,\n  // effect\n  effectTag: number,\n  nextEffect: FNode | null,\n  lastEffect: FNode | null,\n  firstEffect: FNode | null,\n  // this to test linked list\n  linkedList: any,\n  // rootRender\n  rootRender: any,\n  // alternate\n  alternate: FNode | null,\n  // status to know this fiber need work or not\n  status: number,\n  // life cycle of this fiber\n  lifeCycle: any,\n\n}\n\nexport type FRoot = {\n  current: FNode,\n  containerInfo: any,\n}\n\nfunction FNode(\n  tag: number,\n  props: any,\n  key: string | null\n) {\n  this.tag = tag;\n  this.key = key;\n  this.elementType = null;\n  this.type = null;\n\n  this.instanceNode = null;\n  this.return = null;\n  this.child = null;\n  this.sibling = null;\n  this.index = 0;\n\n  this.props = props;\n  this.prevProps = null;\n  this.prevState = null;\n\n  this.effectTag = 0;\n  this.nextEffect = null;\n  this.firstEffect = null;\n  this.lastEffect = null;\n  this.linkedList = new LinkedList();\n  this.next = null;\n\n  this.rootRender = null;\n\n  this.alternate = null;\n\n  this.status = Status.Working;\n\n  this.lifeCycle = null;\n}\n\nexport function createFNode(tag: number, props: any, key: string | null): FNode {\n  return new FNode(tag, props, key);\n}\n\nexport function createFRoot(container: Container): FRoot {\n  const current = new FNode(Tag.Root, null, null);\n  const root = {\n    current: current,\n    containerInfo: container,\n  }\n  current.instanceNode = root;\n  return root;\n}\n\n/**\n * @param {FNode} current is current fnode is displayed on screen\n * @param {any} props is nextProps of fiber\n * @return {FNode} new Fnode is next fiber to work is called work-in-progress\n */\n\nexport function createWIP(current: FNode, props: any): FNode {\n  if (current === null) return;\n  let WIP = current.alternate;\n  if (WIP === null) {\n    // if workInProgress === null we will start create a work-in-progress tree\n    WIP = createFNode(current.tag, props, current.key);\n    WIP.elementType = current.elementType;\n    WIP.type = current.type;\n    WIP.instanceNode = current.instanceNode;\n\n    WIP.alternate = current;\n    current.alternate = WIP;\n  } else {\n    // set props and reset effect tag\n    WIP.props = props;\n    WIP.effectTag = 0;\n\n    // The effect list is no longer valid.\n    WIP.nextEffect = null;\n    WIP.firstEffect = null;\n    WIP.lastEffect = null;\n    WIP.linkedList = new LinkedList();;\n    WIP.next = null;\n\n\n  }\n  WIP.child = current.child;\n\n  WIP.prevProps = current.prevProps;\n  WIP.prevState = current.prevState;\n  WIP.rootRender = current.rootRender;\n\n\n  WIP.sibling = current.sibling;\n  WIP.index = current.index;\n\n  WIP.status = current.status;\n\n  WIP.lifeCycle = current.lifeCycle;\n\n  return WIP;\n\n};\n\n/**\n * @param {Element} el is v-node\n * @return {FNode} new Fnode is created based on v-node element\n*/\n\nexport function createFNodeFromElement(el: VNodeElement): FNode {\n  if (el === null) return null;\n  const { type = '', key = null, props = {} } = el;\n  let fnode;\n  if (isString(type)) {\n    fnode = createFNode(Tag.DNode, props, key);\n  } else if (isFunction(type)) {\n    fnode = createFNode(Tag.FComponent, props, key);\n  }\n  if (fnode !== null) {\n    fnode.elementType = type;\n    fnode.type = type;\n  }\n  return fnode;\n}\n\nexport function createFNodeFromFragment(elements, key) {\n  const fnode = createFNode(Tag.Fragment, elements, key);\n  return fnode;\n}\n"
  },
  {
    "path": "src/fiber/f-with.js",
    "content": "import { scheduleWork } from './scheduler';\nimport * as Status from '../shared/status-work';\nimport {\n  Update as UpdateEffect\n} from '../shared/effect-tag';\nimport { isObject } from '../shared/validate';\nimport {\n  NoEffect as NoHookEffect,\n  UnmountSnapshot,\n  UnmountMutation,\n  MountMutation,\n  MountLayout,\n  UnmountPassive,\n  MountPassive,\n} from '../shared/with-effect';\n\n//test\nimport { withState } from '../core/with-state';\nimport { lifeCycle } from '../core/life-cycle';\n// The work-in-progress fiber. I've named it differently to distinguish it from\n// the work-in-progress hook.\nlet currentlyRenderingFNode = null;\n// Hooks are stored as a linked list on the fiber's prevState field. The\n// current hook list is the list that belongs to the current fiber. The\n// work-in-progress hook list is a new list that will be added to the\n// work-in-progress fiber.\nlet firstCurrentWith = null;\nlet currentWith = null;\nlet firstWIPFNode = null;\nlet WIPWith = null;\nlet componentUpdateQueue = null;\n// Updates scheduled during render will trigger an immediate re-render at the\n// end of the current pass. We can't store these updates on the normal queue,\n// because if the work is aborted, they should be discarded. Because this is\n// a relatively rare case, we also don't want to add an additional field to\n// either the hook or queue object types. So we store them in a lazily create\n// map of queue -> render-phase updates, which are discarded once the component\n// completes without re-rendering.\nfunction getCurrentRenderingFNode() {\n  return currentlyRenderingFNode;\n}\n\nexport function prepareWithState(current, WIP) {\n  currentlyRenderingFNode = WIP;\n  firstCurrentWith = current !== null ? current.prevState : null;\n}\n\nexport function finishedWith(Component, props, children) {\n  // This must be called after every function component to prevent hooks from\n  // being used in classes.\n  const renderedWork = currentlyRenderingFNode;\n  renderedWork.prevState = firstWIPFNode;\n  renderedWork.lifeCycle = componentUpdateQueue;\n\n  currentlyRenderingFNode = null;\n  currentWith = null;\n  firstCurrentWith = null;\n  firstWIPFNode = null;\n  WIPWith = null;\n\n  componentUpdateQueue = null;\n\n  return children;\n}\n\nexport function resetWiths() {\n  // This is called instead of `finishHooks` if the component throws. It's also\n  // called inside mountIndeterminateComponent if we determine the component\n  // is a module-style component.\n  currentlyRenderingFNode = null;\n  firstCurrentWith = null;\n  currentWith = null;\n  firstWIPFNode = null;\n  WIPWith = null;\n  componentUpdateQueue = null;\n\n}\n\nfunction createWith() {\n  return {\n    prevState: null,\n\n    baseState: null,\n    queue: null,\n    baseUpdate: null,\n\n    next: null\n  }\n}\n\nfunction cloneWith(With) {\n  return {\n    prevState: With.prevState,\n\n    baseState: With.prevState,\n    queue: With.queue,\n    baseUpdate: With.baseUpdate,\n\n    next: null,\n  };\n}\n\nfunction createWIPWith() {\n\n  if (WIPWith === null) {\n    // this is the first hook in the list\n    if (firstWIPFNode === null) {\n      currentWith = firstCurrentWith;\n      if (currentWith === null) {\n        // This is a newly mounted hook\n        WIPWith = createWith();\n      } else {\n        // clone the current with\n        WIPWith = cloneWith(currentWith);\n      }\n      firstWIPFNode = WIPWith;\n    } else {\n      // There's already a work-in-progress. Reuse it.\n      currentWith = firstCurrentWith;\n      WIPWith = firstWIPFNode;\n    }\n  } else {\n\n    if (WIPWith.next === null) {\n      let With;\n      if (currentWith === null) {\n        // This is a newly mounted hook\n        With = createWith();\n      } else {\n        // clone\n        currentWith = currentWith.next;\n        if (currentWith === null) {\n          // This is a newly mounted hook\n          With = createWith();\n        } else {\n          // Clone the current hook.\n          With = cloneWith(currentWith);\n        }\n      }\n      // Append to the end of the list\n      WIPWith = WIPWith.next = With;\n    }\n    else {\n      // There's already a work-in-progress. Reuse it.\n      WIPWith = WIPWith.next;\n      currentWith = currentWith !== null ? currentWith.next : null;\n    }\n\n  }\n\n  return WIPWith;\n}\n\nfunction basicStateReducer(state, action) {\n  return typeof action === 'function' ? action(state) : action;\n}\n\n// export const generalId = () => {\n//   return '_' + Math.random().toString(36).substr(2, 9);\n// };\n\nexport function withReducer(initialState) {\n  // const id = generalId();\n  currentlyRenderingFNode = getCurrentRenderingFNode();\n  // set work to this fiber\n  // currentlyRenderingFNode.status = Status.Working;\n  WIPWith = createWIPWith();\n\n  let queue = WIPWith.queue;\n  if (queue !== null) {\n    // Already have a queue, so this is an update.\n\n    // The last update in the entire queue\n    const last = queue.last;\n    // The last update that is part of the base state.\n    const baseUpdate = WIPWith.baseUpdate;\n    // Find the first unprocessed update.\n    let first;\n    if (baseUpdate !== null) {\n      if (last !== null) {\n        // For the first update, the queue is a circular linked list where\n        // `queue.last.next = queue.first`. Once the first update commits, and\n        // the `baseUpdate` is no longer empty, we can unravel the list.\n        last.next = null;\n      }\n      first = baseUpdate.next;\n    } else {\n      first = last !== null ? last.next : null;\n    }\n    if (first !== null) {\n      let newState = WIPWith.baseState;\n      let newBaseState = null;\n      let newBaseUpdate = null;\n      let prevUpdate = baseUpdate;\n      let update = first;\n      let didSkip = false;\n      do {\n        const action = update.action;\n        newState = basicStateReducer(newState, action);\n        prevUpdate = update;\n        update = update.next;\n      } while(update !== null && update !== first)\n\n      if (!didSkip) {\n        newBaseUpdate = prevUpdate;\n        newBaseState = newState;\n      }\n\n      WIPWith.prevState = newState;\n      WIPWith.baseUpdate = newBaseUpdate;\n      WIPWith.baseState = newBaseState;\n\n    }\n\n    const dispatch = queue.dispatch;\n    return [WIPWith.prevState, dispatch];\n  }\n  // There's no existing queue, so this is the initial render.\n  // if (true) {\n  //\n  // }\n  WIPWith.prevState = WIPWith.baseState = initialState;\n  queue = WIPWith.queue = {\n    last: null,\n    dispatch: null,\n  };\n  const dispatch = queue.dispatch = dispatchAction.bind(null, currentlyRenderingFNode, queue);\n\n  return [WIPWith.prevState, dispatch]\n }\n\n function dispatchAction(fnode, queue, action) {\n   fnode.status = 1;\n   const alternate = fnode.alternate;\n\n   if (alternate !== null) {\n     alternate.status = 1;\n   }\n\n   const update = {\n     action,\n     next: null,\n   }\n   // flushPassiveEffects();\n   // append the update to the end of the list\n   const last = queue.last;\n   if (last === null) {\n     // This is the first update. Create a circular list.\n     update.next = update;\n\n   } else {\n     const first = last.next;\n     if (first !== null) {\n      // Still circular.\n      update.next = first;\n      }\n      last.next = update;\n   }\n   queue.last = update;\n   scheduleWork(fnode);\n }\n\n\n export function withLifeCycle(fnodeEffectTag, withEffectTag, lifeCycle) {\n   currentlyRenderingFNode = getCurrentRenderingFNode();\n   WIPWith = createWIPWith();\n   const inputs = undefined;\n   const nextInputs = inputs !== undefined && inputs !== null ? inputs : [];\n   let destroyed = null;\n   if (currentWith !== null) {\n     // for componentdidupdate\n     const prevEffect = currentWith.prevState;\n     destroyed = prevEffect.destroy;\n     if (inputsAreEqual(nextInputs, prevEffect.inputs)) {\n       pushEffect(NoHookEffect, lifeCycle, destroyed);\n       return;\n     }\n   }\n   currentlyRenderingFNode.effectTag |= fnodeEffectTag;\n\n   WIPWith.prevState = pushEffect(\n     withEffectTag,\n     lifeCycle,\n     destroyed,\n   );\n }\n\n function pushEffect(tag, lifeCycle, destroyed) {\n   const { mounted, updated } = lifeCycle;\n   const effect = {\n     tag,\n     mounted: mounted || null,\n     updated: updated || null,\n     destroyed: destroyed || null,\n     inputs: [],\n     // circular linked-list\n     next: null,\n   };\n  if (componentUpdateQueue === null) {\n    componentUpdateQueue = createFunctionComponentUpdateQueue();\n    componentUpdateQueue.lastEffect = effect.next = effect;\n  } else {\n    const lastEffect = componentUpdateQueue.lastEffect;\n    if (lastEffect === null) {\n      componentUpdateQueue.lastEffect = effect.next = effect;\n    } else {\n      const firstEffect = lastEffect.next;\n      lastEffect.next = effect;\n      effect.next = firstEffect;\n      componentUpdateQueue.lastEffect = effect;\n    }\n  }\n  return effect;\n }\n\n function createFunctionComponentUpdateQueue() {\n   return {\n     lastEffect: null,\n   }\n }\n\n function inputsAreEqual(arr1, arr2) {\n  // Don't bother comparing lengths in prod because these arrays should be\n  // passed inline.\n  for (let i = 0; i < arr1.length; i++) {\n    // Inlined Object.is polyfill.\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is\n    const val1 = arr1[i];\n    const val2 = arr2[i];\n    if (\n      (val1 === val2 && (val1 !== 0 || 1 / val1 === 1 / (val2: any))) ||\n      (val1 !== val1 && val2 !== val2) // eslint-disable-line no-self-compare\n    ) {\n      continue;\n    }\n    return false;\n  }\n  return true;\n}\n"
  },
  {
    "path": "src/fiber/host-context.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\nimport type {StackCursor} from './stack';\nimport {createCursor, push, pop} from './stack';\n\ndeclare class NoContextT {}\nconst NO_CONTEXT: NoContextT = ({}: any);\n\nlet rootInstanceStackCursor: StackCursor<T> = createCursor(\n  NO_CONTEXT,\n);\n\nfunction requiredContext<Value>(c: Value | NoContextT): Value {\n  return (c: any);\n}\n\nfunction getRootHostContainer() {\n  const rootInstance = requiredContext(rootInstanceStackCursor.current);\n  return rootInstance;\n}\n\nfunction pushHostContainer(fiber, nextRootInstance) {\n  // Push current root instance onto the stack;\n  // This allows us to reset root when portals are popped.\n  push(rootInstanceStackCursor, nextRootInstance, fiber);\n}\n\nfunction popHostContainer(fiber) {\n  pop(rootInstanceStackCursor, fiber);\n}\n\nexport {\n  getRootHostContainer,\n  popHostContainer,\n  pushHostContainer,\n};\n"
  },
  {
    "path": "src/fiber/reconciler.js",
    "content": "// @flow\nimport type { VNodeElement, Container } from '../shared/types';\nimport type { FNode, FRoot } from './f-node';\n\nimport { createFRoot } from './f-node';\nimport { scheduleWork } from './scheduler';\nimport { createRootRender } from './root-render';\n\nexport function createContainer(container: Container): FRoot {\n  return createFRoot(container);\n}\n\nexport function updateContainer(el: VNodeElement, FRoot: FRoot): void {\n  const current = FRoot.current;\n  return scheduleRootUpdate(current, el);\n}\n\nfunction scheduleRootUpdate(current: FNode, el: VNodeElement): void {\n  const rootRender = createRootRender(el);\n  current.rootRender = rootRender;\n\n  scheduleWork(current);\n}\n"
  },
  {
    "path": "src/fiber/root-render.js",
    "content": "export function createRootRender(el) {\n  const rootRender = {\n    element: el,\n  }\n  return rootRender;\n}\n\n\nexport function updateRootRender(WIP, rootRender) {\n  let resultState;\n  if (rootRender && rootRender.element) {\n    resultState = rootRender;\n  }\n  WIP.prevState = resultState;\n}\n"
  },
  {
    "path": "src/fiber/scheduler.js",
    "content": "// @flow\nimport type { FNode, FRoot } from './f-node';\n\nimport {\n  Root,\n  Text,\n  DNode,\n  FComponent,\n} from '../shared/tag';\nimport {\n  Incomplete,\n  NoEffect,\n  PerformedWork,\n  Placement,\n  Deletion,\n  Update,\n  Passive,\n  PlacementAndUpdate\n} from '../shared/effect-tag';\nimport {\n  UnmountLayout,\n  MountLayout\n} from '../shared/with-effect';\nimport { createWIP } from './f-node';\nimport { beginWork } from './begin-work';\nimport { completeWork } from './complete-work';\nimport {\n  commitPlacement,\n  commitDeletion,\n  commitWork,\n  commitPassiveWithEffects,\n  commitWithEffectList\n} from './commit-work';\nimport { resetWiths } from './f-with';\nimport { callLifeCycle } from './f-life-cycle';\nimport { LinkedList } from '../structures/linked-list';\nconst expireTime = 1;\n\nlet nextUnitOfWork = null;\nlet nextEffect = null;\n\nlet rootWithPendingPassiveEffects = null;\n\nexport function scheduleWork(fnode: FNode): void {\n  const root = getRootFromFnode(fnode);\n  if (root === null) {\n    // clone here\n    return;\n  }\n  resetWiths();\n  requestIdleCallback(dl => performWork(dl, root))\n}\n\nfunction getRootFromFnode(fnode: FNode): FRoot {\n  let node = fnode;\n  if (fnode !== null && node.tag === Root && node.return === null) {\n    return fnode.instanceNode;\n  }\n  node = node.return;\n  return getRootFromFnode(node);\n}\n\nfunction performWork(dl: any, root: FRoot): void {\n  workLoop(dl, root);\n  if (nextUnitOfWork) {\n    requestIdleCallback(dl => performWork(dl, root));\n  }\n  if (nextUnitOfWork === null) {\n    let finishedWork = root.current.alternate;\n    if (finishedWork) {\n      // complete Root\n      completeRoot(root, finishedWork)\n    }\n  }\n}\n\nfunction workLoop(dl: any, root: FRoot): void {\n  if (!nextUnitOfWork) {\n    nextUnitOfWork = createWIP(root.current, null);\n  }\n  while (nextUnitOfWork !== null && dl.timeRemaining() > expireTime) {\n    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);\n  }\n}\n\nfunction performUnitOfWork(WIP: FNode): FNode {\n  const current = WIP.alternate;\n  let next;\n  next = beginWork(current, WIP);\n  WIP.prevProps = WIP.props;\n  if (next === null) {\n    next = completeUnitOfWork(WIP);\n  }\n  return next;\n}\n\nfunction completeUnitOfWork(WIP: FNode): FNode | null {\n  // Attempt to complete the current unit of work, then move to the\n  // next sibling. If there are no more siblings, return to the\n  // parent fiber.\n\n  while (true) {\n    // The current, flushed, state of this fiber is the alternate.\n    // Ideally nothing should rely on this, but relying on it here\n    // means that we don't need an additional field on the work in\n    // progress.\n    const current = WIP.alternate;\n    const returnFNode = WIP.return;\n\n    const siblingFNode = WIP.sibling;\n    if ((WIP.effectTag & Incomplete) === NoEffect) {\n      // completeWork work to create instanceNode of this WIP\n      let next = completeWork(current, WIP);\n      if (next !== null) {\n        return next;\n      }\n\n      if (returnFNode !== null &&\n        // Do not append effects to parents if a sibling failed to complete\n        (returnFNode.effectTag & Incomplete) === NoEffect) {\n          returnFNode.linkedList.addEffectToParent(WIP);\n          // If this fiber had side-effects, we append it AFTER the children's\n          // side-effects. We can perform certain side-effects earlier if\n          // needed, by doing multiple passes over the effect list. We don't want\n          // to schedule our own side-effect on our own list because if end up\n          // reusing children we'll schedule this effect onto itself since we're\n          // at the end.\n          let effectTag = WIP.effectTag;\n          // Skip both NoWork and PerformedWork tags when creating the effect list.\n          // PerformedWork effect is read by React DevTools but shouldn't be committed.\n          if (effectTag > PerformedWork) {\n            returnFNode.linkedList.add(WIP)\n          }\n      }\n\n      if (siblingFNode !== null) {\n        // If there is more work to do in this returnFNode, do that next.\n        return siblingFNode;\n      } else if (returnFNode !== null) {\n        // If there's no more work in this returnFNode. Complete the returnFNode.\n        WIP = returnFNode;\n        continue;\n      } else {\n        // We've reached the root.\n        return null;\n      }\n    } else {\n      if (siblingFNode !== null) {\n        // If there is more work to do in this returnFNode, do that next.\n        return siblingFNode;\n      } else if (returnFNode !== null) {\n        // If there's no more work in this returnFNode. Complete the returnFNode.\n        WIP = returnFNode;\n        continue;\n      } else {\n        return null;\n      }\n    }\n\n  }\n\n  return null\n}\n\nexport function completeRoot(\n  root: FRoot,\n  finishedWork: FNode,\n): void {\n  // Commit the root.\n  root.finishedWork = null;\n  commitRoot(root, finishedWork);\n}\n\nexport function commitRoot(root: FRoot, finishedWork: FNode): void {\n  let firstEffect;\n  const linkedList = finishedWork.linkedList;\n\n  if (finishedWork.effectTag > PerformedWork) {\n    // A fiber's effect list consists only of its children, not itself. So if\n    // the root has an effect, we need to add it to the end of the list. The\n    // resulting list is the set that would belong to the root's parent, if\n    // it had one; that is, all the effects in the tree including the root.\n    if (linkedList.last !== null) {\n      linkedList.last.next = finishedWork;\n      firstEffect = linkedList.first;\n    } else {\n      firstEffect = finishedWork;\n    }\n  } else {\n    // There is no effect on the root.\n    firstEffect = linkedList.first;;\n  }\n\n  nextEffect = firstEffect;\n\n  while (nextEffect !== null) {\n    commitAllHostEffects()\n    if (nextEffect !== null) {\n        nextEffect = nextEffect.next;\n    }\n  }\n\n  // Invoke instances of getSnapshotBeforeUpdate before mutation.\n\n\n\n  // The work-in-progress tree is now the current tree. This must come after\n  // the first pass of the commit phase, so that the previous tree is still\n  // current during componentWillUnmount, but before the second pass, so that\n  // the finished work is current during componentDidMount/Update.\n  root.current = finishedWork;\n\n  // In the second pass we'll perform all life-cycles and ref callbacks.\n  // Life-cycles happen as a separate pass so that all placements, updates,\n  // and deletions in the entire tree have already been invoked.\n  // This pass also triggers any renderer-specific initial effects.\n  nextEffect = firstEffect;\n\n  //commitAllLifeCircleHere\n  while (nextEffect !== null) {\n    commitAllLifeCycles(root);\n    if (nextEffect !== null) {\n      nextEffect = nextEffect.next;\n    }\n  }\n\n  // This commit included a passive effect. These do not need to fire until\n  // after the next paint. Schedule an callback to fire them in an async\n  // event. To ensure serial execution, the callback will be flushed early if\n  // we enter rootWithPendingPassiveEffects commit phase before then.\n  if(\n    firstEffect !== null\n    && rootWithPendingPassiveEffects !== null\n  ) {\n    let callback = commitPassiveEffects.bind(null, root, firstEffect);\n    callLifeCycle(callback);\n  }\n}\n\nfunction commitPassiveEffects(root: FRoot, firstEffect: FNode): void {\n  rootWithPendingPassiveEffects = null;\n  let effect = firstEffect;\n  do {\n    if (effect.effectTag & Passive) {\n      try {\n        commitPassiveWithEffects(effect);\n      } catch(err) {\n        console.log(err)\n      }\n    }\n    effect = effect.next;\n  } while(effect !== null)\n}\n\nfunction commitAllHostEffects() {\n\n  while (nextEffect !== null) {\n    const effectTag = nextEffect.effectTag;\n    // The following switch statement is only concerned about placement,\n    // updates, and deletions. To avoid needing to add a case for every\n    // possible bitmap value, we remove the secondary effects from the\n    // effect tag and switch on that value.\n    let primaryEffectTag = effectTag & (Placement | Update | Deletion);\n    switch (primaryEffectTag) {\n      case Placement: {\n        commitPlacement(nextEffect);\n        // Clear the \"placement\" from effect tag so that we know that this is inserted, before\n        // any life-cycles like componentDidMount gets called.\n        // TODO: findDOMNode doesn't rely on this any more but isMounted\n        // does and isMounted is deprecated anyway so we should be able\n        // to kill this.\n        nextEffect.effectTag &= ~Placement;\n        break;\n      }\n      case PlacementAndUpdate: {\n        // Placement\n        commitPlacement(nextEffect);\n        // Clear the \"placement\" from effect tag so that we know that this is inserted, before\n        // any life-cycles like componentDidMount gets called.\n        nextEffect.effectTag &= ~Placement;\n\n        // Update\n        const current = nextEffect.alternate;\n        commitWork(current, nextEffect);\n        break;\n      };\n      case Update: {\n        const current = nextEffect.alternate;\n        commitWork(current, nextEffect);\n        break;\n      }\n      case Deletion: {\n        commitDeletion(nextEffect);\n        break;\n      }\n      default:\n        break;\n    }\n    nextEffect = nextEffect.next;\n\n  }\n}\n\n\nfunction commitAllLifeCycles(finishedRoot) {\n  while (nextEffect !== null) {\n    const effectTag = nextEffect.effectTag;\n    if (effectTag & Update) {\n      const current = nextEffect.alternate;\n      commitLifeCycles(finishedRoot, current, nextEffect);\n    }\n    if (effectTag & Passive) {\n      rootWithPendingPassiveEffects = finishedRoot;\n    }\n    nextEffect = nextEffect.next;\n\n  }\n}\n\nfunction commitLifeCycles(finishedRoot, current, finishedWork) {\n  switch (finishedWork.tag) {\n    case FComponent:\n      commitWithEffectList(UnmountLayout, MountLayout, finishedWork);\n      return;\n    case Root:\n      return\n    case DNode:\n      return;\n    case Text:\n      return;\n    default:\n      console.log('Error')\n  }\n}\n"
  },
  {
    "path": "src/fiber/stack.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\nexport type StackCursor<T> = {\n  current: T,\n};\n\nconst valueStack: Array<any> = [];\n\nlet fiberStack: Array<any>;\n\nlet index = -1;\n\nfunction createCursor<T>(defaultValue: T): StackCursor<T> {\n  return {\n    current: defaultValue,\n  };\n}\n\nfunction isEmpty(): boolean {\n  return index === -1;\n}\n\nfunction pop<T>(cursor: StackCursor<T>, fiber): void {\n  if (index < 0) {\n    return;\n  }\n\n  cursor.current = valueStack[index];\n  valueStack[index] = null;\n  // fiberStack[index] = null;\n  index--;\n}\n\nfunction push<T>(cursor: StackCursor<T>, value: T, fiber): void {\n  index++;\n\n  valueStack[index] = cursor.current;\n  // fiberStack[index] = fiber;\n\n  cursor.current = value;\n}\n\nexport {\n  createCursor,\n  isEmpty,\n  pop,\n  push,\n};\n"
  },
  {
    "path": "src/shared/effect-tag.js",
    "content": "const NoEffect = 0;\nconst PerformedWork = 1;\nconst Placement = 2;\nconst Update = 4;\nconst PlacementAndUpdate = 6;\nconst Deletion = 8;\n\nconst Incomplete = 1024;\nconst ContentReset = 11;\nconst Passive = 512;\n\nexport {\n  NoEffect,\n  PerformedWork,\n  Placement,\n  Update,\n  PlacementAndUpdate,\n  Deletion,\n\n  Incomplete,\n  ContentReset ,\n  Passive\n\n}\n"
  },
  {
    "path": "src/shared/shallowEqual.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\n/*eslint-disable no-self-compare */\n\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\n\n/**\n * inlined Object.is polyfill to avoid requiring consumers ship their own\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is\n */\nfunction is(x, y) {\n  // SameValue algorithm\n  if (x === y) {\n    // Steps 1-5, 7-10\n    // Steps 6.b-6.e: +0 != -0\n    // Added the nonzero y check to make Flow happy, but it is redundant\n    return x !== 0 || y !== 0 || 1 / x === 1 / y;\n  } else {\n    // Step 6.a: NaN == NaN\n    return x !== x && y !== y;\n  }\n}\n\n/**\n * Performs equality by iterating through keys on an object and returning false\n * when any key has values which are not strictly equal between the arguments.\n * Returns true when the values of all keys are strictly equal.\n */\nfunction shallowEqual(objA: mixed, objB: mixed): boolean {\n  if (is(objA, objB)) {\n    return true;\n  }\n\n  if (\n    typeof objA !== 'object' ||\n    objA === null ||\n    typeof objB !== 'object' ||\n    objB === null\n  ) {\n    return false;\n  }\n\n  const keysA = Object.keys(objA);\n  const keysB = Object.keys(objB);\n\n  if (keysA.length !== keysB.length) {\n    return false;\n  }\n\n  // Test for A's keys different from B.\n  for (let i = 0; i < keysA.length; i++) {\n    if (\n      !hasOwnProperty.call(objB, keysA[i]) ||\n      !is(objA[keysA[i]], objB[keysA[i]])\n    ) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nexport default shallowEqual;\n"
  },
  {
    "path": "src/shared/status-work.js",
    "content": "const NoWork = 0;\nconst Working = 1;\n\nexport {\n  NoWork,\n  Working,\n}\n"
  },
  {
    "path": "src/shared/tag.js",
    "content": "const Root = 0;\nconst DNode = 1;\nconst FComponent = 2;\nconst Text = 3;\nconst Fragment = 7;\n\n\nexport {\n  Root,\n  DNode,\n  FComponent,\n  Text,\n  Fragment,\n}\n"
  },
  {
    "path": "src/shared/types.js",
    "content": "// @flow\nexport type VNodeElement = {\n  $$typeof: any,\n  type: any,\n  key: any,\n  props: any,\n}\n\nexport type Container = Element | Document;\n"
  },
  {
    "path": "src/shared/validate.js",
    "content": "/** Check Array**/\nconst isArray = Array.isArray;\n/** Check null**/\nconst isNil = value => typeof value === 'object' && value === null;\n/** Check object**/\nconst isObject = value => typeof value === 'object' && value !== null && !isArray(value);\n/** Check undefined**/\nconst isUndef = value => typeof value === 'undefined';\n/** Check function**/\nconst isFunction = value => !isUndef(value) && typeof value === 'function';\n/** Check number**/\nconst isNumber = value => Number.isInteger(value) && typeof value === \"number\";\n/** Check string**/\nconst isString = value => typeof value === 'string';\n\nexport {\n  isNil,\n  isObject,\n  isUndef,\n  isFunction,\n  isArray,\n  isString,\n  isNumber,\n};\n"
  },
  {
    "path": "src/shared/with-effect.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nexport type HookEffectTag = number;\n\nexport const NoEffect = /*             */ 0b00000000;\nexport const UnmountSnapshot = /*      */ 0b00000010;\nexport const UnmountMutation = /*      */ 0b00000100;\nexport const MountMutation = /*        */ 0b00001000;\nexport const UnmountLayout = /*        */ 0b00010000;\nexport const MountLayout = /*          */ 0b00100000;\nexport const MountPassive = /*         */ 0b01000000;\nexport const UnmountPassive = /*       */ 0b10000000;\n"
  },
  {
    "path": "src/structures/linked-list.js",
    "content": "export function LinkedList() {\n  this.first = null;\n  this.last = null;\n  return this;\n}\n\nLinkedList.prototype.add = function (node) {\n  if (this.last === null) {\n    this.last = node;\n    this.first = node;\n    return;\n  }\n  this.last.next = node;\n  this.last = node;\n};\n\n// custom single linked-list add node\nLinkedList.prototype.addEffectToParent = function (node) {\n  if (this.first === null) {\n    this.first = node.linkedList.first;\n  }\n\n  if (node.linkedList.last !== null) {\n    if (this.last !== null) {\n      this.last.next = node.linkedList.first;\n    }\n    this.last = node.linkedList.last;\n  }\n};\n"
  },
  {
    "path": "webpack.config.js",
    "content": "var path = require('path');\n// var ExtractTextPlugin = require('extract-text-webpack-plugin');\nvar ReplacePlugin = require('replace-bundle-webpack-plugin');\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\n\n\nmodule.exports = {\n\tentry: {\n    bundle: './index.js'\n  },\n  output: {\n    path: path.resolve(__dirname, 'dist'),\n    filename: 'bundle.js'\n\t},\n\tmodule: {\n\t\trules: [\n\t\t\t{\n\t\t\t\ttest: /\\.jsx?$/,\n\t\t\t\texclude: /node_modules/,\n\t\t\t\tloader: 'babel-loader'\n\t\t\t},\n\t\t\t{\n      \ttest: /\\.js$/,\n     \t\texclude: /node_modules/,\n     \t\tuse: 'babel-loader'\n   \t\t},\n\t\t\t// {\n\t\t\t// \ttest: /\\.css$/,\n\t\t\t// \tloader: ExtractTextPlugin.extract('style')\n\t\t\t// }\n\t\t]\n\t},\n\tplugins: [\n   new HtmlWebpackPlugin({\n\t\t template: 'index.html'\n\t })\n\t],\n\tdevtool: 'source-map',\n\tdevServer: {\n\t\tport: process.env.PORT || 8080\n\t}\n};\n"
  }
]