[
  {
    "path": ".prettierrc",
    "content": "{\n  \"semi\": false,\n  \"printWidth\": 52,\n  \"trailingComma\": \"es5\"\n}\n"
  },
  {
    "path": "didact.js",
    "content": "function createElement(type, props, ...children) {\n  return {\n    type,\n    props: {\n      ...props,\n      children: children.map(child =>\n        typeof child === \"object\"\n          ? child\n          : createTextElement(child)\n      ),\n    },\n  }\n}\n\nfunction createTextElement(text) {\n  return {\n    type: \"TEXT_ELEMENT\",\n    props: {\n      nodeValue: text,\n      children: [],\n    },\n  }\n}\n\nfunction createDom(fiber) {\n  const dom =\n    fiber.type == \"TEXT_ELEMENT\"\n      ? document.createTextNode(\"\")\n      : document.createElement(fiber.type)\n\n  updateDom(dom, {}, fiber.props)\n\n  return dom\n}\n\nconst isEvent = key => key.startsWith(\"on\")\nconst isProperty = key =>\n  key !== \"children\" && !isEvent(key)\nconst isNew = (prev, next) => key =>\n  prev[key] !== next[key]\nconst isGone = (prev, next) => key => !(key in next)\nfunction updateDom(dom, prevProps, nextProps) {\n  //Remove old or changed event listeners\n  Object.keys(prevProps)\n    .filter(isEvent)\n    .filter(\n      key =>\n        !(key in nextProps) ||\n        isNew(prevProps, nextProps)(key)\n    )\n    .forEach(name => {\n      const eventType = name\n        .toLowerCase()\n        .substring(2)\n      dom.removeEventListener(\n        eventType,\n        prevProps[name]\n      )\n    })\n\n  // Remove old properties\n  Object.keys(prevProps)\n    .filter(isProperty)\n    .filter(isGone(prevProps, nextProps))\n    .forEach(name => {\n      dom[name] = \"\"\n    })\n\n  // Set new or changed properties\n  Object.keys(nextProps)\n    .filter(isProperty)\n    .filter(isNew(prevProps, nextProps))\n    .forEach(name => {\n      dom[name] = nextProps[name]\n    })\n\n  // Add event listeners\n  Object.keys(nextProps)\n    .filter(isEvent)\n    .filter(isNew(prevProps, nextProps))\n    .forEach(name => {\n      const eventType = name\n        .toLowerCase()\n        .substring(2)\n      dom.addEventListener(\n        eventType,\n        nextProps[name]\n      )\n    })\n}\n\nfunction commitRoot() {\n  deletions.forEach(commitWork)\n  commitWork(wipRoot.child)\n  currentRoot = wipRoot\n  wipRoot = null\n}\n\nfunction commitWork(fiber) {\n  if (!fiber) {\n    return\n  }\n\n  let domParentFiber = fiber.parent\n  while (!domParentFiber.dom) {\n    domParentFiber = domParentFiber.parent\n  }\n  const domParent = domParentFiber.dom\n\n  if (\n    fiber.effectTag === \"PLACEMENT\" &&\n    fiber.dom != null\n  ) {\n    domParent.appendChild(fiber.dom)\n  } else if (\n    fiber.effectTag === \"UPDATE\" &&\n    fiber.dom != null\n  ) {\n    updateDom(\n      fiber.dom,\n      fiber.alternate.props,\n      fiber.props\n    )\n  } else if (fiber.effectTag === \"DELETION\") {\n    commitDeletion(fiber, domParent)\n  }\n\n  commitWork(fiber.child)\n  commitWork(fiber.sibling)\n}\n\nfunction commitDeletion(fiber, domParent) {\n  if (fiber.dom) {\n    domParent.removeChild(fiber.dom)\n  } else {\n    commitDeletion(fiber.child, domParent)\n  }\n}\n\nfunction render(element, container) {\n  wipRoot = {\n    dom: container,\n    props: {\n      children: [element],\n    },\n    alternate: currentRoot,\n  }\n  deletions = []\n  nextUnitOfWork = wipRoot\n}\n\nlet nextUnitOfWork = null\nlet currentRoot = null\nlet wipRoot = null\nlet deletions = null\n\nfunction workLoop(deadline) {\n  let shouldYield = false\n  while (nextUnitOfWork && !shouldYield) {\n    nextUnitOfWork = performUnitOfWork(\n      nextUnitOfWork\n    )\n    shouldYield = deadline.timeRemaining() < 1\n  }\n\n  if (!nextUnitOfWork && wipRoot) {\n    commitRoot()\n  }\n\n  requestIdleCallback(workLoop)\n}\n\nrequestIdleCallback(workLoop)\n\nfunction performUnitOfWork(fiber) {\n  const isFunctionComponent =\n    fiber.type instanceof Function\n  if (isFunctionComponent) {\n    updateFunctionComponent(fiber)\n  } else {\n    updateHostComponent(fiber)\n  }\n  if (fiber.child) {\n    return fiber.child\n  }\n  let nextFiber = fiber\n  while (nextFiber) {\n    if (nextFiber.sibling) {\n      return nextFiber.sibling\n    }\n    nextFiber = nextFiber.parent\n  }\n}\n\nlet wipFiber = null\nlet hookIndex = null\n\nfunction updateFunctionComponent(fiber) {\n  wipFiber = fiber\n  hookIndex = 0\n  wipFiber.hooks = []\n  const children = [fiber.type(fiber.props)]\n  reconcileChildren(fiber, children)\n}\n\nfunction useState(initial) {\n  const oldHook =\n    wipFiber.alternate &&\n    wipFiber.alternate.hooks &&\n    wipFiber.alternate.hooks[hookIndex]\n  const hook = {\n    state: oldHook ? oldHook.state : initial,\n    queue: [],\n  }\n\n  const actions = oldHook ? oldHook.queue : []\n  actions.forEach(action => {\n    hook.state = action(hook.state)\n  })\n\n  const setState = action => {\n    hook.queue.push(action)\n    wipRoot = {\n      dom: currentRoot.dom,\n      props: currentRoot.props,\n      alternate: currentRoot,\n    }\n    nextUnitOfWork = wipRoot\n    deletions = []\n  }\n\n  wipFiber.hooks.push(hook)\n  hookIndex++\n  return [hook.state, setState]\n}\n\nfunction updateHostComponent(fiber) {\n  if (!fiber.dom) {\n    fiber.dom = createDom(fiber)\n  }\n  reconcileChildren(fiber, fiber.props.children)\n}\n\nfunction reconcileChildren(wipFiber, elements) {\n  let index = 0\n  let oldFiber =\n    wipFiber.alternate && wipFiber.alternate.child\n  let prevSibling = null\n\n  while (\n    index < elements.length ||\n    oldFiber != null\n  ) {\n    const element = elements[index]\n    let newFiber = null\n\n    const sameType =\n      oldFiber &&\n      element &&\n      element.type == oldFiber.type\n\n    if (sameType) {\n      newFiber = {\n        type: oldFiber.type,\n        props: element.props,\n        dom: oldFiber.dom,\n        parent: wipFiber,\n        alternate: oldFiber,\n        effectTag: \"UPDATE\",\n      }\n    }\n    if (element && !sameType) {\n      newFiber = {\n        type: element.type,\n        props: element.props,\n        dom: null,\n        parent: wipFiber,\n        alternate: null,\n        effectTag: \"PLACEMENT\",\n      }\n    }\n    if (oldFiber && !sameType) {\n      oldFiber.effectTag = \"DELETION\"\n      deletions.push(oldFiber)\n    }\n\n    if (oldFiber) {\n      oldFiber = oldFiber.sibling\n    }\n\n    if (index === 0) {\n      wipFiber.child = newFiber\n    } else if (element) {\n      prevSibling.sibling = newFiber\n    }\n\n    prevSibling = newFiber\n    index++\n  }\n}\n\nconst Didact = {\n  createElement,\n  render,\n  useState,\n}\n\n/** @jsx Didact.createElement */\nfunction Counter() {\n  const [state, setState] = Didact.useState(1)\n  return (\n    <h1 onClick={() => setState(c => c + 1)}>\n      Count: {state}\n    </h1>\n  )\n}\nconst element = <Counter />\nconst container = document.getElementById(\"root\")\nDidact.render(element, container)\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"didact\",\n  \"version\": \"3.0.0\",\n  \"description\": \"A didactic alternative to React\",\n  \"license\": \"MIT\",\n  \"repository\": \"pomber/didact\",\n  \"author\": \"pomber\",\n  \"main\": \"didact.js\",\n  \"keywords\": [\n    \"react\"\n  ]\n}\n"
  },
  {
    "path": "readme.md",
    "content": "<p align=\"center\"><img src=\"https://cloud.githubusercontent.com/assets/1911623/26426031/5176c348-40ad-11e7-9f1a-1e2f8840b562.jpeg\"></p>\n\n# Didact\n\n#### A DIY guide to build your own React\n\nThis repository goes together with a [series of posts](https://medium.com/hexacta-engineering/didact-learning-how-react-works-by-building-it-from-scratch-51007984e5c5) that explains how to build React from scratch step by step. **You can jump straight to [the last post](https://pomb.us/build-your-own-react) which is self-contained and includes everything.**\n\n| Blog Post                                                                                                                                       |                         Code sample                          |                                                                                                                                    Commits                                                                                                                                    |                                                       Other languages                                                       |\n| ----------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------: |\n| [Introduction](https://medium.com/hexacta-engineering/didact-learning-how-react-works-by-building-it-from-scratch-51007984e5c5)                        |                                                              |                                                                                                                                                                                                                                                                               |                                                                                                                             |\n| [Rendering DOM elements](https://medium.com/hexacta-engineering/didact-rendering-dom-elements-91c9aa08323b)                                            | [codepen](https://codepen.io/pomber/pen/eWbwBq?editors=0010) |                                                                                           [diff](https://github.com/hexacta/didact/commit/fc4d360d91a1e68f0442d39dbce5b9cca5a08f24)                                                                                           |               [中文](https://github.com/chinanf-boy/didact-explain#1-%E6%B8%B2%E6%9F%93dom%E5%85%83%E7%B4%A0)               |\n| [Element creation and JSX](https://medium.com/hexacta-engineering/didact-element-creation-and-jsx-d05171c55c56)                                        | [codepen](https://codepen.io/pomber/pen/xdmoWE?editors=0010) |                                                                                           [diff](https://github.com/hexacta/didact/commit/15010f8e7b8b54841d1e2dd9eacf7b3c06b1a24b)                                                                                           |          [中文](https://github.com/chinanf-boy/didact-explain#2-%E5%85%83%E7%B4%A0%E5%88%9B%E5%BB%BA%E5%92%8Cjsx)           |\n| [Virtual DOM and reconciliation](https://medium.com/hexacta-engineering/didact-instances-reconciliation-and-virtual-dom-9316d650f1d0)                  | [codepen](https://codepen.io/pomber/pen/WjLqYW?editors=0010) | [diff](https://github.com/hexacta/didact/commit/8eb7ffd6f5e210526fb4c274c4f60d609fe2f810) [diff](https://github.com/hexacta/didact/commit/6f5fdb7331ed77ba497fa5917d920eafe1f4c8dc) [diff](https://github.com/hexacta/didact/commit/35619a039d48171a6e6c53bd433ed049f2d718cb) | [中文](https://github.com/chinanf-boy/didact-explain#3-%E5%AE%9E%E4%BE%8B-%E5%AF%B9%E6%AF%94%E5%92%8C%E8%99%9A%E6%8B%9Fdom) |\n| [Components and State](https://medium.com/hexacta-engineering/didact-components-and-state-53ab4c900e37)                                                |       [codepen](https://codepen.io/pomber/pen/RVqBrx)        |                                                                                           [diff](https://github.com/hexacta/didact/commit/2e290ff5c486b8a3f361abcbc6e36e2c21db30b8)                                                                                           |            [中文](https://github.com/chinanf-boy/didact-explain#4-%E7%BB%84%E4%BB%B6%E5%92%8C%E7%8A%B6%E6%80%81)            |\n| [Fiber: Incremental reconciliation](https://medium.com/hexacta-engineering/didact-fiber-incremental-reconciliation-b2fe028dcaec) (self-contained post) |       [codepen](https://codepen.io/pomber/pen/veVOdd)        |                                              [diff](https://github.com/hexacta/didact/commit/6174a2289e69895acd8fc85abdc3aaff1ded9011) [diff](https://github.com/hexacta/didact/commit/accafb81e116a0569f8b7d70e5b233e14af999ad)                                              |             [中文](https://github.com/chinanf-boy/didact-explain#5-fibre-%E9%80%92%E5%A2%9E%E5%AF%B9%E6%AF%94)              |\n| [The one with Hooks](https://pomb.us/build-your-own-react) (self-contained post)                                                                |    [codesandbox](https://codesandbox.io/s/didact-8-21ost)    |                                                                                                                                                                                                                                                                               |  [中文](https://www.tangdingblog.cn/blog/react/buildyourownreact-2020-09-22/)                                                                                                                         |\n\n> Follow [@pomber](https://twitter.com/pomber) on twitter for updates.\n\n## License\n\nThe MIT License (MIT)\n"
  }
]