Full Code of yesmeck/react-with-hooks for AI

master e1ff16b19016 cached
33 files
179.8 KB
44.5k tokens
146 symbols
1 requests
Download .txt
Repository: yesmeck/react-with-hooks
Branch: master
Commit: e1ff16b19016
Files: 33
Total size: 179.8 KB

Directory structure:
gitextract_5sudl4xz/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── babel.config.js
├── index.d.ts
├── package.json
├── polyfill.js
├── scripts/
│   ├── alertFlag.sh
│   └── jest/
│       ├── matchers/
│       │   └── toWarnDev.js
│       ├── setupTests.js
│       └── shouldIgnoreConsoleError.js
├── src/
│   ├── ReactCurrentDispatcher.js
│   ├── ReactHookEffectTags.js
│   ├── ReactHooks.js
│   ├── ReactSideEffectTags.js
│   ├── __mocks__/
│   │   └── scheduleCallback.js
│   ├── index.js
│   ├── objectIs.js
│   ├── polyfill.js
│   ├── scheduleCallback.js
│   └── withHooks.js
├── tests/
│   ├── ReactHooksWithNoopRenderer.test.js
│   └── ReactHooksWithReactDOM.test.js
└── vendors/
    └── react-noop-renderer/
        ├── LICENSE
        ├── README.md
        ├── cjs/
        │   ├── react-noop-renderer-persistent.development.js
        │   ├── react-noop-renderer-server.development.js
        │   └── react-noop-renderer.development.js
        ├── index.js
        ├── package.json
        ├── persistent.js
        └── server.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/node_modules
/lib
/coverage
/yarn.lock
/yarn-error.log


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
  - stable
script:
  - npm test -- --coverage
  - bash <(curl -s https://codecov.io/bash)



================================================
FILE: LICENSE
================================================
The MIT License

Copyright (c) 2018-present Wei Zhu <yesmeck@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: README.md
================================================
# react-with-hooks

[![Build Status](https://img.shields.io/travis/yesmeck/react-with-hooks.svg?style=flat-square)](https://travis-ci.org/yesmeck/react-with-hooks)
![codecov](https://img.shields.io/codecov/c/github/yesmeck/react-with-hooks.svg?style=flat-square)

Polyfill and ponyfill for the [React Hooks API](https://reactjs.org/docs/hooks-intro.html).

Works on React Native!

⚠️The code on master branch is still WIP.

## Install

```bash
$ npm i react-with-hooks --save
```

## Usage

You can use `react-with-hooks` as a polyfill; in this case, when you later transition to native React Hooks you will only need to remove the `import 'react-with-hooks/polyfill'` statement:

```javascript
import 'react-with-hooks/polyfill'; // import the polyfill in the entry of your application
import React, { useState, useEffect } from 'react';

const Counter = () => {
  const [ count, setCount ] = useState(0);
  useEffect(() => {
    document.title = "count is " + count;
  })
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
};
```

Alternatively, you can use this library as a ponyfill with the `withHooks` helper. In this case, you will have to refactor your code later when you transition to use native React Hooks.

```javascript
import React from 'react';
import withHooks, { useState, useEffect } from 'react-with-hooks';

const Counter = withHooks(() => {
  const [ count, setCount ] = useState(0);
  useEffect(() => {
    document.title = "count is " + count;
  })
  return (
    <div>
      {count}
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
});
```

[Live Demo](https://codesandbox.io/s/olx6zp44n6)

## API Reference

- Basic Hooks
  - [useState](https://reactjs.org/docs/hooks-reference.html#usestate)
  - [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect)
  - [useContext](https://reactjs.org/docs/hooks-reference.html#usecontext)
- Additional Hooks
  - [useReducer](https://reactjs.org/docs/hooks-reference.html#usereducer)
  - [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)
  - [useMemo](https://reactjs.org/docs/hooks-reference.html#usememo)
  - [useRef](https://reactjs.org/docs/hooks-reference.html#useref)
  - [useImperativeHandle](https://reactjs.org/docs/hooks-reference.html#useimperativehandle)
  - [useLayoutEffect](https://reactjs.org/docs/hooks-reference.html#uselayouteffect)


## License

[MIT](./LICENSE)


================================================
FILE: babel.config.js
================================================
module.exports = {
  presets: ['@babel/preset-env', '@babel/preset-react'],
  plugins: [
    '@babel/plugin-proposal-class-properties'
  ]
};


================================================
FILE: index.d.ts
================================================
import * as React from 'react';

type WithHooks = <T>(component: React.SFC<T>) => React.SFC<T>;

declare function useContext<T>(context: React.Context<T>): T;
declare function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>];
declare function useReducer<S, A>(
  reducer: React.Reducer<S, A>,
  initialState: S,
  initialAction?: A | null,
): [S, React.Dispatch<A>];
declare function useRef<T>(initialValue: T): React.MutableRefObject<T>;
declare function useRef<T>(initialValue: T | null): React.RefObject<T>;
declare function useMutationEffect(effect: React.EffectCallback, inputs?: React.InputIdentityList): void;
declare function useLayoutEffect(effect: React.EffectCallback, inputs?: React.InputIdentityList): void;
declare function useEffect(effect: React.EffectCallback, inputs?: React.InputIdentityList): void;
declare function useImperativeHandle<T, R extends T>(
  ref: React.Ref<T> | undefined,
  init: () => R,
  inputs?: React.InputIdentityList,
): void;
declare function useCallback<T extends (...args: any[]) => any>(callback: T, inputs: React.InputIdentityList): T;
declare function useMemo<T>(factory: () => T, inputs: React.InputIdentityList): T;

declare var withHooks: WithHooks;

export {
  useContext,
  useState,
  useReducer,
  useRef,
  useMutationEffect,
  useLayoutEffect,
  useEffect,
  useImperativeHandle,
  useCallback,
  useMemo,
}
export default withHooks;


================================================
FILE: package.json
================================================
{
  "name": "react-with-hooks",
  "version": "1.1.6",
  "description": "react hooks polyfill",
  "main": "lib/index.js",
  "files": [
    "lib",
    "index.d.ts",
    "polyfill.js"
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/yesmeck/react-with-hooks"
  },
  "bugs": {
    "url": "https://github.com/yesmeck/react-with-hooks/issues"
  },
  "keywords": [
    "react",
    "hooks"
  ],
  "author": "yesmeck <yesmeck@gmail.com>",
  "license": "MIT",
  "scripts": {
    "test": "NODE_ENV=development jest",
    "build": "babel src -d lib",
    "prepack": "npm run build",
    "postinstall": "./scripts/alertFlag.sh"
  },
  "jest": {
    "setupFilesAfterEnv": [
      "<rootDir>scripts/jest/setupTests.js"
    ],
    "collectCoverageFrom": [
      "src/**/*.js"
    ]
  },
  "typings": "index.d.ts",
  "devDependencies": {
    "@babel/cli": "^7.1.2",
    "@babel/core": "^7.1.2",
    "@babel/plugin-proposal-class-properties": "^7.1.0",
    "@babel/preset-env": "^7.1.0",
    "@babel/preset-react": "^7.0.0",
    "babel-jest": "^24.0.0",
    "chalk": "^2.4.2",
    "jest": "^24.0.0",
    "jest-diff": "^24.0.0",
    "jest-dom": "^3.1.1",
    "react": "^16.8.1",
    "react-dom": "^16.8.1",
    "react-reconciler": "^0.19.1",
    "react-testing-library": "^5.8.0",
    "regenerator-runtime": "^0.12.1"
  },
  "dependencies": {
    "invariant": "^2.2.4",
    "react-is": "^16.8.1"
  }
}


================================================
FILE: polyfill.js
================================================
module.exports = require('./lib/polyfill');


================================================
FILE: scripts/alertFlag.sh
================================================
#!/bin/sh

 perl -i -pe's/var debugRenderPhaseSideEffectsForStrictMode = true;/var debugRenderPhaseSideEffectsForStrictMode = false;/'  node_modules/react-reconciler/cjs/react-reconciler.development.js


================================================
FILE: scripts/jest/matchers/toWarnDev.js
================================================
'use strict';

const jestDiff = require('jest-diff');
const util = require('util');
const shouldIgnoreConsoleError = require('../shouldIgnoreConsoleError');

function normalizeCodeLocInfo(str) {
  return str && str.replace(/at .+?:\d+/g, 'at **');
}

const createMatcherFor = consoleMethod =>
  function matcher(callback, expectedMessages, options = {}) {
    if (__DEV__) {
      // Warn about incorrect usage of matcher.
      if (typeof expectedMessages === 'string') {
        expectedMessages = [expectedMessages];
      } else if (!Array.isArray(expectedMessages)) {
        throw Error(
          `toWarnDev() requires a parameter of type string or an array of strings ` +
            `but was given ${typeof expectedMessages}.`
        );
      }
      if (
        options != null &&
        (typeof options !== 'object' || Array.isArray(options))
      ) {
        throw new Error(
          'toWarnDev() second argument, when present, should be an object. ' +
            'Did you forget to wrap the messages into an array?'
        );
      }
      if (arguments.length > 3) {
        // `matcher` comes from Jest, so it's more than 2 in practice
        throw new Error(
          'toWarnDev() received more than two arguments. ' +
            'Did you forget to wrap the messages into an array?'
        );
      }

      const withoutStack = options.withoutStack;
      const warningsWithoutComponentStack = [];
      const warningsWithComponentStack = [];
      const unexpectedWarnings = [];

      let lastWarningWithMismatchingFormat = null;
      let lastWarningWithExtraComponentStack = null;

      // Catch errors thrown by the callback,
      // But only rethrow them if all test expectations have been satisfied.
      // Otherwise an Error in the callback can mask a failed expectation,
      // and result in a test that passes when it shouldn't.
      let caughtError;

      const isLikelyAComponentStack = message =>
        typeof message === 'string' && message.includes('\n    in ');

      const consoleSpy = (format, ...args) => {
        // Ignore uncaught errors reported by jsdom
        // and React addendums because they're too noisy.
        if (
          consoleMethod === 'error' &&
          shouldIgnoreConsoleError(format, args)
        ) {
          return;
        }

        const message = util.format(format, ...args);
        const normalizedMessage = normalizeCodeLocInfo(message);

        // Remember if the number of %s interpolations
        // doesn't match the number of arguments.
        // We'll fail the test if it happens.
        let argIndex = 0;
        format.replace(/%s/g, () => argIndex++);
        if (argIndex !== args.length) {
          lastWarningWithMismatchingFormat = {
            format,
            args,
            expectedArgCount: argIndex,
          };
        }

        // Protect against accidentally passing a component stack
        // to warning() which already injects the component stack.
        if (
          args.length >= 2 &&
          isLikelyAComponentStack(args[args.length - 1]) &&
          isLikelyAComponentStack(args[args.length - 2])
        ) {
          lastWarningWithExtraComponentStack = {
            format,
          };
        }

        for (let index = 0; index < expectedMessages.length; index++) {
          const expectedMessage = expectedMessages[index];
          if (
            normalizedMessage === expectedMessage ||
            normalizedMessage.includes(expectedMessage)
          ) {
            if (isLikelyAComponentStack(normalizedMessage)) {
              warningsWithComponentStack.push(normalizedMessage);
            } else {
              warningsWithoutComponentStack.push(normalizedMessage);
            }
            expectedMessages.splice(index, 1);
            return;
          }
        }

        let errorMessage;
        if (expectedMessages.length === 0) {
          errorMessage =
            'Unexpected warning recorded: ' +
            this.utils.printReceived(normalizedMessage);
        } else if (expectedMessages.length === 1) {
          errorMessage =
            'Unexpected warning recorded: ' +
            jestDiff(expectedMessages[0], normalizedMessage);
        } else {
          errorMessage =
            'Unexpected warning recorded: ' +
            jestDiff(expectedMessages, [normalizedMessage]);
        }

        // Record the call stack for unexpected warnings.
        // We don't throw an Error here though,
        // Because it might be suppressed by ReactFiberScheduler.
        unexpectedWarnings.push(new Error(errorMessage));
      };

      // TODO Decide whether we need to support nested toWarn* expectations.
      // If we don't need it, add a check here to see if this is already our spy,
      // And throw an error.
      const originalMethod = console[consoleMethod];

      // Avoid using Jest's built-in spy since it can't be removed.
      console[consoleMethod] = consoleSpy;

      try {
        callback();
      } catch (error) {
        caughtError = error;
      } finally {
        // Restore the unspied method so that unexpected errors fail tests.
        console[consoleMethod] = originalMethod;

        // Any unexpected Errors thrown by the callback should fail the test.
        // This should take precedence since unexpected errors could block warnings.
        if (caughtError) {
          throw caughtError;
        }

        // Any unexpected warnings should be treated as a failure.
        if (unexpectedWarnings.length > 0) {
          return {
            message: () => unexpectedWarnings[0].stack,
            pass: false,
          };
        }

        // Any remaining messages indicate a failed expectations.
        if (expectedMessages.length > 0) {
          return {
            message: () =>
              `Expected warning was not recorded:\n  ${this.utils.printReceived(
                expectedMessages[0]
              )}`,
            pass: false,
          };
        }

        if (typeof withoutStack === 'number') {
          // We're expecting a particular number of warnings without stacks.
          if (withoutStack !== warningsWithoutComponentStack.length) {
            return {
              message: () =>
                `Expected ${withoutStack} warnings without a component stack but received ${
                  warningsWithoutComponentStack.length
                }:\n` +
                warningsWithoutComponentStack.map(warning =>
                  this.utils.printReceived(warning)
                ),
              pass: false,
            };
          }
        } else if (withoutStack === true) {
          // We're expecting that all warnings won't have the stack.
          // If some warnings have it, it's an error.
          if (warningsWithComponentStack.length > 0) {
            return {
              message: () =>
                `Received warning unexpectedly includes a component stack:\n  ${this.utils.printReceived(
                  warningsWithComponentStack[0]
                )}\nIf this warning intentionally includes the component stack, remove ` +
                `{withoutStack: true} from the toWarnDev() call. If you have a mix of ` +
                `warnings with and without stack in one toWarnDev() call, pass ` +
                `{withoutStack: N} where N is the number of warnings without stacks.`,
              pass: false,
            };
          }
        } else if (withoutStack === false || withoutStack === undefined) {
          // We're expecting that all warnings *do* have the stack (default).
          // If some warnings don't have it, it's an error.
          if (warningsWithoutComponentStack.length > 0) {
            return {
              message: () =>
                `Received warning unexpectedly does not include a component stack:\n  ${this.utils.printReceived(
                  warningsWithoutComponentStack[0]
                )}\nIf this warning intentionally omits the component stack, add ` +
                `{withoutStack: true} to the toWarnDev() call.`,
              pass: false,
            };
          }
        } else {
          throw Error(
            `The second argument for toWarnDev(), when specified, must be an object. It may have a ` +
              `property called "withoutStack" whose value may be undefined, boolean, or a number. ` +
              `Instead received ${typeof withoutStack}.`
          );
        }

        if (lastWarningWithMismatchingFormat !== null) {
          return {
            message: () =>
              `Received ${
                lastWarningWithMismatchingFormat.args.length
              } arguments for a message with ${
                lastWarningWithMismatchingFormat.expectedArgCount
              } placeholders:\n  ${this.utils.printReceived(
                lastWarningWithMismatchingFormat.format
              )}`,
            pass: false,
          };
        }

        if (lastWarningWithExtraComponentStack !== null) {
          return {
            message: () =>
              `Received more than one component stack for a warning:\n  ${this.utils.printReceived(
                lastWarningWithExtraComponentStack.format
              )}\nDid you accidentally pass a stack to warning() as the last argument? ` +
              `Don't forget warning() already injects the component stack automatically.`,
            pass: false,
          };
        }

        return {pass: true};
      }
    } else {
      // Any uncaught errors or warnings should fail tests in production mode.
      callback();

      return {pass: true};
    }
  };

module.exports = {
  toLowPriorityWarnDev: createMatcherFor('warn'),
  toWarnDev: createMatcherFor('error'),
};


================================================
FILE: scripts/jest/setupTests.js
================================================
'use strict';

const chalk = require('chalk');
const util = require('util');
const shouldIgnoreConsoleError = require('./shouldIgnoreConsoleError');
const env = jasmine.getEnv();

const NODE_ENV = process.env.NODE_ENV;
if (NODE_ENV !== 'development' && NODE_ENV !== 'production') {
  throw new Error('NODE_ENV must either be set to development or production.');
}
global.__DEV__ = NODE_ENV === 'development';

const expect = global.expect;

expect.extend({
  ...require('./matchers/toWarnDev'),
});

['error', 'warn'].forEach(methodName => {
  const unexpectedConsoleCallStacks = [];
  const newMethod = function(format, ...args) {
    // Ignore uncaught errors reported by jsdom
    // and React addendums because they're too noisy.
    if (methodName === 'error' && shouldIgnoreConsoleError(format, args)) {
      return;
    }

    // Capture the call stack now so we can warn about it later.
    // The call stack has helpful information for the test author.
    // Don't throw yet though b'c it might be accidentally caught and suppressed.
    const stack = new Error().stack;
    unexpectedConsoleCallStacks.push([stack.substr(stack.indexOf('\n') + 1), util.format(format, ...args)]);
  };

  console[methodName] = newMethod;

  env.beforeEach(() => {
    unexpectedConsoleCallStacks.length = 0;
  });

  env.afterEach(() => {
    if (console[methodName] !== newMethod && !isSpy(console[methodName])) {
      throw new Error(`Test did not tear down console.${methodName} mock properly.`);
    }

    if (unexpectedConsoleCallStacks.length > 0) {
      const messages = unexpectedConsoleCallStacks.map(
        ([stack, message]) =>
          `${chalk.red(message)}\n` +
          `${stack
            .split('\n')
            .map(line => chalk.gray(line))
            .join('\n')}`,
      );

      const message =
        `Expected test not to call ${chalk.bold(`console.${methodName}()`)}.\n\n` +
        'If the warning is expected, test for it explicitly by:\n' +
        `1. Using the ${chalk.bold('.toWarnDev()')} / ${chalk.bold('.toLowPriorityWarnDev()')} matchers, or...\n` +
        `2. Mock it out using ${chalk.bold('spyOnDev')}(console, '${methodName}') or ${chalk.bold(
          'spyOnProd',
        )}(console, '${methodName}'), and test that the warning occurs.`;

      throw new Error(`${message}\n\n${messages.join('\n\n')}`);
    }
  });
});


================================================
FILE: scripts/jest/shouldIgnoreConsoleError.js
================================================
'use strict';

module.exports = function shouldIgnoreConsoleError(format, args) {
  if (__DEV__) {
    if (typeof format === 'string') {
      if (format.indexOf('Error: Uncaught [') === 0) {
        // This looks like an uncaught error from invokeGuardedCallback() wrapper
        // in development that is reported by jsdom. Ignore because it's noisy.
        return true;
      }
      if (format.indexOf('The above error occurred') === 0) {
        // This looks like an error addendum from ReactFiberErrorLogger.
        // Ignore it too.
        return true;
      }
    }
  } else {
    if (
      format != null &&
      typeof format.message === 'string' &&
      typeof format.stack === 'string' &&
      args.length === 0
    ) {
      // In production, ReactFiberErrorLogger logs error objects directly.
      // They are noisy too so we'll try to ignore them.
      return true;
    }
  }
  // Looks legit
  return false;
};


================================================
FILE: src/ReactCurrentDispatcher.js
================================================
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

/**
 * Keeps track of the current dispatcher.
 */
const ReactCurrentDispatcher = {
  /**
   * @internal
   * @type {ReactComponent}
   */
  current: null,
};

export default ReactCurrentDispatcher;


================================================
FILE: src/ReactHookEffectTags.js
================================================
export const NoEffect = /*             */ 0b00000000;
export const UnmountSnapshot = /*      */ 0b00000010;
export const UnmountMutation = /*      */ 0b00000100;
export const MountMutation = /*        */ 0b00001000;
export const UnmountLayout = /*        */ 0b00010000;
export const MountLayout = /*          */ 0b00100000;
export const MountPassive = /*         */ 0b01000000;
export const UnmountPassive = /*       */ 0b10000000;


================================================
FILE: src/ReactHooks.js
================================================
/**
 * Copyright (c) 2013-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

import invariant from 'invariant';

import ReactCurrentDispatcher from './ReactCurrentDispatcher';

function resolveDispatcher() {
  const dispatcher = ReactCurrentDispatcher.current;
  invariant(
    dispatcher !== null,
    'Hooks can only be called inside the body of a function component. ' +
      '(https://fb.me/react-invalid-hook-call)',
  );
  return dispatcher;
}

export function useContext(
  context,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useContext(context);
}

export function useState(initialState) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useState(initialState);
}

export function useReducer(
  reducer,
  initialArg,
  init,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useReducer(reducer, initialArg, init);
}

export function useRef(initialValue) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useRef(initialValue);
}

export function useEffect(
  create,
  inputs,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useEffect(create, inputs);
}

export function useLayoutEffect(
  create,
  inputs,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useLayoutEffect(create, inputs);
}

export function useCallback(
  callback,
  inputs,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useCallback(callback, inputs);
}

export function useMemo(
  create,
  inputs,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useMemo(create, inputs);
}

export function useImperativeHandle(
  ref,
  create,
  inputs,
) {
  const dispatcher = resolveDispatcher();
  return dispatcher.useImperativeHandle(ref, create, inputs);
}


================================================
FILE: src/ReactSideEffectTags.js
================================================
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

// Don't change these two values. They're used by React Dev Tools.
export const NoEffect = /*              */ 0b000000000000;
export const PerformedWork = /*         */ 0b000000000001;

// You can change the rest (and add more).
export const Placement = /*             */ 0b000000000010;
export const Update = /*                */ 0b000000000100;
export const PlacementAndUpdate = /*    */ 0b000000000110;
export const Deletion = /*              */ 0b000000001000;
export const ContentReset = /*          */ 0b000000010000;
export const Callback = /*              */ 0b000000100000;
export const DidCapture = /*            */ 0b000001000000;
export const Ref = /*                   */ 0b000010000000;
export const Snapshot = /*              */ 0b000100000000;
export const Passive = /*               */ 0b001000000000;

// Passive & Update & Callback & Ref & Snapshot
export const LifecycleEffectMask = /*   */ 0b001110100100;

// Union of all host effects
export const HostEffectMask = /*        */ 0b001111111111;

export const Incomplete = /*            */ 0b010000000000;
export const ShouldCapture = /*         */ 0b100000000000;


================================================
FILE: src/__mocks__/scheduleCallback.js
================================================
let pendingWorks = [];

const scheduleCallback = callback => {
  pendingWorks.push(callback);
  return () => {
    pendingWorks = pendingWorks.filter(cb => cb === callback);
  };
};

scheduleCallback.flush = () => {
  let work = pendingWorks.shift();
  while (work !== undefined) {
    work();
    work = pendingWorks.shift();
  }
};

export default scheduleCallback;


================================================
FILE: src/index.js
================================================
import React from 'react';
import withHooks from './withHooks';
import * as hooks from './ReactHooks';

const useNative = !!React.useState;

export const useState = useNative ? React.useState : hooks.useState;
export const useEffect = useNative ? React.useEffect : hooks.useEffect;
export const useContext = useNative ? React.useContext : hooks.useContext;
export const useReducer = useNative ? React.useReducer : hooks.useReducer;
export const useCallback = useNative ? React.useCallback : hooks.useCallback;
export const useMemo = useNative ? React.useMemo : hooks.useMemo;
export const useRef = useNative ? React.useRef : hooks.useRef;
export const useImperativeHandle = useNative ? React.useImperativeHandle : hooks.useImperativeHandle;
export const useMutationEffect = useNative ? React.useMutationEffect : hooks.useMutationEffect;
export const useLayoutEffect = useNative ? React.useLayoutEffect : hooks.useLayoutEffect;
export default useNative ? (fn) => fn : withHooks;


================================================
FILE: src/objectIs.js
================================================
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

/**
 * inlined Object.is polyfill to avoid requiring consumers ship their own
 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
 */
function is(x, y) {
  return (
    (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
  );
}

export default is;


================================================
FILE: src/polyfill.js
================================================
import React from 'react';
import * as ReactIs from 'react-is';
import withHooks from './withHooks';
import * as hooks from './ReactHooks';

const useNative = __DEV__ ? false : !!React.useState;

const nativeCreateElement = React.createElement;

function shouldConstruct(Component) {
  const prototype = Component.prototype;
  return !!(prototype && prototype.isReactComponent);
}

function isSimpleFunctionComponent(type) {
  return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined;
}

function hasHooks(fn) {
  return /\buse[A-Z0-9]/.test(fn.toString());
}

const createElementWithHooks = (() => {
  const componentMap = new Map();
  return (component, props, ...children) => {
    if (componentMap.has(component)) {
      return nativeCreateElement(componentMap.get(component), props, ...children);
    }
    const element = nativeCreateElement(component, props, ...children);
    let wrappedComponent = component;
    let render;
    if (ReactIs.isForwardRef(element)) {
      render = component.render;
      wrappedComponent.render = withHooks(render);
      componentMap.set(component, wrappedComponent);
    }
    if (ReactIs.isMemo(component)) {
      render = component.type;
      wrappedComponent.type = withHooks(render);
      componentMap.set(component, wrappedComponent);
    }
    if (isSimpleFunctionComponent(component) && component.__react_with_hooks !== true) {
      render = component;
      wrappedComponent = withHooks(render);
      componentMap.set(component, wrappedComponent);
    }
    if (!render || !hasHooks(render)) {
      return element;
    }
    return nativeCreateElement(wrappedComponent, props, ...children);
  };
})();

React.createElement = useNative ? React.createElement : createElementWithHooks;

if (!useNative) {
  Object.keys(hooks).forEach(hook => {
    React[hook] = hooks[hook];
  });
}


================================================
FILE: src/scheduleCallback.js
================================================
export default function scheduleCallback(callback) {
  const timer = requestAnimationFrame(callback);
  return () => {
    cancelAnimationFrame(timer);
  };
}


================================================
FILE: src/withHooks.js
================================================
import React, { createElement } from 'react';
import invariant from 'invariant';
import ReactCurrentDispatcher from './ReactCurrentDispatcher';
import { Update as UpdateEffect, Passive as PassiveEffect } from './ReactSideEffectTags';
import {
  NoEffect as NoHookEffect,
  UnmountMutation,
  MountLayout,
  UnmountPassive,
  MountPassive,
  MountMutation,
  UnmountLayout,
} from './ReactHookEffectTags';
import is from './objectIs';
import scheduleCallback from './scheduleCallback';

const RE_RENDER_LIMIT = 25;

let firstCurrentHook = null;
let firstWorkInProgressHook = null;
let currentHook = null;
let nextCurrentHook = null;
let workInProgressHook = null;
let nextWorkInProgressHook = null;
let didScheduleRenderPhaseUpdate = false;
let currentInstance = null;
let renderPhaseUpdates = null;
let numberOfReRenders = 0;
let componentUpdateQueue = null;
let sideEffectTag = 0;
let componentContext = null;
let isRenderPhase = false;
let didReceiveUpdate = false;
let passiveHookEffects = [];

function markWorkInProgressReceivedUpdate() {
  didReceiveUpdate = true;
}

function basicStateReducer(state, action) {
  return typeof action === 'function' ? action(state) : action;
}

function prepareToUseHooks(current) {
  currentInstance = current;
  firstCurrentHook = nextCurrentHook = current !== null ? current.memoizedState : null;
}

function resetHooks() {
  currentInstance = null;
  firstCurrentHook = null;
  currentHook = null;
  firstWorkInProgressHook = null;
  workInProgressHook = null;
  componentUpdateQueue = null;
  componentContext = null;

  didScheduleRenderPhaseUpdate = false;
  renderPhaseUpdates = null;
  numberOfReRenders = 0;
  isRenderPhase = false;
}

function mountWorkInProgressHook() {
  const hook = {
    memoizedState: null,

    baseState: null,
    queue: null,
    baseUpdate: null,

    next: null,
  };

  if (workInProgressHook === null) {
    // This is the first hook in the list
    firstWorkInProgressHook = workInProgressHook = hook;
  } else {
    // Append to the end of the list
    workInProgressHook = workInProgressHook.next = hook;
  }
  return workInProgressHook;
}

function updateWorkInProgressHook() {
  // This function is used both for updates and for re-renders triggered by a
  // render phase update. It assumes there is either a current hook we can
  // clone, or a work-in-progress hook from a previous render pass that we can
  // use as a base. When we reach the end of the base list, we must switch to
  // the dispatcher used for mounts.
  if (nextWorkInProgressHook !== null) {
    // There's already a work-in-progress. Reuse it.
    workInProgressHook = nextWorkInProgressHook;
    nextWorkInProgressHook = workInProgressHook.next;

    currentHook = nextCurrentHook;
    nextCurrentHook = currentHook !== null ? currentHook.next : null;
  } else {
    // Clone from the current hook.
    invariant(nextCurrentHook !== null, 'Rendered more hooks than during the previous render.');
    currentHook = nextCurrentHook;

    const newHook = {
      memoizedState: currentHook.memoizedState,

      baseState: currentHook.baseState,
      queue: currentHook.queue,
      baseUpdate: currentHook.baseUpdate,

      next: null,
    };

    if (workInProgressHook === null) {
      // This is the first hook in the list.
      workInProgressHook = firstWorkInProgressHook = newHook;
    } else {
      // Append to the end of the list.
      workInProgressHook = workInProgressHook.next = newHook;
    }
    nextCurrentHook = currentHook.next;
  }
  return workInProgressHook;
}

function createFunctionComponentUpdateQueue() {
  return {
    lastEffect: null,
  };
}

function areHookInputsEqual(nextDeps, prevDeps) {
  if (prevDeps === null) {
    return false;
  }

  for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
    if (is(nextDeps[i], prevDeps[i])) {
      continue;
    }
    return false;
  }
  return true;
}

function mountState(initialState) {
  const hook = mountWorkInProgressHook();
  if (typeof initialState === 'function') {
    initialState = initialState();
  }
  hook.memoizedState = hook.baseState = initialState;
  const queue = (hook.queue = {
    last: null,
    dispatch: null,
    eagerReducer: basicStateReducer,
    eagerState: initialState,
  });
  const dispatch = (queue.dispatch = dispatchAction.bind(null, currentInstance, queue));
  return [hook.memoizedState, dispatch];
}

function updateState(initialState) {
  return updateReducer(basicStateReducer, initialState);
}

function pushEffect(tag, create, destroy, deps) {
  const effect = {
    tag,
    create,
    destroy,
    deps,
    // Circular
    next: null,
  };
  if (componentUpdateQueue === null) {
    componentUpdateQueue = createFunctionComponentUpdateQueue();
    componentUpdateQueue.lastEffect = effect.next = effect;
  } else {
    const lastEffect = componentUpdateQueue.lastEffect;
    if (lastEffect === null) {
      componentUpdateQueue.lastEffect = effect.next = effect;
    } else {
      const firstEffect = lastEffect.next;
      lastEffect.next = effect;
      effect.next = firstEffect;
      componentUpdateQueue.lastEffect = effect;
    }
  }
  return effect;
}

function pushContext(context) {
  const _context = {
    Consumer: context.Consumer,
    next: null,
  };
  if (componentContext === null) {
    componentContext = _context;
  } else {
    componentContext.next = _context;
  }
  return _context;
}

function mountRef(initialValue) {
  const hook = mountWorkInProgressHook();
  const ref = { current: initialValue };
  hook.memoizedState = ref;
  return ref;
}

function updateRef() {
  const hook = updateWorkInProgressHook();
  return hook.memoizedState;
}

function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  sideEffectTag |= fiberEffectTag;
  hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps);
}

function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  let destroy = undefined;

  if (currentHook !== null) {
    const prevEffect = currentHook.memoizedState;
    destroy = prevEffect.destroy;
    if (nextDeps !== null) {
      const prevDeps = prevEffect.deps;
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        pushEffect(NoHookEffect, create, destroy, nextDeps);
        return;
      }
    }
  }

  sideEffectTag |= fiberEffectTag;
  hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps);
}

function mountEffect(create, deps) {
  return mountEffectImpl(UpdateEffect | PassiveEffect, UnmountPassive | MountPassive, create, deps);
}

function updateEffect(create, deps) {
  return updateEffectImpl(UpdateEffect | PassiveEffect, UnmountPassive | MountPassive, create, deps);
}

function mountLayoutEffect(create, deps) {
  return mountEffectImpl(UpdateEffect, UnmountMutation | MountLayout, create, deps);
}

function updateLayoutEffect(create, deps) {
  return updateEffectImpl(UpdateEffect, UnmountMutation | MountLayout, create, deps);
}

function imperativeHandleEffect(create, ref) {
  if (typeof ref === 'function') {
    const refCallback = ref;
    const inst = create();
    refCallback(inst);
    return () => {
      refCallback(null);
    };
  } else if (ref !== null && ref !== undefined) {
    const refObject = ref;
    const inst = create();
    refObject.current = inst;
    return () => {
      refObject.current = null;
    };
  }
}

function mountImperativeHandle(ref, create, deps) {
  // TODO: If deps are provided, should we skip comparing the ref itself?
  const effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : [ref];

  return mountEffectImpl(
    UpdateEffect,
    UnmountMutation | MountLayout,
    imperativeHandleEffect.bind(null, create, ref),
    effectDeps,
  );
}

function updateImperativeHandle(ref, create, deps) {
  // TODO: If deps are provided, should we skip comparing the ref itself?
  const effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : [ref];

  return updateEffectImpl(
    UpdateEffect,
    UnmountMutation | MountLayout,
    imperativeHandleEffect.bind(null, create, ref),
    effectDeps,
  );
}

function mountContext(Context) {
  pushContext(Context);
  return Context._currentValue;
}

function mountReducer(reducer, initialArg, init) {
  const hook = mountWorkInProgressHook();
  let initialState;
  if (init !== undefined) {
    initialState = init(initialArg);
  } else {
    initialState = initialArg;
  }
  hook.memoizedState = hook.baseState = initialState;
  const queue = (hook.queue = {
    last: null,
    dispatch: null,
    eagerReducer: reducer,
    eagerState: initialState,
  });
  const dispatch = (queue.dispatch = dispatchAction.bind(
    null,
    // Flow doesn't know this is non-null, but we do.
    currentInstance,
    queue,
  ));
  return [hook.memoizedState, dispatch];
}

function updateReducer(reducer, initialArg, init) {
  const hook = updateWorkInProgressHook();
  const queue = hook.queue;
  invariant(queue !== null, 'Should have a queue. This is likely a bug in React. Please file an issue.');

  if (numberOfReRenders > 0) {
    // This is a re-render. Apply the new render phase updates to the previous
    // work-in-progress hook.
    const dispatch = queue.dispatch;
    if (renderPhaseUpdates !== null) {
      // Render phase updates are stored in a map of queue -> linked list
      const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
      if (firstRenderPhaseUpdate !== undefined) {
        renderPhaseUpdates.delete(queue);
        let newState = hook.memoizedState;
        let update = firstRenderPhaseUpdate;
        do {
          // Process this render phase update. We don't have to check the
          // priority because it will always be the same as the current
          // render's.
          const action = update.action;
          newState = reducer(newState, action);
          update = update.next;
        } while (update !== null);

        // Mark that the fiber performed work, but only if the new state is
        // different from the current state.
        if (!is(newState, hook.memoizedState)) {
          markWorkInProgressReceivedUpdate();
        }

        hook.memoizedState = newState;

        // Don't persist the state accumlated from the render phase updates to
        // the base state unless the queue is empty.
        // TODO: Not sure if this is the desired semantics, but it's what we
        // do for gDSFP. I can't remember why.
        if (hook.baseUpdate === queue.last) {
          hook.baseState = newState;
        }

        return [newState, dispatch];
      }
    }
    return [hook.memoizedState, dispatch];
  }

  // The last update in the entire queue
  const last = queue.last;
  // The last update that is part of the base state.
  const baseUpdate = hook.baseUpdate;
  const baseState = hook.baseState;

  // Find the first unprocessed update.
  let first;
  if (baseUpdate !== null) {
    if (last !== null) {
      // For the first update, the queue is a circular linked list where
      // `queue.last.next = queue.first`. Once the first update commits, and
      // the `baseUpdate` is no longer empty, we can unravel the list.
      last.next = null;
    }
    first = baseUpdate.next;
  } else {
    first = last !== null ? last.next : null;
  }
  if (first !== null) {
    let newState = baseState;
    let newBaseState = null;
    let newBaseUpdate = null;
    let prevUpdate = baseUpdate;
    let update = first;
    let didSkip = false;

    do {
      // Process this update.
      if (update.eagerReducer === reducer) {
        // If this update was processed eagerly, and its reducer matches the
        // current reducer, we can use the eagerly computed state.
        newState = update.eagerState;
      } else {
        const action = update.action;
        newState = reducer(newState, action);
      }
      prevUpdate = update;
      update = update.next;
    } while (update !== null && update !== first);

    if (!didSkip) {
      newBaseUpdate = prevUpdate;
      newBaseState = newState;
    }

    // Mark that the fiber performed work, but only if the new state is
    // different from the current state.
    if (!is(newState, hook.memoizedState)) {
      markWorkInProgressReceivedUpdate();
    }

    hook.memoizedState = newState;
    hook.baseUpdate = newBaseUpdate;
    hook.baseState = newBaseState;

    queue.eagerReducer = reducer;
    queue.eagerState = newState;
  }

  const dispatch = queue.dispatch;
  return [hook.memoizedState, dispatch];
}

function mountCallback(callback, deps) {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

function updateCallback(callback, deps) {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    if (nextDeps !== null) {
      const prevDeps = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  hook.memoizedState = [callback, nextDeps];
  return callback;
}

function mountMemo(nextCreate, deps) {
  const hook = mountWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}

function updateMemo(nextCreate, deps) {
  const hook = updateWorkInProgressHook();
  const nextDeps = deps === undefined ? null : deps;
  const prevState = hook.memoizedState;
  if (prevState !== null) {
    // Assume these are defined. If they're not, areHookInputsEqual will warn.
    if (nextDeps !== null) {
      const prevDeps = prevState[1];
      if (areHookInputsEqual(nextDeps, prevDeps)) {
        return prevState[0];
      }
    }
  }
  const nextValue = nextCreate();
  hook.memoizedState = [nextValue, nextDeps];
  return nextValue;
}

function flushPassiveEffects() {
  passiveHookEffects.forEach(effect => {
    effect.cancel();
    effect.callback();
  });
  passiveHookEffects = [];
}

function dispatchAction(instance, queue, action) {
  invariant(
    numberOfReRenders < RE_RENDER_LIMIT,
    'Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.',
  );
  if (isRenderPhase) {
    // This is a render phase update. Stash it in a lazily-created map of
    // queue -> linked list of updates. After this render pass, we'll restart
    // and apply the stashed updates on top of the work-in-progress hook.
    didScheduleRenderPhaseUpdate = true;
    const update = {
      action,
      next: null,
    };
    if (renderPhaseUpdates === null) {
      renderPhaseUpdates = new Map();
    }
    const firstRenderPhaseUpdate = renderPhaseUpdates.get(queue);
    if (firstRenderPhaseUpdate === undefined) {
      renderPhaseUpdates.set(queue, update);
    } else {
      // Append the update to the end of the list.
      let lastRenderPhaseUpdate = firstRenderPhaseUpdate;
      while (lastRenderPhaseUpdate.next !== null) {
        lastRenderPhaseUpdate = lastRenderPhaseUpdate.next;
      }
      lastRenderPhaseUpdate.next = update;
    }
  } else {
    flushPassiveEffects();

    const update = {
      action,
      next: null,
    };
    // Append the update to the end of the list.
    const last = queue.last;
    if (last === null) {
      // This is the first update. Create a circular list.
      update.next = update;
    } else {
      const first = last.next;
      if (first !== null) {
        // Still circular.
        update.next = first;
      }
      last.next = update;
    }
    queue.last = update;

    // The queue is currently empty, which means we can eagerly compute the
    // next state before entering the render phase. If the new state is the
    // same as the current state, we may be able to bail out entirely.
    // const eagerReducer = queue.eagerReducer;
    // if (eagerReducer !== null) {
    //   let prevDispatcher;
    //   try {
    //     const currentState = queue.eagerState;
    //     const eagerState = eagerReducer(currentState, action);
    //     // Stash the eagerly computed state, and the reducer used to compute
    //     // it, on the update object. If the reducer hasn't changed by the
    //     // time we enter the render phase, then the eager state can be used
    //     // without calling the reducer again.
    //     update.eagerReducer = eagerReducer;
    //     update.eagerState = eagerState;
    //     if (is(eagerState, currentState)) {
    //       // Fast path. We can bail out without scheduling React to re-render.
    //       // It's still possible that we'll need to rebase this update later,
    //       // if the component re-renders for a different reason and by that
    //       // time the reducer has changed.
    //       return;
    //     }
    //   } catch (error) {
    //     // Suppress the error. It will throw again in the render phase.
    //   }
    // }

    instance.setState({});
  }
}

const HooksDispatcherOnMount = {
  useCallback: mountCallback,
  useContext: mountContext,
  useEffect: mountEffect,
  useImperativeHandle: mountImperativeHandle,
  useLayoutEffect: mountLayoutEffect,
  useMemo: mountMemo,
  useReducer: mountReducer,
  useRef: mountRef,
  useState: mountState,
};

const HooksDispatcherOnUpdate = {
  useCallback: updateCallback,
  useContext: mountContext,
  useEffect: updateEffect,
  useImperativeHandle: updateImperativeHandle,
  useLayoutEffect: updateLayoutEffect,
  useMemo: updateMemo,
  useReducer: updateReducer,
  useRef: updateRef,
  useState: updateState,
};

export default function withHooks(render) {
  class WithHooks extends React.Component {
    memoizedState = null;
    passiveHookEffect = null;

    componentDidMount() {
      // useLayoutEffect
      this.commitHookEffectList(UnmountMutation, MountMutation);
      this.commitHookEffectList(UnmountLayout, MountLayout);

      // useEffect
      this.createPassiveHookEffect();
      this.mounted = true;
    }

    componentDidUpdate() {
      // useLayoutEffect
      this.commitHookEffectList(UnmountMutation, MountMutation);
      this.commitHookEffectList(UnmountLayout, MountLayout);

      // useEffect
      this.createPassiveHookEffect();
    }

    componentWillUnmount() {
      this.callDestroy();
    }

    createPassiveHookEffect() {
      const callback = this.commitPassiveHookEffects.bind(this);
      const cancel = scheduleCallback(callback);
      this.passiveHookEffect = {
        callback,
        cancel,
      };
      passiveHookEffects.push(this.passiveHookEffect);
    }

    commitPassiveHookEffects() {
      if (this.passiveHookEffect === null) {
        return;
      }
      passiveHookEffects = passiveHookEffects.filter(effect => effect !== this.passiveHookEffect);
      this.passiveHookEffect = null;
      this.commitHookEffectList(UnmountPassive, NoHookEffect);
      this.commitHookEffectList(NoHookEffect, MountPassive);
    }

    commitHookEffectList(unmountTag, mountTag) {
      let lastEffect = this.updateQueue !== null ? this.updateQueue.lastEffect : null;
      if (lastEffect !== null) {
        const firstEffect = lastEffect.next;
        let effect = firstEffect;
        do {
          if ((effect.tag & unmountTag) !== NoHookEffect) {
            // Unmount
            const destroy = effect.destroy;
            effect.destroy = undefined;
            if (destroy !== undefined) {
              destroy();
            }
          }
          effect = effect.next;
        } while (effect !== firstEffect);

        effect = firstEffect;
        do {
          if ((effect.tag & mountTag) !== NoHookEffect) {
            // Mount
            const create = effect.create;
            const destroy = create();
            effect.destroy = typeof destroy === 'function' ? destroy : undefined;
          }
          effect = effect.next;
        } while (effect !== firstEffect);
      }
    }

    callDestroy() {
      const updateQueue = this.updateQueue;

      if (updateQueue !== null) {
        var lastEffect = updateQueue.lastEffect;

        if (lastEffect !== null) {
          var firstEffect = lastEffect.next;
          var effect = firstEffect;

          do {
            var destroy = effect.destroy;

            if (destroy !== undefined) {
              destroy();
            }

            effect = effect.next;
          } while (effect !== firstEffect);
        }
      }
    }

    applyContext(render, context, children) {
      if (!children) {
        children = render();
      }
      context = context || componentContext;
      if (context !== null) {
        return createElement(context.Consumer, {}, () => {
          if (this.mounted) {
            children = render();
          }
          return context.next === null ? children : this.applyContext(render, context.next, children);
        });
      }
      return children;
    }

    render() {
      resetHooks();
      prepareToUseHooks(this);

      ReactCurrentDispatcher.current = nextCurrentHook === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate;

      const { _forwardedRef, ...rest } = this.props;

      isRenderPhase = true;

      let children = this.applyContext(() => render(rest, _forwardedRef));

      if (didScheduleRenderPhaseUpdate) {
        do {
          didScheduleRenderPhaseUpdate = false;
          numberOfReRenders += 1;

          // Start over from the beginning of the list
          firstCurrentHook = nextCurrentHook = this.memoizedState;
          nextWorkInProgressHook = firstWorkInProgressHook;

          currentHook = null;
          workInProgressHook = null;
          componentUpdateQueue = null;

          ReactCurrentDispatcher.current = HooksDispatcherOnUpdate;

          children = render(this.props, _forwardedRef);
        } while (didScheduleRenderPhaseUpdate);

        renderPhaseUpdates = null;
        numberOfReRenders = 0;
      }

      this.memoizedState = firstWorkInProgressHook;
      this.updateQueue = componentUpdateQueue;
      this.effectTag |= sideEffectTag;

      const didRenderTooFewHooks = currentHook !== null && currentHook.next !== null;

      currentInstance = null;

      firstCurrentHook = null;
      currentHook = null;
      nextCurrentHook = null;
      firstWorkInProgressHook = null;
      workInProgressHook = null;
      nextWorkInProgressHook = null;

      componentUpdateQueue = null;
      sideEffectTag = 0;
      isRenderPhase = false;

      // These were reset above
      // didScheduleRenderPhaseUpdate = false;
      // renderPhaseUpdates = null;
      // numberOfReRenders = 0;

      invariant(
        !didRenderTooFewHooks,
        'Rendered fewer hooks than expected. This may be caused by an accidental ' + 'early return statement.',
      );

      return children;
    }
  }
  WithHooks.displayName = render.displayName || render.name;
  const wrap = (props, ref) => <WithHooks {...props} _forwardedRef={ref} />;
  wrap.__react_with_hooks = true;
  wrap.displayName = `WithHooks(${WithHooks.displayName})`;
  return wrap;
}


================================================
FILE: tests/ReactHooksWithNoopRenderer.test.js
================================================

jest.mock('../src/scheduleCallback');

let React;
let ReactNoop;
let scheduleCallback;
let useState;
let useReducer;
let useEffect;
let useLayoutEffect;
let useCallback;
let useMemo;
let useRef;
let useContext;
let useImperativeHandle;
let forwardRef;
let createContext;
let memo;
let act;

describe('hooks', () => {
  function span(prop) {
    return { type: 'span', hidden: false, children: [], prop };
  }

  function Text(props) {
    ReactNoop.yield(props.text);
    return <span prop={props.text} />;
  }

  beforeEach(() => {
    jest.resetModules();

    require('../src/polyfill');
    React = require('react');
    ReactNoop = require('../vendors/react-noop-renderer');
    scheduleCallback = require('../src/scheduleCallback').default;
    const nativeFlushPassiveEffects = ReactNoop.flushPassiveEffects;
    ReactNoop.flushPassiveEffects = () => {
      scheduleCallback.flush();
      return nativeFlushPassiveEffects();
    };
    useState = React.useState;
    useReducer = React.useReducer;
    useEffect = React.useEffect;
    useLayoutEffect = React.useLayoutEffect;
    useCallback = React.useCallback;
    useMemo = React.useMemo;
    useRef = React.useRef;
    useContext = React.useContext;
    useImperativeHandle = React.useImperativeHandle;
    forwardRef = React.forwardRef;
    createContext = React.createContext;
    memo = React.memo;
    act = ReactNoop.act;
  });

  describe('useState', () => {
    it('simple mount and update', () => {
      function Counter(props, ref) {
        const [count, updateCount] = useState(0);
        useImperativeHandle(ref, () => ({ updateCount }));
        return <Text text={'Count: ' + count} />;
      }
      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      act(() => counter.current.updateCount(1));
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);

      act(() => counter.current.updateCount(count => count + 10));
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 11')]);
    });

    it('lazy state initializer', () => {
      function Counter(props, ref) {
        const [count, updateCount] = useState(() => {
          ReactNoop.yield('getInitialState');
          return props.initialState;
        });
        useImperativeHandle(ref, () => ({ updateCount }));
        return <Text text={'Count: ' + count} />;
      }
      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter initialState={42} ref={counter} />);
      expect(ReactNoop.flush()).toEqual(['getInitialState', 'Count: 42']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 42')]);

      act(() => counter.current.updateCount(7));
      expect(ReactNoop.flush()).toEqual(['Count: 7']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 7')]);
    });

    it('multiple states', () => {
      function Counter(props, ref) {
        const [count, updateCount] = useState(0);
        const [label, updateLabel] = useState('Count');
        useImperativeHandle(ref, () => ({ updateCount, updateLabel }));
        return <Text text={label + ': ' + count} />;
      }
      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      act(() => counter.current.updateCount(7));
      expect(ReactNoop.flush()).toEqual(['Count: 7']);

      act(() => counter.current.updateLabel('Total'));
      expect(ReactNoop.flush()).toEqual(['Total: 7']);
    });

    it('returns the same updater function every time', () => {
      let updaters = [];
      function Counter() {
        const [count, updateCount] = useState(0);
        updaters.push(updateCount);
        return <Text text={'Count: ' + count} />;
      }
      ReactNoop.render(<Counter />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      act(() => updaters[0](1));
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);

      act(() => updaters[0](count => count + 10));
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 11')]);

      expect(updaters).toEqual([updaters[0], updaters[0], updaters[0]]);
    });

    it('warns on set after unmount', () => {
      let _updateCount;
      function Counter(props, ref) {
        const [, updateCount] = useState(0);
        _updateCount = updateCount;
        return null;
      }

      ReactNoop.render(<Counter />);
      ReactNoop.flush();
      ReactNoop.render(null);
      ReactNoop.flush();
      expect(() => act(() => _updateCount(1))).toWarnDev(
        "Warning: Can't perform a React state update on an unmounted " +
          'component. This is a no-op, but it indicates a memory leak in your ' +
          'application. To fix, cancel all subscriptions and asynchronous ' +
          'tasks in the componentWillUnmount method.\n' +
          '    in Counter (created by WithHooks(Counter))\n' +
          '    in WithHooks(Counter)',
      );
    });

    it('works with memo', () => {
      let _updateCount;
      function Counter(props) {
        const [count, updateCount] = useState(0);
        _updateCount = updateCount;
        return <Text text={'Count: ' + count} />;
      }
      Counter = memo(Counter);

      ReactNoop.render(<Counter />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      ReactNoop.render(<Counter />);
      expect(ReactNoop.flush()).toEqual([]);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      act(() => _updateCount(1));
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
    });
  });

  describe('updates during the render phase', () => {
    it('restarts the render function and applies the new updates on top', () => {
      function ScrollView({ row: newRow }) {
        let [isScrollingDown, setIsScrollingDown] = useState(false);
        let [row, setRow] = useState(null);

        if (row !== newRow) {
          // Row changed since last render. Update isScrollingDown.
          setIsScrollingDown(row !== null && newRow > row);
          setRow(newRow);
        }

        return <Text text={`Scrolling down: ${isScrollingDown}`} />;
      }

      ReactNoop.render(<ScrollView row={1} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Scrolling down: false')]);

      ReactNoop.render(<ScrollView row={5} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Scrolling down: true')]);

      ReactNoop.render(<ScrollView row={5} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Scrolling down: true')]);

      ReactNoop.render(<ScrollView row={10} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Scrolling down: true')]);

      ReactNoop.render(<ScrollView row={2} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Scrolling down: false')]);

      ReactNoop.render(<ScrollView row={2} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Scrolling down: false')]);
    });

    it('keeps restarting until there are no more new updates', () => {
      function Counter({ row: newRow }) {
        let [count, setCount] = useState(0);
        if (count < 3) {
          setCount(count + 1);
        }
        ReactNoop.yield('Render: ' + count);
        return <Text text={count} />;
      }

      ReactNoop.render(<Counter />);
      expect(ReactNoop.flush()).toEqual(['Render: 0', 'Render: 1', 'Render: 2', 'Render: 3', 3]);
      expect(ReactNoop.getChildren()).toEqual([span(3)]);
    });

    it('updates multiple times within same render function', () => {
      function Counter({ row: newRow }) {
        let [count, setCount] = useState(0);
        if (count < 12) {
          setCount(c => c + 1);
          setCount(c => c + 1);
          setCount(c => c + 1);
        }
        ReactNoop.yield('Render: ' + count);
        return <Text text={count} />;
      }

      ReactNoop.render(<Counter />);
      expect(ReactNoop.flush()).toEqual([
        // Should increase by three each time
        'Render: 0',
        'Render: 3',
        'Render: 6',
        'Render: 9',
        'Render: 12',
        12,
      ]);
      expect(ReactNoop.getChildren()).toEqual([span(12)]);
    });

    it('throws after too many iterations', () => {
      function Counter({ row: newRow }) {
        let [count, setCount] = useState(0);
        setCount(count + 1);
        ReactNoop.yield('Render: ' + count);
        return <Text text={count} />;
      }
      ReactNoop.render(<Counter />);
      expect(() => ReactNoop.flush()).toThrow(
        'Too many re-renders. React limits the number of renders to prevent ' + 'an infinite loop.',
      );
    });

    it('works with useReducer', () => {
      function reducer(state, action) {
        return action === 'increment' ? state + 1 : state;
      }
      function Counter({ row: newRow }) {
        let [count, dispatch] = useReducer(reducer, 0);
        if (count < 3) {
          dispatch('increment');
        }
        ReactNoop.yield('Render: ' + count);
        return <Text text={count} />;
      }

      ReactNoop.render(<Counter />);
      expect(ReactNoop.flush()).toEqual(['Render: 0', 'Render: 1', 'Render: 2', 'Render: 3', 3]);
      expect(ReactNoop.getChildren()).toEqual([span(3)]);
    });

    it('uses reducer passed at time of render, not time of dispatch', () => {
      // This test is a bit contrived but it demonstrates a subtle edge case.

      // Reducer A increments by 1. Reducer B increments by 10.
      function reducerA(state, action) {
        switch (action) {
          case 'increment':
            return state + 1;
          case 'reset':
            return 0;
        }
      }
      function reducerB(state, action) {
        switch (action) {
          case 'increment':
            return state + 10;
          case 'reset':
            return 0;
        }
      }

      function Counter({ row: newRow }, ref) {
        let [reducer, setReducer] = useState(() => reducerA);
        let [count, dispatch] = useReducer(reducer, 0);
        useImperativeHandle(ref, () => ({ dispatch }));
        if (count < 20) {
          dispatch('increment');
          // Swap reducers each time we increment
          if (reducer === reducerA) {
            setReducer(() => reducerB);
          } else {
            setReducer(() => reducerA);
          }
        }
        ReactNoop.yield('Render: ' + count);
        return <Text text={count} />;
      }
      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);
      expect(ReactNoop.flush()).toEqual([
        // The count should increase by alternating amounts of 10 and 1
        // until we reach 21.
        'Render: 0',
        'Render: 10',
        'Render: 11',
        'Render: 21',
        21,
      ]);
      expect(ReactNoop.getChildren()).toEqual([span(21)]);

      // Test that it works on update, too. This time the log is a bit different
      // because we started with reducerB instead of reducerA.
      counter.current.dispatch('reset');
      ReactNoop.render(<Counter ref={counter} />);
      expect(ReactNoop.flush()).toEqual(['Render: 0', 'Render: 1', 'Render: 11', 'Render: 12', 'Render: 22', 22]);
      expect(ReactNoop.getChildren()).toEqual([span(22)]);
    });
  });

  describe('useReducer', () => {
    it('simple mount and update', () => {
      const INCREMENT = 'INCREMENT';
      const DECREMENT = 'DECREMENT';

      function reducer(state, action) {
        switch (action) {
          case 'INCREMENT':
            return state + 1;
          case 'DECREMENT':
            return state - 1;
          default:
            return state;
        }
      }

      function Counter(props, ref) {
        const [count, dispatch] = useReducer(reducer, 0);
        useImperativeHandle(ref, () => ({dispatch}));
        return <Text text={'Count: ' + count} />;
      }
      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      act(() => counter.current.dispatch(INCREMENT));
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);

      act(() => {
        counter.current.dispatch(DECREMENT);
        counter.current.dispatch(DECREMENT);
        counter.current.dispatch(DECREMENT);
      });

      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: -2')]);
    });

    it('lazy init', () => {
      const INCREMENT = 'INCREMENT';
      const DECREMENT = 'DECREMENT';

      function reducer(state, action) {
        switch (action) {
          case 'INCREMENT':
            return state + 1;
          case 'DECREMENT':
            return state - 1;
          default:
            return state;
        }
      }

      function Counter(props, ref) {
        const [count, dispatch] = useReducer(reducer, props, p => {
          ReactNoop.yield('Init');
          return p.initialCount;
        });
        useImperativeHandle(ref, () => ({dispatch}));
        return <Text text={'Count: ' + count} />;
      }
      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter initialCount={10} ref={counter} />);
      expect(ReactNoop.flush()).toEqual(['Init', 'Count: 10']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 10')]);

      act(() => counter.current.dispatch(INCREMENT));
      expect(ReactNoop.flush()).toEqual(['Count: 11']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 11')]);

      act(() => {
        counter.current.dispatch(DECREMENT);
        counter.current.dispatch(DECREMENT);
        counter.current.dispatch(DECREMENT);
      });

      expect(ReactNoop.flush()).toEqual(['Count: 8']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 8')]);
    });

    // Regression test for https://github.com/facebook/react/issues/14360
    it.skip('handles dispatches with mixed priorities', () => {
      const INCREMENT = 'INCREMENT';

      function reducer(state, action) {
        return action === INCREMENT ? state + 1 : state;
      }

      function Counter(props, ref) {
        const [count, dispatch] = useReducer(reducer, 0);
        useImperativeHandle(ref, () => ({dispatch}));
        return <Text text={'Count: ' + count} />;
      }

      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);

      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      act(() => {
        counter.current.dispatch(INCREMENT);
        counter.current.dispatch(INCREMENT);
        counter.current.dispatch(INCREMENT);
      });

      ReactNoop.flushSync(() => {
        counter.current.dispatch(INCREMENT);
      });
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);

      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 4')]);
    });
  });

  describe('useEffect', () => {
    it('simple mount and update', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Did commit [${props.count}]`);
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did commit [0]']);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      // Effects are deferred until after the commit
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did commit [1]']);
    });

    // tested in react-dom
    it.skip('flushes passive effects even with sibling deletions', () => {
      function LayoutEffect(props) {
        useLayoutEffect(() => {
          ReactNoop.yield(`Layout effect`);
        });
        return <Text text="Layout" />;
      }
      function PassiveEffect(props) {
        useEffect(() => {
          ReactNoop.yield(`Passive effect`);
        }, []);
        return <Text text="Passive" />;
      }
      let passive = <PassiveEffect key="p" />;
      ReactNoop.render([<LayoutEffect key="l" />, passive]);
      expect(ReactNoop.flush()).toEqual(['Layout', 'Passive', 'Layout effect']);
      expect(ReactNoop.getChildren()).toEqual([span('Layout'), span('Passive')]);

      // Destroying the first child shouldn't prevent the passive effect from
      // being executed
      ReactNoop.render([passive]);
      expect(ReactNoop.flush()).toEqual(['Passive effect']);
      expect(ReactNoop.getChildren()).toEqual([span('Passive')]);

      // (No effects are left to flush.)
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(null);
    });

    it.skip('flushes passive effects even if siblings schedule an update', () => {
      function PassiveEffect(props) {
        useEffect(() => {
          ReactNoop.yield('Passive effect');
        });
        return <Text text="Passive" />;
      }
      function LayoutEffect(props) {
        let [count, setCount] = useState(0);
        useLayoutEffect(() => {
          // Scheduling work shouldn't interfere with the queued passive effect
          if (count === 0) {
            setCount(1);
          }
          ReactNoop.yield('Layout effect ' + count);
        });
        return <Text text="Layout" />;
      }

      ReactNoop.render([<PassiveEffect key="p" />, <LayoutEffect key="l" />]);

      act(() => {
        expect(ReactNoop.flush()).toEqual([
          'Passive',
          'Layout',
          'Layout effect 0',
          'Passive effect',
          'Layout',
          'Layout effect 1',
        ]);
      });

      expect(ReactNoop.getChildren()).toEqual([span('Passive'), span('Layout')]);
    });

    it.skip('flushes passive effects even if siblings schedule a new root', () => {
      function PassiveEffect(props) {
        useEffect(() => {
          ReactNoop.yield('Passive effect');
        }, []);
        return <Text text="Passive" />;
      }
      function LayoutEffect(props) {
        useLayoutEffect(() => {
          ReactNoop.yield('Layout effect');
          // Scheduling work shouldn't interfere with the queued passive effect
          ReactNoop.renderToRootWithID(<Text text="New Root" />, 'root2');
        });
        return <Text text="Layout" />;
      }
      ReactNoop.render([<PassiveEffect key="p" />, <LayoutEffect key="l" />]);
      expect(ReactNoop.flush()).toEqual(['Passive', 'Layout', 'Layout effect', 'Passive effect', 'New Root']);
      expect(ReactNoop.getChildren()).toEqual([span('Passive'), span('Layout')]);
    });

    it(
      'flushes effects serially by flushing old effects before flushing ' + "new ones, if they haven't already fired",
      () => {
        function getCommittedText() {
          const children = ReactNoop.getChildren();
          if (children === null) {
            return null;
          }
          return children[0].prop;
        }

        function Counter(props) {
          useEffect(() => {
            ReactNoop.yield(`Committed state when effect was fired: ${getCommittedText()}`);
          });
          return <Text text={props.count} />;
        }
        ReactNoop.render(<Counter count={0} />);
        expect(ReactNoop.flush()).toEqual([0]);
        expect(ReactNoop.getChildren()).toEqual([span(0)]);

        // Before the effects have a chance to flush, schedule another update
        ReactNoop.render(<Counter count={1} />);
        expect(ReactNoop.flush()).toEqual([
          // The previous effect flushes before the reconciliation
          'Committed state when effect was fired: 0',
          1,
        ]);
        expect(ReactNoop.getChildren()).toEqual([span(1)]);

        ReactNoop.flushPassiveEffects();
        expect(ReactNoop.clearYields()).toEqual(['Committed state when effect was fired: 1']);
      },
    );

    it('updates have async priority', () => {
      function Counter(props) {
        const [count, updateCount] = useState('(empty)');
        useEffect(() => {
          ReactNoop.yield(`Schedule update [${props.count}]`);
          updateCount(props.count);
        }, [props.count]);
        return <Text text={'Count: ' + count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: (empty)']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Schedule update [0]']);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Schedule update [1]']);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
    });

    it.skip('updates have async priority even if effects are flushed early', () => {
      function Counter(props) {
        const [count, updateCount] = useState('(empty)');
        useEffect(() => {
          ReactNoop.yield(`Schedule update [${props.count}]`);
          updateCount(props.count);
        }, [props.count]);
        return <Text text={'Count: ' + count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: (empty)']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);

      // Rendering again should flush the previous commit's effects
      ReactNoop.render(<Counter count={1} />);
      ReactNoop.flushThrough(['Schedule update [0]', 'Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);

      ReactNoop.batchedUpdates(() => {
        expect(ReactNoop.flush()).toEqual([]);
      });

      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.flush()).toEqual(['Schedule update [1]', 'Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
    });

    it.skip('flushes serial effects before enqueueing work', () => {
      let _updateCount;
      function Counter(props) {
        const [count, updateCount] = useState(0);
        _updateCount = updateCount;
        useEffect(() => {
          ReactNoop.yield(`Will set count to 1`);
          updateCount(1);
        }, []);
        return <Text text={'Count: ' + count} />;
      }

      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      // Enqueuing this update forces the passive effect to be flushed --
      // updateCount(1) happens first, so 2 wins.
      act(() => _updateCount(2));
      expect(ReactNoop.flush()).toEqual(['Will set count to 1', 'Count: 2']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 2')]);
    });

    it.skip('flushes serial effects before enqueueing work (with tracing)', () => {
      const onInteractionScheduledWorkCompleted = jest.fn();
      const onWorkCanceled = jest.fn();
      SchedulerTracing.unstable_subscribe({
        onInteractionScheduledWorkCompleted,
        onInteractionTraced: jest.fn(),
        onWorkCanceled,
        onWorkScheduled: jest.fn(),
        onWorkStarted: jest.fn(),
        onWorkStopped: jest.fn(),
      });

      let _updateCount;
      function Counter(props) {
        const [count, updateCount] = useState(0);
        _updateCount = updateCount;
        useEffect(() => {
          expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([tracingEvent]);
          ReactNoop.yield(`Will set count to 1`);
          updateCount(1);
        }, []);
        return <Text text={'Count: ' + count} />;
      }

      const tracingEvent = { id: 0, name: 'hello', timestamp: 0 };
      SchedulerTracing.unstable_trace(tracingEvent.name, tracingEvent.timestamp, () => {
        ReactNoop.render(<Counter count={0} />);
      });
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(0);

      // Enqueuing this update forces the passive effect to be flushed --
      // updateCount(1) happens first, so 2 wins.
      act(() => _updateCount(2));
      expect(ReactNoop.flush()).toEqual(['Will set count to 1', 'Count: 2']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 2')]);

      expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
      expect(onWorkCanceled).toHaveBeenCalledTimes(0);
    });

    it.skip('in sync mode, useEffect is deferred and updates finish synchronously ' + '(in a single batch)', () => {
      function Counter(props) {
        const [count, updateCount] = useState('(empty)');
        useEffect(() => {
          // Update multiple times. These should all be batched together in
          // a single render.
          updateCount(props.count);
          updateCount(props.count);
          updateCount(props.count);
          updateCount(props.count);
          updateCount(props.count);
          updateCount(props.count);
        }, [props.count]);
        return <Text text={'Count: ' + count} />;
      }
      ReactNoop.renderLegacySyncRoot(<Counter count={0} />);
      // Even in sync mode, effects are deferred until after paint
      expect(ReactNoop.flush()).toEqual(['Count: (empty)']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
      // Now fire the effects
      ReactNoop.flushPassiveEffects();
      // There were multiple updates, but there should only be a
      // single render
      expect(ReactNoop.clearYields()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
    });

    it.skip('flushSync is not allowed', () => {
      function Counter(props) {
        const [count, updateCount] = useState('(empty)');
        useEffect(() => {
          ReactNoop.yield(`Schedule update [${props.count}]`);
          ReactNoop.flushSync(() => {
            updateCount(props.count);
          });
        }, [props.count]);
        return <Text text={'Count: ' + count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: (empty)']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);

      expect(() => {
        ReactNoop.flushPassiveEffects();
      }).toThrow('flushSync was called from inside a lifecycle method');
    });

    it('unmounts previous effect', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Did create [${props.count}]`);
          return () => {
            ReactNoop.yield(`Did destroy [${props.count}]`);
          };
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did create [0]']);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did destroy [0]', 'Did create [1]']);
    });

    it('unmounts on deletion', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Did create [${props.count}]`);
          return () => {
            ReactNoop.yield(`Did destroy [${props.count}]`);
          };
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did create [0]']);

      ReactNoop.render(null);
      expect(ReactNoop.flush()).toEqual(['Did destroy [0]']);
      expect(ReactNoop.getChildren()).toEqual([]);
    });

    it('unmounts on deletion after skipped effect', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Did create [${props.count}]`);
          return () => {
            ReactNoop.yield(`Did destroy [${props.count}]`);
          };
        }, []);
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did create [0]']);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(null);

      ReactNoop.render(null);
      expect(ReactNoop.flush()).toEqual(['Did destroy [0]']);
      expect(ReactNoop.getChildren()).toEqual([]);
    });

    it('always fires effects if no dependencies are provided', () => {
      function effect() {
        ReactNoop.yield(`Did create`);
        return () => {
          ReactNoop.yield(`Did destroy`);
        };
      }
      function Counter(props) {
        useEffect(effect);
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did create']);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did destroy', 'Did create']);

      ReactNoop.render(null);
      expect(ReactNoop.flush()).toEqual(['Did destroy']);
      expect(ReactNoop.getChildren()).toEqual([]);
    });

    it('skips effect if inputs have not changed', () => {
      function Counter(props) {
        const text = `${props.label}: ${props.count}`;
        useEffect(() => {
          ReactNoop.yield(`Did create [${text}]`);
          return () => {
            ReactNoop.yield(`Did destroy [${text}]`);
          };
        }, [props.label, props.count]);
        return <Text text={text} />;
      }
      ReactNoop.render(<Counter label="Count" count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did create [Count: 0]']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      ReactNoop.render(<Counter label="Count" count={1} />);
      // Count changed
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did destroy [Count: 0]', 'Did create [Count: 1]']);

      ReactNoop.render(<Counter label="Count" count={1} />);
      // Nothing changed, so no effect should have fired
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(null);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);

      ReactNoop.render(<Counter label="Total" count={1} />);
      // Label changed
      expect(ReactNoop.flush()).toEqual(['Total: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Total: 1')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did destroy [Count: 1]', 'Did create [Total: 1]']);
    });

    it('multiple effects', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Did commit 1 [${props.count}]`);
        });
        useEffect(() => {
          ReactNoop.yield(`Did commit 2 [${props.count}]`);
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did commit 1 [0]', 'Did commit 2 [0]']);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Did commit 1 [1]', 'Did commit 2 [1]']);
    });

    it('unmounts all previous effects before creating any new ones', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Mount A [${props.count}]`);
          return () => {
            ReactNoop.yield(`Unmount A [${props.count}]`);
          };
        });
        useEffect(() => {
          ReactNoop.yield(`Mount B [${props.count}]`);
          return () => {
            ReactNoop.yield(`Unmount B [${props.count}]`);
          };
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Mount A [0]', 'Mount B [0]']);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Unmount A [0]', 'Unmount B [0]', 'Mount A [1]', 'Mount B [1]']);
    });

    it.skip('handles errors on mount', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Mount A [${props.count}]`);
          return () => {
            ReactNoop.yield(`Unmount A [${props.count}]`);
          };
        });
        useEffect(() => {
          ReactNoop.yield('Oops!');
          throw new Error('Oops!');
          // eslint-disable-next-line no-unreachable
          ReactNoop.yield(`Mount B [${props.count}]`);
          return () => {
            ReactNoop.yield(`Unmount B [${props.count}]`);
          };
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
      expect(ReactNoop.clearYields()).toEqual([
        'Mount A [0]',
        'Oops!',
        // Clean up effect A. There's no effect B to clean-up, because it
        // never mounted.
        'Unmount A [0]',
      ]);
      expect(ReactNoop.getChildren()).toEqual([]);
    });

    it.skip('handles errors on update', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Mount A [${props.count}]`);
          return () => {
            ReactNoop.yield(`Unmount A [${props.count}]`);
          };
        });
        useEffect(() => {
          if (props.count === 1) {
            ReactNoop.yield('Oops!');
            throw new Error('Oops!');
          }
          ReactNoop.yield(`Mount B [${props.count}]`);
          return () => {
            ReactNoop.yield(`Unmount B [${props.count}]`);
          };
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Mount A [0]', 'Mount B [0]']);

      // This update will trigger an errror
      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
      expect(ReactNoop.clearYields()).toEqual([
        'Unmount A [0]',
        'Unmount B [0]',
        'Mount A [1]',
        'Oops!',
        // Clean up effect A. There's no effect B to clean-up, because it
        // never mounted.
        'Unmount A [1]',
      ]);
      expect(ReactNoop.getChildren()).toEqual([]);
    });

    it.skip('handles errors on unmount', () => {
      function Counter(props) {
        useEffect(() => {
          ReactNoop.yield(`Mount A [${props.count}]`);
          return () => {
            ReactNoop.yield('Oops!');
            throw new Error('Oops!');
            // eslint-disable-next-line no-unreachable
            ReactNoop.yield(`Unmount A [${props.count}]`);
          };
        });
        useEffect(() => {
          ReactNoop.yield(`Mount B [${props.count}]`);
          return () => {
            ReactNoop.yield(`Unmount B [${props.count}]`);
          };
        });
        return <Text text={'Count: ' + props.count} />;
      }
      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Mount A [0]', 'Mount B [0]']);

      // This update will trigger an errror
      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
      expect(ReactNoop.clearYields()).toEqual([
        'Oops!',
        // B unmounts even though an error was thrown in the previous effect
        'Unmount B [0]',
      ]);
      expect(ReactNoop.getChildren()).toEqual([]);
    });

    it('works with memo', () => {
      function Counter({ count }) {
        useLayoutEffect(() => {
          ReactNoop.yield('Mount: ' + count);
          return () => ReactNoop.yield('Unmount: ' + count);
        });
        return <Text text={'Count: ' + count} />;
      }
      Counter = memo(Counter);

      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Count: 0', 'Mount: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual(['Count: 1', 'Unmount: 0', 'Mount: 1']);
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);

      ReactNoop.render(null);
      expect(ReactNoop.flush()).toEqual(['Unmount: 1']);
      expect(ReactNoop.getChildren()).toEqual([]);
    });
  });

  describe('useLayoutEffect', () => {
    it('fires layout effects after the host has been mutated', () => {
      function getCommittedText() {
        const children = ReactNoop.getChildren();
        if (children === null) {
          return null;
        }
        return children[0].prop;
      }

      function Counter(props) {
        useLayoutEffect(() => {
          ReactNoop.yield(`Current: ${getCommittedText()}`);
        });
        return <Text text={props.count} />;
      }

      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual([0, 'Current: 0']);
      expect(ReactNoop.getChildren()).toEqual([span(0)]);

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual([1, 'Current: 1']);
      expect(ReactNoop.getChildren()).toEqual([span(1)]);
    });

    it.skip('force flushes passive effects before firing new layout effects', () => {
      let committedText = '(empty)';

      function Counter(props) {
        useLayoutEffect(() => {
          // Normally this would go in a mutation effect, but this test
          // intentionally omits a mutation effect.
          committedText = props.count + '';

          ReactNoop.yield(`Mount layout [current: ${committedText}]`);
          return () => {
            ReactNoop.yield(`Unmount layout [current: ${committedText}]`);
          };
        });
        useEffect(() => {
          ReactNoop.yield(`Mount normal [current: ${committedText}]`);
          return () => {
            ReactNoop.yield(`Unmount normal [current: ${committedText}]`);
          };
        });
        return null;
      }

      ReactNoop.render(<Counter count={0} />);
      expect(ReactNoop.flush()).toEqual(['Mount layout [current: 0]']);
      expect(committedText).toEqual('0');

      ReactNoop.render(<Counter count={1} />);
      expect(ReactNoop.flush()).toEqual([
        'Mount normal [current: 0]',
        'Unmount layout [current: 0]',
        'Mount layout [current: 1]',
      ]);
      expect(committedText).toEqual('1');

      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Unmount normal [current: 1]', 'Mount normal [current: 1]']);
    });
  });

  describe('useCallback', () => {
    it('memoizes callback by comparing inputs', () => {
      class IncrementButton extends React.PureComponent {
        increment = () => {
          this.props.increment();
        };
        render() {
          return <Text text="Increment" />;
        }
      }

      function Counter({ incrementBy }) {
        const [count, updateCount] = useState(0);
        const increment = useCallback(() => updateCount(c => c + incrementBy), [incrementBy]);
        return (
          <React.Fragment>
            <IncrementButton increment={increment} ref={button} />
            <Text text={'Count: ' + count} />
          </React.Fragment>
        );
      }

      const button = React.createRef(null);
      ReactNoop.render(<Counter incrementBy={1} />);
      expect(ReactNoop.flush()).toEqual(['Increment', 'Count: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('Increment'), span('Count: 0')]);

      act(button.current.increment);
      expect(ReactNoop.flush()).toEqual([
        // Button should not re-render, because its props haven't changed
        // 'Increment',
        'Count: 1',
      ]);
      expect(ReactNoop.getChildren()).toEqual([span('Increment'), span('Count: 1')]);

      // Increase the increment amount
      ReactNoop.render(<Counter incrementBy={10} />);
      expect(ReactNoop.flush()).toEqual([
        // Inputs did change this time
        'Increment',
        'Count: 1',
      ]);
      expect(ReactNoop.getChildren()).toEqual([span('Increment'), span('Count: 1')]);

      // Callback should have updated
      act(button.current.increment);
      expect(ReactNoop.flush()).toEqual(['Count: 11']);
      expect(ReactNoop.getChildren()).toEqual([span('Increment'), span('Count: 11')]);
    });
  });

  describe('useMemo', () => {
    it('memoizes value by comparing to previous inputs', () => {
      function CapitalizedText(props) {
        const text = props.text;
        const capitalizedText = useMemo(() => {
          ReactNoop.yield(`Capitalize '${text}'`);
          return text.toUpperCase();
        }, [text]);
        return <Text text={capitalizedText} />;
      }

      ReactNoop.render(<CapitalizedText text="hello" />);
      expect(ReactNoop.flush()).toEqual(["Capitalize 'hello'", 'HELLO']);
      expect(ReactNoop.getChildren()).toEqual([span('HELLO')]);

      ReactNoop.render(<CapitalizedText text="hi" />);
      expect(ReactNoop.flush()).toEqual(["Capitalize 'hi'", 'HI']);
      expect(ReactNoop.getChildren()).toEqual([span('HI')]);

      ReactNoop.render(<CapitalizedText text="hi" />);
      expect(ReactNoop.flush()).toEqual(['HI']);
      expect(ReactNoop.getChildren()).toEqual([span('HI')]);

      ReactNoop.render(<CapitalizedText text="goodbye" />);
      expect(ReactNoop.flush()).toEqual(["Capitalize 'goodbye'", 'GOODBYE']);
      expect(ReactNoop.getChildren()).toEqual([span('GOODBYE')]);
    });

    it('always re-computes if no inputs are provided', () => {
      function LazyCompute(props) {
        const computed = useMemo(props.compute);
        return <Text text={computed} />;
      }

      function computeA() {
        ReactNoop.yield('compute A');
        return 'A';
      }

      function computeB() {
        ReactNoop.yield('compute B');
        return 'B';
      }

      ReactNoop.render(<LazyCompute compute={computeA} />);
      expect(ReactNoop.flush()).toEqual(['compute A', 'A']);

      ReactNoop.render(<LazyCompute compute={computeA} />);
      expect(ReactNoop.flush()).toEqual(['compute A', 'A']);

      ReactNoop.render(<LazyCompute compute={computeA} />);
      expect(ReactNoop.flush()).toEqual(['compute A', 'A']);

      ReactNoop.render(<LazyCompute compute={computeB} />);
      expect(ReactNoop.flush()).toEqual(['compute B', 'B']);
    });

    it('should not invoke memoized function during re-renders unless inputs change', () => {
      function LazyCompute(props) {
        const computed = useMemo(() => props.compute(props.input), [props.input]);
        const [count, setCount] = useState(0);
        if (count < 3) {
          setCount(count + 1);
        }
        return <Text text={computed} />;
      }

      function compute(val) {
        ReactNoop.yield('compute ' + val);
        return val;
      }

      ReactNoop.render(<LazyCompute compute={compute} input="A" />);
      expect(ReactNoop.flush()).toEqual(['compute A', 'A']);

      ReactNoop.render(<LazyCompute compute={compute} input="A" />);
      expect(ReactNoop.flush()).toEqual(['A']);

      ReactNoop.render(<LazyCompute compute={compute} input="B" />);
      expect(ReactNoop.flush()).toEqual(['compute B', 'B']);
    });
  });

  describe('useRef', () => {
    it('creates a ref object initialized with the provided value', () => {
      jest.useFakeTimers();

      function useDebouncedCallback(callback, ms, inputs) {
        const timeoutID = useRef(-1);
        useEffect(() => {
          return function unmount() {
            clearTimeout(timeoutID.current);
          };
        }, []);
        const debouncedCallback = useCallback(
          (...args) => {
            clearTimeout(timeoutID.current);
            timeoutID.current = setTimeout(callback, ms, ...args);
          },
          [callback, ms],
        );
        return useCallback(debouncedCallback, inputs);
      }

      let ping;
      function App() {
        ping = useDebouncedCallback(
          value => {
            ReactNoop.yield('ping: ' + value);
          },
          100,
          [],
        );
        return null;
      }

      ReactNoop.render(<App />);
      expect(ReactNoop.flush()).toEqual([]);

      ping(1);
      ping(2);
      ping(3);

      expect(ReactNoop.flush()).toEqual([]);

      jest.advanceTimersByTime(100);

      expect(ReactNoop.flush()).toEqual(['ping: 3']);

      ping(4);
      jest.advanceTimersByTime(20);
      ping(5);
      ping(6);
      jest.advanceTimersByTime(80);

      expect(ReactNoop.flush()).toEqual([]);

      jest.advanceTimersByTime(20);
      expect(ReactNoop.flush()).toEqual(['ping: 6']);
    });

    it('should return the same ref during re-renders', () => {
      function Counter() {
        const ref = useRef('val');
        const [count, setCount] = useState(0);
        const [firstRef] = useState(ref);

        if (firstRef !== ref) {
          throw new Error('should never change');
        }

        if (count < 3) {
          setCount(count + 1);
        }

        return <Text text={ref.current} />;
      }

      ReactNoop.render(<Counter />);
      expect(ReactNoop.flush()).toEqual(['val']);

      ReactNoop.render(<Counter />);
      expect(ReactNoop.flush()).toEqual(['val']);
    });
  });

  describe('useImperativeHandle', () => {
    it('does not update when deps are the same', () => {
      const INCREMENT = 'INCREMENT';

      function reducer(state, action) {
        return action === INCREMENT ? state + 1 : state;
      }

      function Counter(props, ref) {
        const [count, dispatch] = useReducer(reducer, 0);
        useImperativeHandle(ref, () => ({ count, dispatch }), []);
        return <Text text={'Count: ' + count} />;
      }

      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      expect(counter.current.count).toBe(0);

      act(() => {
        counter.current.dispatch(INCREMENT);
      });
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      // Intentionally not updated because of [] deps:
      expect(counter.current.count).toBe(0);
    });

    // Regression test for https://github.com/facebook/react/issues/14782
    it.skip('automatically updates when deps are not specified', () => {
      const INCREMENT = 'INCREMENT';

      function reducer(state, action) {
        return action === INCREMENT ? state + 1 : state;
      }

      function Counter(props, ref) {
        const [count, dispatch] = useReducer(reducer, 0);
        useImperativeHandle(ref, () => ({ count, dispatch }));
        return <Text text={'Count: ' + count} />;
      }

      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      expect(counter.current.count).toBe(0);

      act(() => {
        counter.current.dispatch(INCREMENT);
      });
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      expect(counter.current.count).toBe(1);
    });

    it('updates when deps are different', () => {
      const INCREMENT = 'INCREMENT';

      function reducer(state, action) {
        return action === INCREMENT ? state + 1 : state;
      }

      let totalRefUpdates = 0;
      function Counter(props, ref) {
        const [count, dispatch] = useReducer(reducer, 0);
        useImperativeHandle(
          ref,
          () => {
            totalRefUpdates++;
            return { count, dispatch };
          },
          [count],
        );
        return <Text text={'Count: ' + count} />;
      }

      Counter = forwardRef(Counter);
      const counter = React.createRef(null);
      ReactNoop.render(<Counter ref={counter} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
      expect(counter.current.count).toBe(0);
      expect(totalRefUpdates).toBe(1);

      act(() => {
        counter.current.dispatch(INCREMENT);
      });
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      expect(counter.current.count).toBe(1);
      expect(totalRefUpdates).toBe(2);

      // Update that doesn't change the ref dependencies
      ReactNoop.render(<Counter ref={counter} />);
      ReactNoop.flush();
      expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
      expect(counter.current.count).toBe(1);
      expect(totalRefUpdates).toBe(2); // Should not increase since last time
    });
  });

  describe('progressive enhancement (not supported)', () => {
    it('mount additional state', () => {
      let updateA;
      let updateB;
      // let updateC;

      function App(props) {
        const [A, _updateA] = useState(0);
        const [B, _updateB] = useState(0);
        updateA = _updateA;
        updateB = _updateB;

        let C;
        if (props.loadC) {
          useState(0);
        } else {
          C = '[not loaded]';
        }

        return <Text text={`A: ${A}, B: ${B}, C: ${C}`} />;
      }

      ReactNoop.render(<App loadC={false} />);
      expect(ReactNoop.flush()).toEqual(['A: 0, B: 0, C: [not loaded]']);
      expect(ReactNoop.getChildren()).toEqual([span('A: 0, B: 0, C: [not loaded]')]);

      act(() => {
        updateA(2);
        updateB(3);
      });

      expect(ReactNoop.flush()).toEqual(['A: 2, B: 3, C: [not loaded]']);
      expect(ReactNoop.getChildren()).toEqual([span('A: 2, B: 3, C: [not loaded]')]);

      ReactNoop.render(<App loadC={true} />);
      expect(() => {
        expect(ReactNoop.flush()).toEqual(['A: 2, B: 3, C: 0']);
      }).toThrow('Rendered more hooks than during the previous render');

      // Uncomment if/when we support this again
      // expect(ReactNoop.getChildren()).toEqual([span('A: 2, B: 3, C: 0')]);

      // updateC(4);
      // expect(ReactNoop.flush()).toEqual(['A: 2, B: 3, C: 4']);
      // expect(ReactNoop.getChildren()).toEqual([span('A: 2, B: 3, C: 4')]);
    });

    it('unmount state', () => {
      let updateA;
      let updateB;
      let updateC;

      function App(props) {
        const [A, _updateA] = useState(0);
        const [B, _updateB] = useState(0);
        updateA = _updateA;
        updateB = _updateB;

        let C;
        if (props.loadC) {
          const [_C, _updateC] = useState(0);
          C = _C;
          updateC = _updateC;
        } else {
          C = '[not loaded]';
        }

        return <Text text={`A: ${A}, B: ${B}, C: ${C}`} />;
      }

      ReactNoop.render(<App loadC={true} />);
      expect(ReactNoop.flush()).toEqual(['A: 0, B: 0, C: 0']);
      expect(ReactNoop.getChildren()).toEqual([span('A: 0, B: 0, C: 0')]);
      act(() => {
        updateA(2);
        updateB(3);
        updateC(4);
      });
      expect(ReactNoop.flush()).toEqual(['A: 2, B: 3, C: 4']);
      expect(ReactNoop.getChildren()).toEqual([span('A: 2, B: 3, C: 4')]);
      // Skip
      // ReactNoop.render(<App loadC={false} />);
      // expect(() => ReactNoop.flush()).toThrow(
      //   'Rendered fewer hooks than expected. This may be caused by an ' + 'accidental early return statement.',
      // );
    });

    it.skip('unmount effects', () => {
      function App(props) {
        useEffect(() => {
          ReactNoop.yield('Mount A');
          return () => {
            ReactNoop.yield('Unmount A');
          };
        }, []);

        if (props.showMore) {
          useEffect(() => {
            ReactNoop.yield('Mount B');
            return () => {
              ReactNoop.yield('Unmount B');
            };
          }, []);
        }

        return null;
      }

      ReactNoop.render(<App showMore={false} />);
      expect(ReactNoop.flush()).toEqual([]);
      ReactNoop.flushPassiveEffects();
      expect(ReactNoop.clearYields()).toEqual(['Mount A']);

      ReactNoop.render(<App showMore={true} />);
      expect(() => {
        expect(ReactNoop.flush()).toEqual([]);
      }).toThrow('Rendered more hooks than during the previous render');

      // Uncomment if/when we support this again
      // ReactNoop.flushPassiveEffects();
      // expect(ReactNoop.clearYields()).toEqual(['Mount B']);

      // ReactNoop.render(<App showMore={false} />);
      // expect(() => ReactNoop.flush()).toThrow(
      //   'Rendered fewer hooks than expected. This may be caused by an ' +
      //     'accidental early return statement.',
      // );
    });
  });

  describe('useContext', () => {
    it('simple use', () => {
      const CounterContext = createContext();
      const Counter = () => {
        const count = useContext(CounterContext);
        return <Text text={count} />;
      };
      class Blank extends React.PureComponent {
        render() {
          return this.props.children;
        }
      }
      const App = props => {
        return (
          <CounterContext.Provider value={props.count}>
            <Blank>
              <Counter />
            </Blank>
          </CounterContext.Provider>
        );
      };
      ReactNoop.render(<App count={0} />);
      expect(ReactNoop.flush()).toEqual([0]);
      ReactNoop.render(<App count={1} />);
      expect(ReactNoop.flush()).toEqual([1]);
    });

    it('works with shouldComponentUpdate', () => {
      const CounterContext = createContext(0);
      const Counter = () => {
        const count = useContext(CounterContext);
        return <Text text={count} />
      };
      class Blank extends React.PureComponent {
        render() {
          return <Counter />;
        }
      }
      let updateCount;
      const App = () => {
        const [count, _updateCount] = useState(0);
        updateCount = _updateCount;
        return (
          <CounterContext.Provider value={count}>
            <Blank />
          </CounterContext.Provider>
        );
      };
      ReactNoop.render(<App />);
      expect(ReactNoop.flush()).toEqual([0]);
      updateCount(1);
      expect(ReactNoop.flush()).toEqual([1]);
    });

    it('multiple contexts', () => {
      const CounterContext1 = createContext();
      const CounterContext2 = createContext();
      const Counter = () => {
        const count1 = useContext(CounterContext1);
        const count2 = useContext(CounterContext2);
        return (
          <Text text={`${count1}${count2}`} />
        );
      };
      class Blank extends React.PureComponent {
        render() {
          return <Counter />;
        }
      }
      const App = props => {
        return (
          <CounterContext1.Provider value={props.count1}>
            <CounterContext2.Provider value={props.count2}>
              <Blank />
            </CounterContext2.Provider>
          </CounterContext1.Provider>
        );
      };
      ReactNoop.render(<App count1={0} count2={0} />);
      expect(ReactNoop.flush()).toEqual(['00']);
      ReactNoop.render(<App count1={1} count2={0} />);
      expect(ReactNoop.flush()).toEqual(['10']);
      ReactNoop.render(<App count1={1} count2={1} />);
      expect(ReactNoop.flush()).toEqual(['11']);
    });
  });
});


================================================
FILE: tests/ReactHooksWithReactDOM.test.js
================================================
import '../src/polyfill';
import React, { forwardRef, useState, useImperativeHandle, useLayoutEffect, useEffect } from 'react';
import { render, cleanup } from 'react-testing-library';
import 'jest-dom/extend-expect';

class Logger {
  yieldedValues = null;

  yield(value) {
    if (this.yieldedValues === null) {
      this.yieldedValues = [value];
    } else {
      this.yieldedValues.push(value);
    }
  }

  flush() {
    const values = this.yieldedValues || [];
    this.yieldedValues = null;
    return values;
  }

  clearYields() {
    const values = this.yieldedValues;
    this.yieldedValues = null;
    return values;
  }
}

let logger;

describe('hooks', () => {
  function Text(props) {
    logger.yield(props.text);
    return <span data-testid="text">{props.text}</span>;
  }

  beforeEach(() => {
    logger = new Logger();
    jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => setTimeout(cb));
  });

  afterEach(() => {
    cleanup();
    window.requestAnimationFrame.mockRestore();
    jest.clearAllTimers();
  });

  describe('useEffect', () => {
    it('flushes passive effects even with sibling deletions', () => {
      jest.useFakeTimers();
      function LayoutEffect(props) {
        useLayoutEffect(() => {
          logger.yield(`Layout effect`);
        });
        return <Text text="Layout" />;
      }
      function PassiveEffect(props) {
        useEffect(() => {
          logger.yield(`Passive effect`);
        }, []);
        return <Text text="Passive" />;
      }
      let passive = <PassiveEffect key="p" />;
      const { container, rerender } = render([<LayoutEffect key="l" />, passive]);
      expect(logger.flush()).toEqual(['Layout', 'Passive', 'Layout effect']);
      expect(container).toHaveTextContent('LayoutPassive');

      // Destroying the first child shouldn't prevent the passive effect from
      // being executed
      rerender([passive]);
      jest.runAllTimers();
      expect(logger.flush()).toEqual(['Passive effect']);
      expect(container).toHaveTextContent('Passive');

      // (No effects are left to flush.)
      jest.runAllTimers();
      expect(logger.clearYields()).toEqual(null);
    });

    it('flushes passive effects even if siblings schedule an update', () => {
      jest.useFakeTimers();
      function PassiveEffect(props) {
        useEffect(() => {
          debugger
          logger.yield('Passive effect');
        });
        return <Text text="Passive" />;
      }
      function LayoutEffect(props) {
        let [count, setCount] = useState(0);
        useLayoutEffect(() => {
          // Scheduling work shouldn't interfere with the queued passive effect
          if (count === 0) {
            setCount(1);
          }
          logger.yield('Layout effect ' + count);
        });
        return <Text text="Layout" />;
      }

      render([<PassiveEffect key="p" />, <LayoutEffect key="l" />]);

      jest.runAllTimers();

      expect(logger.flush()).toEqual([
        'Passive',
        'Layout',
        'Layout effect 0',
        'Passive effect',
        'Layout',
        'Layout effect 1',
      ]);

      expect(container).toHaveTextContent('PassiveLayout');
    });

  });
});


================================================
FILE: vendors/react-noop-renderer/LICENSE
================================================
MIT License

Copyright (c) Facebook, Inc. and its affiliates.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: vendors/react-noop-renderer/README.md
================================================
# `react-noop-renderer`

This package is the renderer we use for debugging [Fiber](https://github.com/facebook/react/issues/6170).
It is not intended to be used directly.


================================================
FILE: vendors/react-noop-renderer/cjs/react-noop-renderer-persistent.development.js
================================================
/** @license React v16.6.1
 * react-noop-renderer-persistent.development.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

const regeneratorRuntime = require("regenerator-runtime");

if (process.env.NODE_ENV !== "production") {
  (function() {
'use strict';

var ReactFiberPersistentReconciler = require('react-reconciler/persistent');
var _assign = require('object-assign');
var expect = require('expect');

// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === 'function' && Symbol.for;

var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7;
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;

function createPortal(children, containerInfo,
// TODO: figure out the API for cross-renderer implementation.
implementation) {
  var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;

  return {
    // This tag allow us to uniquely identify this as a React Portal
    $$typeof: REACT_PORTAL_TYPE,
    key: key == null ? null : '' + key,
    children: children,
    containerInfo: containerInfo,
    implementation: implementation
  };
}

/**
 * Similar to invariant but only logs a warning if the condition is not met.
 * This can be used to log issues in development environments in critical
 * paths. Removing the logging code for production environments will keep the
 * same logic and follow the same code paths.
 */

var warningWithoutStack = function () {};

{
  warningWithoutStack = function (condition, format) {
    for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
      args[_key - 2] = arguments[_key];
    }

    if (format === undefined) {
      throw new Error('`warningWithoutStack(condition, format, ...args)` requires a warning ' + 'message argument');
    }
    if (args.length > 8) {
      // Check before the condition to catch violations early.
      throw new Error('warningWithoutStack() currently supports at most 8 arguments.');
    }
    if (condition) {
      return;
    }
    if (typeof console !== 'undefined') {
      var argsWithFormat = args.map(function (item) {
        return '' + item;
      });
      argsWithFormat.unshift('Warning: ' + format);

      // We intentionally don't use spread (or .apply) directly because it
      // breaks IE9: https://github.com/facebook/react/issues/13610
      Function.prototype.apply.call(console.error, console, argsWithFormat);
    }
    try {
      // --- Welcome to debugging React ---
      // This error was thrown as a convenience so that you can use this stack
      // to find the callsite that caused this warning to fire.
      var argIndex = 0;
      var message = 'Warning: ' + format.replace(/%s/g, function () {
        return args[argIndex++];
      });
      throw new Error(message);
    } catch (x) {}
  };
}

var warningWithoutStack$1 = warningWithoutStack;

// for .act's return value


var NO_CONTEXT = {};
var UPDATE_SIGNAL = {};
{
  Object.freeze(NO_CONTEXT);
  Object.freeze(UPDATE_SIGNAL);
}

function createReactNoop(reconciler, useMutation) {
  var _marked = /*#__PURE__*/regeneratorRuntime.mark(flushUnitsOfWork);

  var scheduledCallback = null;
  var scheduledCallbackTimeout = -1;
  var scheduledPassiveCallback = null;
  var instanceCounter = 0;
  var hostDiffCounter = 0;
  var hostUpdateCounter = 0;
  var hostCloneCounter = 0;

  function appendChildToContainerOrInstance(parentInstance, child) {
    var index = parentInstance.children.indexOf(child);
    if (index !== -1) {
      parentInstance.children.splice(index, 1);
    }
    parentInstance.children.push(child);
  }

  function appendChildToContainer(parentInstance, child) {
    if (typeof parentInstance.rootID !== 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('appendChildToContainer() first argument is not a container.');
    }
    appendChildToContainerOrInstance(parentInstance, child);
  }

  function appendChild(parentInstance, child) {
    if (typeof parentInstance.rootID === 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('appendChild() first argument is not an instance.');
    }
    appendChildToContainerOrInstance(parentInstance, child);
  }

  function insertInContainerOrInstanceBefore(parentInstance, child, beforeChild) {
    var index = parentInstance.children.indexOf(child);
    if (index !== -1) {
      parentInstance.children.splice(index, 1);
    }
    var beforeIndex = parentInstance.children.indexOf(beforeChild);
    if (beforeIndex === -1) {
      throw new Error('This child does not exist.');
    }
    parentInstance.children.splice(beforeIndex, 0, child);
  }

  function insertInContainerBefore(parentInstance, child, beforeChild) {
    if (typeof parentInstance.rootID !== 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('insertInContainerBefore() first argument is not a container.');
    }
    insertInContainerOrInstanceBefore(parentInstance, child, beforeChild);
  }

  function insertBefore(parentInstance, child, beforeChild) {
    if (typeof parentInstance.rootID === 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('insertBefore() first argument is not an instance.');
    }
    insertInContainerOrInstanceBefore(parentInstance, child, beforeChild);
  }

  function removeChildFromContainerOrInstance(parentInstance, child) {
    var index = parentInstance.children.indexOf(child);
    if (index === -1) {
      throw new Error('This child does not exist.');
    }
    parentInstance.children.splice(index, 1);
  }

  function removeChildFromContainer(parentInstance, child) {
    if (typeof parentInstance.rootID !== 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('removeChildFromContainer() first argument is not a container.');
    }
    removeChildFromContainerOrInstance(parentInstance, child);
  }

  function removeChild(parentInstance, child) {
    if (typeof parentInstance.rootID === 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('removeChild() first argument is not an instance.');
    }
    removeChildFromContainerOrInstance(parentInstance, child);
  }

  function cloneInstance(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle, keepChildren, recyclableInstance) {
    var clone = {
      id: instance.id,
      type: type,
      children: keepChildren ? instance.children : [],
      text: shouldSetTextContent(type, newProps) ? newProps.children + '' : null,
      prop: newProps.prop,
      hidden: newProps.hidden === true
    };
    Object.defineProperty(clone, 'id', {
      value: clone.id,
      enumerable: false
    });
    Object.defineProperty(clone, 'text', {
      value: clone.text,
      enumerable: false
    });
    hostCloneCounter++;
    return clone;
  }

  function shouldSetTextContent(type, props) {
    if (type === 'errorInBeginPhase') {
      throw new Error('Error in host config.');
    }
    return typeof props.children === 'string' || typeof props.children === 'number';
  }

  var elapsedTimeInMs = 0;

  var sharedHostConfig = {
    getRootHostContext: function () {
      return NO_CONTEXT;
    },
    getChildHostContext: function () {
      return NO_CONTEXT;
    },
    getPublicInstance: function (instance) {
      return instance;
    },
    createInstance: function (type, props) {
      if (type === 'errorInCompletePhase') {
        throw new Error('Error in host config.');
      }
      var inst = {
        id: instanceCounter++,
        type: type,
        children: [],
        text: shouldSetTextContent(type, props) ? props.children + '' : null,
        prop: props.prop,
        hidden: props.hidden === true
      };
      // Hide from unit tests
      Object.defineProperty(inst, 'id', { value: inst.id, enumerable: false });
      Object.defineProperty(inst, 'text', {
        value: inst.text,
        enumerable: false
      });
      return inst;
    },
    appendInitialChild: function (parentInstance, child) {
      parentInstance.children.push(child);
    },
    finalizeInitialChildren: function (domElement, type, props) {
      return false;
    },
    prepareUpdate: function (instance, type, oldProps, newProps) {
      if (type === 'errorInCompletePhase') {
        throw new Error('Error in host config.');
      }
      if (oldProps === null) {
        throw new Error('Should have old props');
      }
      if (newProps === null) {
        throw new Error('Should have new props');
      }
      hostDiffCounter++;
      return UPDATE_SIGNAL;
    },


    shouldSetTextContent: shouldSetTextContent,

    shouldDeprioritizeSubtree: function (type, props) {
      return !!props.hidden;
    },
    createTextInstance: function (text, rootContainerInstance, hostContext, internalInstanceHandle) {
      var inst = { text: text, id: instanceCounter++, hidden: false };
      // Hide from unit tests
      Object.defineProperty(inst, 'id', { value: inst.id, enumerable: false });
      return inst;
    },
    scheduleDeferredCallback: function (callback, options) {
      if (scheduledCallback) {
        throw new Error('Scheduling a callback twice is excessive. Instead, keep track of ' + 'whether the callback has already been scheduled.');
      }
      scheduledCallback = callback;
      if (typeof options === 'object' && options !== null && typeof options.timeout === 'number') {
        var newTimeout = options.timeout;
        if (scheduledCallbackTimeout === -1 || scheduledCallbackTimeout > newTimeout) {
          scheduledCallbackTimeout = elapsedTimeInMs + newTimeout;
        }
      }
      return 0;
    },
    cancelDeferredCallback: function () {
      if (scheduledCallback === null) {
        throw new Error('No callback is scheduled.');
      }
      scheduledCallback = null;
      scheduledCallbackTimeout = -1;
    },


    shouldYield: shouldYield,

    scheduleTimeout: setTimeout,
    cancelTimeout: clearTimeout,
    noTimeout: -1,
    schedulePassiveEffects: function (callback) {
      if (scheduledCallback) {
        throw new Error('Scheduling a callback twice is excessive. Instead, keep track of ' + 'whether the callback has already been scheduled.');
      }
      scheduledPassiveCallback = callback;
    },
    cancelPassiveEffects: function () {
      if (scheduledPassiveCallback === null) {
        throw new Error('No passive effects callback is scheduled.');
      }
      scheduledPassiveCallback = null;
    },
    prepareForCommit: function () {},
    resetAfterCommit: function () {},
    now: function () {
      return elapsedTimeInMs;
    },


    isPrimaryRenderer: true,
    supportsHydration: false
  };

  var hostConfig = useMutation ? _assign({}, sharedHostConfig, {

    supportsMutation: true,
    supportsPersistence: false,

    commitMount: function (instance, type, newProps) {
      // Noop
    },
    commitUpdate: function (instance, updatePayload, type, oldProps, newProps) {
      if (oldProps === null) {
        throw new Error('Should have old props');
      }
      hostUpdateCounter++;
      instance.prop = newProps.prop;
      instance.hidden = newProps.hidden === true;
      if (shouldSetTextContent(type, newProps)) {
        instance.text = newProps.children + '';
      }
    },
    commitTextUpdate: function (textInstance, oldText, newText) {
      hostUpdateCounter++;
      textInstance.text = newText;
    },


    appendChild: appendChild,
    appendChildToContainer: appendChildToContainer,
    insertBefore: insertBefore,
    insertInContainerBefore: insertInContainerBefore,
    removeChild: removeChild,
    removeChildFromContainer: removeChildFromContainer,

    hideInstance: function (instance) {
      instance.hidden = true;
    },
    hideTextInstance: function (textInstance) {
      textInstance.hidden = true;
    },
    unhideInstance: function (instance, props) {
      if (!props.hidden) {
        instance.hidden = false;
      }
    },
    unhideTextInstance: function (textInstance, text) {
      textInstance.hidden = false;
    },
    resetTextContent: function (instance) {
      instance.text = null;
    }
  }) : _assign({}, sharedHostConfig, {
    supportsMutation: false,
    supportsPersistence: true,

    cloneInstance: cloneInstance,

    createContainerChildSet: function (container) {
      return [];
    },
    appendChildToContainerChildSet: function (childSet, child) {
      childSet.push(child);
    },
    finalizeContainerChildren: function (container, newChildren) {},
    replaceContainerChildren: function (container, newChildren) {
      container.children = newChildren;
    },
    cloneHiddenInstance: function (instance, type, props, internalInstanceHandle) {
      var clone = cloneInstance(instance, null, type, props, props, internalInstanceHandle, true, null);
      clone.hidden = true;
      return clone;
    },
    cloneUnhiddenInstance: function (instance, type, props, internalInstanceHandle) {
      var clone = cloneInstance(instance, null, type, props, props, internalInstanceHandle, true, null);
      clone.hidden = props.hidden;
      return clone;
    },
    createHiddenTextInstance: function (text, rootContainerInstance, hostContext, internalInstanceHandle) {
      var inst = { text: text, id: instanceCounter++, hidden: true };
      // Hide from unit tests
      Object.defineProperty(inst, 'id', {
        value: inst.id,
        enumerable: false
      });
      return inst;
    }
  });

  var NoopRenderer = reconciler(hostConfig);

  var rootContainers = new Map();
  var roots = new Map();
  var DEFAULT_ROOT_ID = '<default>';

  var yieldedValues = null;

  var didYield = void 0;
  var unitsRemaining = void 0;

  function shouldYield() {
    if (scheduledCallbackTimeout === -1 || elapsedTimeInMs > scheduledCallbackTimeout) {
      return false;
    } else {
      if (didYield || yieldedValues !== null) {
        return true;
      }
      if (unitsRemaining-- > 0) {
        return false;
      }
      didYield = true;
      return true;
    }
  }

  function flushUnitsOfWork(n) {
    var cb, values;
    return regeneratorRuntime.wrap(function flushUnitsOfWork$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            unitsRemaining = n + 1;
            didYield = false;
            _context.prev = 2;

          case 3:
            if (!(!didYield && scheduledCallback !== null)) {
              _context.next = 14;
              break;
            }

            cb = scheduledCallback;

            scheduledCallback = null;
            cb();

            if (!(yieldedValues !== null)) {
              _context.next = 12;
              break;
            }

            values = yieldedValues;

            yieldedValues = null;
            _context.next = 12;
            return values;

          case 12:
            _context.next = 3;
            break;

          case 14:
            _context.prev = 14;

            unitsRemaining = -1;
            didYield = false;
            return _context.finish(14);

          case 18:
          case 'end':
            return _context.stop();
        }
      }
    }, _marked, this, [[2,, 14, 18]]);
  }

  function childToJSX(child, text) {
    if (text !== null) {
      return text;
    }
    if (child === null) {
      return null;
    }
    if (typeof child === 'string') {
      return child;
    }
    if (Array.isArray(child)) {
      if (child.length === 0) {
        return null;
      }
      if (child.length === 1) {
        return childToJSX(child[0], null);
      }
      // $FlowFixMe
      var _children = child.map(function (c) {
        return childToJSX(c, null);
      });
      if (_children.every(function (c) {
        return typeof c === 'string' || typeof c === 'number';
      })) {
        return _children.join('');
      }
      return _children;
    }
    if (Array.isArray(child.children)) {
      // This is an instance.
      var instance = child;
      var _children2 = childToJSX(instance.children, instance.text);
      var props = { prop: instance.prop };
      if (instance.hidden) {
        props.hidden = true;
      }
      if (_children2 !== null) {
        props.children = _children2;
      }
      return {
        $$typeof: REACT_ELEMENT_TYPE,
        type: instance.type,
        key: null,
        ref: null,
        props: props,
        _owner: null,
        _store: {}
      };
    }
    // This is a text instance
    var textInstance = child;
    if (textInstance.hidden) {
      return '';
    }
    return textInstance.text;
  }

  var ReactNoop = {
    getChildren: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      var container = rootContainers.get(rootID);
      if (container) {
        return container.children;
      } else {
        return null;
      }
    },
    getOrCreateRootContainer: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;
      var isConcurrent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

      var root = roots.get(rootID);
      if (!root) {
        var container = { rootID: rootID, children: [] };
        rootContainers.set(rootID, container);
        root = NoopRenderer.createContainer(container, isConcurrent, false);
        roots.set(rootID, root);
      }
      return root.current.stateNode.containerInfo;
    },
    getChildrenAsJSX: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      var children = childToJSX(ReactNoop.getChildren(rootID), null);
      if (children === null) {
        return null;
      }
      if (Array.isArray(children)) {
        return {
          $$typeof: REACT_ELEMENT_TYPE,
          type: REACT_FRAGMENT_TYPE,
          key: null,
          ref: null,
          props: { children: children },
          _owner: null,
          _store: {}
        };
      }
      return children;
    },
    createPortal: function (children, container) {
      var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;

      return createPortal(children, container, null, key);
    },


    // Shortcut for testing a single root
    render: function (element, callback) {
      ReactNoop.renderToRootWithID(element, DEFAULT_ROOT_ID, callback);
    },
    renderLegacySyncRoot: function (element, callback) {
      var rootID = DEFAULT_ROOT_ID;
      var isConcurrent = false;
      var container = ReactNoop.getOrCreateRootContainer(rootID, isConcurrent);
      var root = roots.get(container.rootID);
      NoopRenderer.updateContainer(element, root, null, callback);
    },
    renderToRootWithID: function (element, rootID, callback) {
      var isConcurrent = true;
      var container = ReactNoop.getOrCreateRootContainer(rootID, isConcurrent);
      var root = roots.get(container.rootID);
      NoopRenderer.updateContainer(element, root, null, callback);
    },
    unmountRootWithID: function (rootID) {
      var root = roots.get(rootID);
      if (root) {
        NoopRenderer.updateContainer(null, root, null, function () {
          roots.delete(rootID);
          rootContainers.delete(rootID);
        });
      }
    },
    findInstance: function (componentOrElement) {
      if (componentOrElement == null) {
        return null;
      }
      // Unsound duck typing.
      var component = componentOrElement;
      if (typeof component.id === 'number') {
        return component;
      }
      {
        return NoopRenderer.findHostInstanceWithWarning(component, 'findInstance');
      }
      return NoopRenderer.findHostInstance(component);
    },
    flushDeferredPri: function () {
      var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity;

      // The legacy version of this function decremented the timeout before
      // returning the new time.
      // TODO: Convert tests to use flushUnitsOfWork or flushAndYield instead.
      var n = timeout / 5 - 1;

      var values = [];
      // eslint-disable-next-line no-for-of-loops/no-for-of-loops
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = flushUnitsOfWork(n)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var value = _step.value;

          values.push.apply(values, value);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return values;
    },
    flush: function () {
      return ReactNoop.flushUnitsOfWork(Infinity);
    },
    flushAndYield: function () {
      var unitsOfWork = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity;

      return flushUnitsOfWork(unitsOfWork);
    },
    flushUnitsOfWork: function (n) {
      var values = yieldedValues || [];
      yieldedValues = null;
      // eslint-disable-next-line no-for-of-loops/no-for-of-loops
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = flushUnitsOfWork(n)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var value = _step2.value;

          values.push.apply(values, value);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2.return) {
            _iterator2.return();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return values;
    },
    flushThrough: function (expected) {
      var actual = [];
      if (expected.length !== 0) {
        // eslint-disable-next-line no-for-of-loops/no-for-of-loops
        var _iteratorNormalCompletion3 = true;
        var _didIteratorError3 = false;
        var _iteratorError3 = undefined;

        try {
          for (var _iterator3 = flushUnitsOfWork(Infinity)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
            var value = _step3.value;

            actual.push.apply(actual, value);
            if (actual.length >= expected.length) {
              break;
            }
          }
        } catch (err) {
          _didIteratorError3 = true;
          _iteratorError3 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion3 && _iterator3.return) {
              _iterator3.return();
            }
          } finally {
            if (_didIteratorError3) {
              throw _iteratorError3;
            }
          }
        }
      }
      expect(actual).toEqual(expected);
    },
    flushNextYield: function () {
      var actual = null;
      // eslint-disable-next-line no-for-of-loops/no-for-of-loops
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = flushUnitsOfWork(Infinity)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var value = _step4.value;

          actual = value;
          break;
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4.return) {
            _iterator4.return();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }

      return actual !== null ? actual : [];
    },
    flushWithHostCounters: function (fn) {
      hostDiffCounter = 0;
      hostUpdateCounter = 0;
      hostCloneCounter = 0;
      try {
        ReactNoop.flush();
        return useMutation ? {
          hostDiffCounter: hostDiffCounter,
          hostUpdateCounter: hostUpdateCounter
        } : {
          hostDiffCounter: hostDiffCounter,
          hostCloneCounter: hostCloneCounter
        };
      } finally {
        hostDiffCounter = 0;
        hostUpdateCounter = 0;
        hostCloneCounter = 0;
      }
    },
    expire: function (ms) {
      ReactNoop.advanceTime(ms);
      return ReactNoop.flushExpired();
    },
    advanceTime: function (ms) {
      elapsedTimeInMs += ms;
    },
    flushExpired: function () {
      return ReactNoop.flushUnitsOfWork(0);
    },
    yield: function (value) {
      if (yieldedValues === null) {
        yieldedValues = [value];
      } else {
        yieldedValues.push(value);
      }
    },
    clearYields: function () {
      var values = yieldedValues;
      yieldedValues = null;
      return values;
    },
    hasScheduledCallback: function () {
      return !!scheduledCallback;
    },


    batchedUpdates: NoopRenderer.batchedUpdates,

    deferredUpdates: NoopRenderer.deferredUpdates,

    unbatchedUpdates: NoopRenderer.unbatchedUpdates,

    interactiveUpdates: NoopRenderer.interactiveUpdates,

    // maybe this should exist only in the test file
    act: function (callback) {
      // note: keep these warning messages in sync with
      // ReactTestRenderer.js and ReactTestUtils.js
      var result = NoopRenderer.batchedUpdates(callback);
      {
        if (result !== undefined) {
          var addendum = void 0;
          if (result !== null && typeof result.then === 'function') {
            addendum = "\n\nIt looks like you wrote ReactNoop.act(async () => ...) or returned a Promise from it's callback. " + 'Putting asynchronous logic inside ReactNoop.act(...) is not supported.\n';
          } else {
            addendum = ' You returned: ' + result;
          }
          warningWithoutStack$1(false, 'The callback passed to ReactNoop.act(...) function must not return anything.%s', addendum);
        }
      }
      ReactNoop.flushPassiveEffects();
      // we want the user to not expect a return,
      // but we want to warn if they use it like they can await on it.
      return {
        then: function () {
          {
            warningWithoutStack$1(false, 'Do not await the result of calling ReactNoop.act(...), it is not a Promise.');
          }
        }
      };
    },
    flushSync: function (fn) {
      yieldedValues = [];
      NoopRenderer.flushSync(fn);
      return yieldedValues;
    },
    flushPassiveEffects: function () {
      // Trick to flush passive effects without exposing an internal API:
      // Create a throwaway root and schedule a dummy update on it.
      var rootID = 'bloopandthenmoreletterstoavoidaconflict';
      var container = { rootID: rootID, children: [] };
      rootContainers.set(rootID, container);
      var root = NoopRenderer.createContainer(container, true, false);
      NoopRenderer.updateContainer(null, root, null, null);
    },


    // Logs the current state of the tree.
    dumpTree: function () {
      var _console;

      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      var root = roots.get(rootID);
      var rootContainer = rootContainers.get(rootID);
      if (!root || !rootContainer) {
        console.log('Nothing rendered yet.');
        return;
      }

      var bufferedLog = [];
      function log() {
        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        bufferedLog.push.apply(bufferedLog, args.concat(['\n']));
      }

      function logHostInstances(children, depth) {
        for (var i = 0; i < children.length; i++) {
          var child = children[i];
          var indent = '  '.repeat(depth);
          if (typeof child.text === 'string') {
            log(indent + '- ' + child.text);
          } else {
            // $FlowFixMe - The child should've been refined now.
            log(indent + '- ' + child.type + '#' + child.id);
            // $FlowFixMe - The child should've been refined now.
            logHostInstances(child.children, depth + 1);
          }
        }
      }
      function logContainer(container, depth) {
        log('  '.repeat(depth) + '- [root#' + container.rootID + ']');
        logHostInstances(container.children, depth + 1);
      }

      function logUpdateQueue(updateQueue, depth) {
        log('  '.repeat(depth + 1) + 'QUEUED UPDATES');
        var firstUpdate = updateQueue.firstUpdate;
        if (!firstUpdate) {
          return;
        }

        log('  '.repeat(depth + 1) + '~', '[' + firstUpdate.expirationTime + ']');
        while (firstUpdate.next) {
          log('  '.repeat(depth + 1) + '~', '[' + firstUpdate.expirationTime + ']');
        }
      }

      function logFiber(fiber, depth) {
        log('  '.repeat(depth) + '- ' + (
        // need to explicitly coerce Symbol to a string
        fiber.type ? fiber.type.name || fiber.type.toString() : '[root]'), '[' + fiber.childExpirationTime + (fiber.pendingProps ? '*' : '') + ']');
        if (fiber.updateQueue) {
          logUpdateQueue(fiber.updateQueue, depth);
        }
        // const childInProgress = fiber.progressedChild;
        // if (childInProgress && childInProgress !== fiber.child) {
        //   log(
        //     '  '.repeat(depth + 1) + 'IN PROGRESS: ' + fiber.pendingWorkPriority,
        //   );
        //   logFiber(childInProgress, depth + 1);
        //   if (fiber.child) {
        //     log('  '.repeat(depth + 1) + 'CURRENT');
        //   }
        // } else if (fiber.child && fiber.updateQueue) {
        //   log('  '.repeat(depth + 1) + 'CHILDREN');
        // }
        if (fiber.child) {
          logFiber(fiber.child, depth + 1);
        }
        if (fiber.sibling) {
          logFiber(fiber.sibling, depth);
        }
      }

      log('HOST INSTANCES:');
      logContainer(rootContainer, 0);
      log('FIBERS:');
      logFiber(root.current, 0);

      (_console = console).log.apply(_console, bufferedLog);
    },
    flushWithoutCommitting: function (expectedFlush) {
      var rootID = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_ROOT_ID;

      var root = roots.get(rootID);
      var expiration = NoopRenderer.computeUniqueAsyncExpiration();
      var batch = {
        _defer: true,
        _expirationTime: expiration,
        _onComplete: function () {
          root.firstBatch = null;
        },
        _next: null
      };
      root.firstBatch = batch;
      var actual = ReactNoop.flush();
      expect(actual).toEqual(expectedFlush);
      return function (expectedCommit) {
        batch._defer = false;
        NoopRenderer.flushRoot(root, expiration);
        expect(yieldedValues).toEqual(expectedCommit);
      };
    },
    getRoot: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      return roots.get(rootID);
    }
  };

  return ReactNoop;
}

/**
 * This is a renderer of React that doesn't have a render target output.
 * It is useful to demonstrate the internals of the reconciler in isolation
 * and for testing semantics of reconciliation separate from the host
 * environment.
 */

var ReactNoopPersistent = createReactNoop(ReactFiberPersistentReconciler, // reconciler
false // useMutation
);



var ReactNoopPersistent$2 = Object.freeze({
	default: ReactNoopPersistent
});

var ReactNoopPersistent$3 = ( ReactNoopPersistent$2 && ReactNoopPersistent ) || ReactNoopPersistent$2;

// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
var persistent = ReactNoopPersistent$3.default || ReactNoopPersistent$3;

module.exports = persistent;
  })();
}


================================================
FILE: vendors/react-noop-renderer/cjs/react-noop-renderer-server.development.js
================================================
/** @license React v16.6.1
 * react-noop-renderer-server.development.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';



if (process.env.NODE_ENV !== "production") {
  (function() {
'use strict';

var ReactFizzStreamer = require('react-stream');

/**
 * This is a renderer of React that doesn't have a render target output.
 * It is useful to demonstrate the internals of the reconciler in isolation
 * and for testing semantics of reconciliation separate from the host
 * environment.
 */

var ReactNoopServer = ReactFizzStreamer({
  scheduleWork: function (callback) {
    callback();
  },
  beginWriting: function (destination) {},
  writeChunk: function (destination, buffer) {
    destination.push(JSON.parse(Buffer.from(buffer).toString('utf8')));
  },
  completeWriting: function (destination) {},
  close: function (destination) {},
  flushBuffered: function (destination) {},
  convertStringToBuffer: function (content) {
    return Buffer.from(content, 'utf8');
  },
  formatChunk: function (type, props) {
    return Buffer.from(JSON.stringify({ type: type, props: props }), 'utf8');
  }
});

function render(children) {
  var destination = [];
  var request = ReactNoopServer.createRequest(children, destination);
  ReactNoopServer.startWork(request);
  return destination;
}

var ReactNoopServer$1 = {
  render: render
};

var ReactNoopServer$2 = Object.freeze({
	default: ReactNoopServer$1
});

var ReactNoopServer$3 = ( ReactNoopServer$2 && ReactNoopServer$1 ) || ReactNoopServer$2;

// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
var server = ReactNoopServer$3.default || ReactNoopServer$3;

module.exports = server;
  })();
}


================================================
FILE: vendors/react-noop-renderer/cjs/react-noop-renderer.development.js
================================================
/** @license React v16.6.1
 * react-noop-renderer.development.js
 *
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

const regeneratorRuntime = require("regenerator-runtime");

if (process.env.NODE_ENV !== "production") {
  (function() {
'use strict';

var ReactFiberReconciler = require('react-reconciler');
var _assign = require('object-assign');
var expect = require('expect');

// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === 'function' && Symbol.for;

var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7;
var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;

function createPortal(children, containerInfo,
// TODO: figure out the API for cross-renderer implementation.
implementation) {
  var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;

  return {
    // This tag allow us to uniquely identify this as a React Portal
    $$typeof: REACT_PORTAL_TYPE,
    key: key == null ? null : '' + key,
    children: children,
    containerInfo: containerInfo,
    implementation: implementation
  };
}

/**
 * Similar to invariant but only logs a warning if the condition is not met.
 * This can be used to log issues in development environments in critical
 * paths. Removing the logging code for production environments will keep the
 * same logic and follow the same code paths.
 */

var warningWithoutStack = function () {};

{
  warningWithoutStack = function (condition, format) {
    for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
      args[_key - 2] = arguments[_key];
    }

    if (format === undefined) {
      throw new Error('`warningWithoutStack(condition, format, ...args)` requires a warning ' + 'message argument');
    }
    if (args.length > 8) {
      // Check before the condition to catch violations early.
      throw new Error('warningWithoutStack() currently supports at most 8 arguments.');
    }
    if (condition) {
      return;
    }
    if (typeof console !== 'undefined') {
      var argsWithFormat = args.map(function (item) {
        return '' + item;
      });
      argsWithFormat.unshift('Warning: ' + format);

      // We intentionally don't use spread (or .apply) directly because it
      // breaks IE9: https://github.com/facebook/react/issues/13610
      Function.prototype.apply.call(console.error, console, argsWithFormat);
    }
    try {
      // --- Welcome to debugging React ---
      // This error was thrown as a convenience so that you can use this stack
      // to find the callsite that caused this warning to fire.
      var argIndex = 0;
      var message = 'Warning: ' + format.replace(/%s/g, function () {
        return args[argIndex++];
      });
      throw new Error(message);
    } catch (x) {}
  };
}

var warningWithoutStack$1 = warningWithoutStack;

// for .act's return value


var NO_CONTEXT = {};
var UPDATE_SIGNAL = {};
{
  Object.freeze(NO_CONTEXT);
  Object.freeze(UPDATE_SIGNAL);
}

function createReactNoop(reconciler, useMutation) {
  var _marked = /*#__PURE__*/regeneratorRuntime.mark(flushUnitsOfWork);

  var scheduledCallback = null;
  var scheduledCallbackTimeout = -1;
  var scheduledPassiveCallback = null;
  var instanceCounter = 0;
  var hostDiffCounter = 0;
  var hostUpdateCounter = 0;
  var hostCloneCounter = 0;

  function appendChildToContainerOrInstance(parentInstance, child) {
    var index = parentInstance.children.indexOf(child);
    if (index !== -1) {
      parentInstance.children.splice(index, 1);
    }
    parentInstance.children.push(child);
  }

  function appendChildToContainer(parentInstance, child) {
    if (typeof parentInstance.rootID !== 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('appendChildToContainer() first argument is not a container.');
    }
    appendChildToContainerOrInstance(parentInstance, child);
  }

  function appendChild(parentInstance, child) {
    if (typeof parentInstance.rootID === 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('appendChild() first argument is not an instance.');
    }
    appendChildToContainerOrInstance(parentInstance, child);
  }

  function insertInContainerOrInstanceBefore(parentInstance, child, beforeChild) {
    var index = parentInstance.children.indexOf(child);
    if (index !== -1) {
      parentInstance.children.splice(index, 1);
    }
    var beforeIndex = parentInstance.children.indexOf(beforeChild);
    if (beforeIndex === -1) {
      throw new Error('This child does not exist.');
    }
    parentInstance.children.splice(beforeIndex, 0, child);
  }

  function insertInContainerBefore(parentInstance, child, beforeChild) {
    if (typeof parentInstance.rootID !== 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('insertInContainerBefore() first argument is not a container.');
    }
    insertInContainerOrInstanceBefore(parentInstance, child, beforeChild);
  }

  function insertBefore(parentInstance, child, beforeChild) {
    if (typeof parentInstance.rootID === 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('insertBefore() first argument is not an instance.');
    }
    insertInContainerOrInstanceBefore(parentInstance, child, beforeChild);
  }

  function removeChildFromContainerOrInstance(parentInstance, child) {
    var index = parentInstance.children.indexOf(child);
    if (index === -1) {
      throw new Error('This child does not exist.');
    }
    parentInstance.children.splice(index, 1);
  }

  function removeChildFromContainer(parentInstance, child) {
    if (typeof parentInstance.rootID !== 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('removeChildFromContainer() first argument is not a container.');
    }
    removeChildFromContainerOrInstance(parentInstance, child);
  }

  function removeChild(parentInstance, child) {
    if (typeof parentInstance.rootID === 'string') {
      // Some calls to this aren't typesafe.
      // This helps surface mistakes in tests.
      throw new Error('removeChild() first argument is not an instance.');
    }
    removeChildFromContainerOrInstance(parentInstance, child);
  }

  function cloneInstance(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle, keepChildren, recyclableInstance) {
    var clone = {
      id: instance.id,
      type: type,
      children: keepChildren ? instance.children : [],
      text: shouldSetTextContent(type, newProps) ? newProps.children + '' : null,
      prop: newProps.prop,
      hidden: newProps.hidden === true
    };
    Object.defineProperty(clone, 'id', {
      value: clone.id,
      enumerable: false
    });
    Object.defineProperty(clone, 'text', {
      value: clone.text,
      enumerable: false
    });
    hostCloneCounter++;
    return clone;
  }

  function shouldSetTextContent(type, props) {
    if (type === 'errorInBeginPhase') {
      throw new Error('Error in host config.');
    }
    return typeof props.children === 'string' || typeof props.children === 'number';
  }

  var elapsedTimeInMs = 0;

  var sharedHostConfig = {
    getRootHostContext: function () {
      return NO_CONTEXT;
    },
    getChildHostContext: function () {
      return NO_CONTEXT;
    },
    getPublicInstance: function (instance) {
      return instance;
    },
    createInstance: function (type, props) {
      if (type === 'errorInCompletePhase') {
        throw new Error('Error in host config.');
      }
      var inst = {
        id: instanceCounter++,
        type: type,
        children: [],
        text: shouldSetTextContent(type, props) ? props.children + '' : null,
        prop: props.prop,
        hidden: props.hidden === true
      };
      // Hide from unit tests
      Object.defineProperty(inst, 'id', { value: inst.id, enumerable: false });
      Object.defineProperty(inst, 'text', {
        value: inst.text,
        enumerable: false
      });
      return inst;
    },
    appendInitialChild: function (parentInstance, child) {
      parentInstance.children.push(child);
    },
    finalizeInitialChildren: function (domElement, type, props) {
      return false;
    },
    prepareUpdate: function (instance, type, oldProps, newProps) {
      if (type === 'errorInCompletePhase') {
        throw new Error('Error in host config.');
      }
      if (oldProps === null) {
        throw new Error('Should have old props');
      }
      if (newProps === null) {
        throw new Error('Should have new props');
      }
      hostDiffCounter++;
      return UPDATE_SIGNAL;
    },


    shouldSetTextContent: shouldSetTextContent,

    shouldDeprioritizeSubtree: function (type, props) {
      return !!props.hidden;
    },
    createTextInstance: function (text, rootContainerInstance, hostContext, internalInstanceHandle) {
      var inst = { text: text, id: instanceCounter++, hidden: false };
      // Hide from unit tests
      Object.defineProperty(inst, 'id', { value: inst.id, enumerable: false });
      return inst;
    },
    scheduleDeferredCallback: function (callback, options) {
      if (scheduledCallback) {
        throw new Error('Scheduling a callback twice is excessive. Instead, keep track of ' + 'whether the callback has already been scheduled.');
      }
      scheduledCallback = callback;
      if (typeof options === 'object' && options !== null && typeof options.timeout === 'number') {
        var newTimeout = options.timeout;
        if (scheduledCallbackTimeout === -1 || scheduledCallbackTimeout > newTimeout) {
          scheduledCallbackTimeout = elapsedTimeInMs + newTimeout;
        }
      }
      return 0;
    },
    cancelDeferredCallback: function () {
      if (scheduledCallback === null) {
        throw new Error('No callback is scheduled.');
      }
      scheduledCallback = null;
      scheduledCallbackTimeout = -1;
    },


    shouldYield: shouldYield,

    scheduleTimeout: setTimeout,
    cancelTimeout: clearTimeout,
    noTimeout: -1,
    schedulePassiveEffects: function (callback) {
      if (scheduledCallback) {
        throw new Error('Scheduling a callback twice is excessive. Instead, keep track of ' + 'whether the callback has already been scheduled.');
      }
      scheduledPassiveCallback = callback;
    },
    cancelPassiveEffects: function () {
      if (scheduledPassiveCallback === null) {
        throw new Error('No passive effects callback is scheduled.');
      }
      scheduledPassiveCallback = null;
    },
    prepareForCommit: function () {},
    resetAfterCommit: function () {},
    now: function () {
      return elapsedTimeInMs;
    },


    isPrimaryRenderer: true,
    supportsHydration: false
  };

  var hostConfig = useMutation ? _assign({}, sharedHostConfig, {

    supportsMutation: true,
    supportsPersistence: false,

    commitMount: function (instance, type, newProps) {
      // Noop
    },
    commitUpdate: function (instance, updatePayload, type, oldProps, newProps) {
      if (oldProps === null) {
        throw new Error('Should have old props');
      }
      hostUpdateCounter++;
      instance.prop = newProps.prop;
      instance.hidden = newProps.hidden === true;
      if (shouldSetTextContent(type, newProps)) {
        instance.text = newProps.children + '';
      }
    },
    commitTextUpdate: function (textInstance, oldText, newText) {
      hostUpdateCounter++;
      textInstance.text = newText;
    },


    appendChild: appendChild,
    appendChildToContainer: appendChildToContainer,
    insertBefore: insertBefore,
    insertInContainerBefore: insertInContainerBefore,
    removeChild: removeChild,
    removeChildFromContainer: removeChildFromContainer,

    hideInstance: function (instance) {
      instance.hidden = true;
    },
    hideTextInstance: function (textInstance) {
      textInstance.hidden = true;
    },
    unhideInstance: function (instance, props) {
      if (!props.hidden) {
        instance.hidden = false;
      }
    },
    unhideTextInstance: function (textInstance, text) {
      textInstance.hidden = false;
    },
    resetTextContent: function (instance) {
      instance.text = null;
    }
  }) : _assign({}, sharedHostConfig, {
    supportsMutation: false,
    supportsPersistence: true,

    cloneInstance: cloneInstance,

    createContainerChildSet: function (container) {
      return [];
    },
    appendChildToContainerChildSet: function (childSet, child) {
      childSet.push(child);
    },
    finalizeContainerChildren: function (container, newChildren) {},
    replaceContainerChildren: function (container, newChildren) {
      container.children = newChildren;
    },
    cloneHiddenInstance: function (instance, type, props, internalInstanceHandle) {
      var clone = cloneInstance(instance, null, type, props, props, internalInstanceHandle, true, null);
      clone.hidden = true;
      return clone;
    },
    cloneUnhiddenInstance: function (instance, type, props, internalInstanceHandle) {
      var clone = cloneInstance(instance, null, type, props, props, internalInstanceHandle, true, null);
      clone.hidden = props.hidden;
      return clone;
    },
    createHiddenTextInstance: function (text, rootContainerInstance, hostContext, internalInstanceHandle) {
      var inst = { text: text, id: instanceCounter++, hidden: true };
      // Hide from unit tests
      Object.defineProperty(inst, 'id', {
        value: inst.id,
        enumerable: false
      });
      return inst;
    }
  });

  var NoopRenderer = reconciler(hostConfig);

  var rootContainers = new Map();
  var roots = new Map();
  var DEFAULT_ROOT_ID = '<default>';

  var yieldedValues = null;

  var didYield = void 0;
  var unitsRemaining = void 0;

  function shouldYield() {
    if (scheduledCallbackTimeout === -1 || elapsedTimeInMs > scheduledCallbackTimeout) {
      return false;
    } else {
      if (didYield || yieldedValues !== null) {
        return true;
      }
      if (unitsRemaining-- > 0) {
        return false;
      }
      didYield = true;
      return true;
    }
  }

  function flushUnitsOfWork(n) {
    var cb, values;
    return regeneratorRuntime.wrap(function flushUnitsOfWork$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            unitsRemaining = n + 1;
            didYield = false;
            _context.prev = 2;

          case 3:
            if (!(!didYield && scheduledCallback !== null)) {
              _context.next = 14;
              break;
            }

            cb = scheduledCallback;

            scheduledCallback = null;
            cb();

            if (!(yieldedValues !== null)) {
              _context.next = 12;
              break;
            }

            values = yieldedValues;

            yieldedValues = null;
            _context.next = 12;
            return values;

          case 12:
            _context.next = 3;
            break;

          case 14:
            _context.prev = 14;

            unitsRemaining = -1;
            didYield = false;
            return _context.finish(14);

          case 18:
          case 'end':
            return _context.stop();
        }
      }
    }, _marked, this, [[2,, 14, 18]]);
  }

  function childToJSX(child, text) {
    if (text !== null) {
      return text;
    }
    if (child === null) {
      return null;
    }
    if (typeof child === 'string') {
      return child;
    }
    if (Array.isArray(child)) {
      if (child.length === 0) {
        return null;
      }
      if (child.length === 1) {
        return childToJSX(child[0], null);
      }
      // $FlowFixMe
      var _children = child.map(function (c) {
        return childToJSX(c, null);
      });
      if (_children.every(function (c) {
        return typeof c === 'string' || typeof c === 'number';
      })) {
        return _children.join('');
      }
      return _children;
    }
    if (Array.isArray(child.children)) {
      // This is an instance.
      var instance = child;
      var _children2 = childToJSX(instance.children, instance.text);
      var props = { prop: instance.prop };
      if (instance.hidden) {
        props.hidden = true;
      }
      if (_children2 !== null) {
        props.children = _children2;
      }
      return {
        $$typeof: REACT_ELEMENT_TYPE,
        type: instance.type,
        key: null,
        ref: null,
        props: props,
        _owner: null,
        _store: {}
      };
    }
    // This is a text instance
    var textInstance = child;
    if (textInstance.hidden) {
      return '';
    }
    return textInstance.text;
  }

  var ReactNoop = {
    getChildren: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      var container = rootContainers.get(rootID);
      if (container) {
        return container.children;
      } else {
        return null;
      }
    },
    getOrCreateRootContainer: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;
      var isConcurrent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

      var root = roots.get(rootID);
      if (!root) {
        var container = { rootID: rootID, children: [] };
        rootContainers.set(rootID, container);
        root = NoopRenderer.createContainer(container, isConcurrent, false);
        roots.set(rootID, root);
      }
      return root.current.stateNode.containerInfo;
    },
    getChildrenAsJSX: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      var children = childToJSX(ReactNoop.getChildren(rootID), null);
      if (children === null) {
        return null;
      }
      if (Array.isArray(children)) {
        return {
          $$typeof: REACT_ELEMENT_TYPE,
          type: REACT_FRAGMENT_TYPE,
          key: null,
          ref: null,
          props: { children: children },
          _owner: null,
          _store: {}
        };
      }
      return children;
    },
    createPortal: function (children, container) {
      var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;

      return createPortal(children, container, null, key);
    },


    // Shortcut for testing a single root
    render: function (element, callback) {
      ReactNoop.renderToRootWithID(element, DEFAULT_ROOT_ID, callback);
    },
    renderLegacySyncRoot: function (element, callback) {
      var rootID = DEFAULT_ROOT_ID;
      var isConcurrent = false;
      var container = ReactNoop.getOrCreateRootContainer(rootID, isConcurrent);
      var root = roots.get(container.rootID);
      NoopRenderer.updateContainer(element, root, null, callback);
    },
    renderToRootWithID: function (element, rootID, callback) {
      var isConcurrent = true;
      var container = ReactNoop.getOrCreateRootContainer(rootID, isConcurrent);
      var root = roots.get(container.rootID);
      NoopRenderer.updateContainer(element, root, null, callback);
    },
    unmountRootWithID: function (rootID) {
      var root = roots.get(rootID);
      if (root) {
        NoopRenderer.updateContainer(null, root, null, function () {
          roots.delete(rootID);
          rootContainers.delete(rootID);
        });
      }
    },
    findInstance: function (componentOrElement) {
      if (componentOrElement == null) {
        return null;
      }
      // Unsound duck typing.
      var component = componentOrElement;
      if (typeof component.id === 'number') {
        return component;
      }
      {
        return NoopRenderer.findHostInstanceWithWarning(component, 'findInstance');
      }
      return NoopRenderer.findHostInstance(component);
    },
    flushDeferredPri: function () {
      var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity;

      // The legacy version of this function decremented the timeout before
      // returning the new time.
      // TODO: Convert tests to use flushUnitsOfWork or flushAndYield instead.
      var n = timeout / 5 - 1;

      var values = [];
      // eslint-disable-next-line no-for-of-loops/no-for-of-loops
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = flushUnitsOfWork(n)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var value = _step.value;

          values.push.apply(values, value);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return values;
    },
    flush: function () {
      return ReactNoop.flushUnitsOfWork(Infinity);
    },
    flushAndYield: function () {
      var unitsOfWork = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Infinity;

      return flushUnitsOfWork(unitsOfWork);
    },
    flushUnitsOfWork: function (n) {
      var values = yieldedValues || [];
      yieldedValues = null;
      // eslint-disable-next-line no-for-of-loops/no-for-of-loops
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = flushUnitsOfWork(n)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var value = _step2.value;

          values.push.apply(values, value);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2.return) {
            _iterator2.return();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }

      return values;
    },
    flushThrough: function (expected) {
      var actual = [];
      if (expected.length !== 0) {
        // eslint-disable-next-line no-for-of-loops/no-for-of-loops
        var _iteratorNormalCompletion3 = true;
        var _didIteratorError3 = false;
        var _iteratorError3 = undefined;

        try {
          for (var _iterator3 = flushUnitsOfWork(Infinity)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
            var value = _step3.value;

            actual.push.apply(actual, value);
            if (actual.length >= expected.length) {
              break;
            }
          }
        } catch (err) {
          _didIteratorError3 = true;
          _iteratorError3 = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion3 && _iterator3.return) {
              _iterator3.return();
            }
          } finally {
            if (_didIteratorError3) {
              throw _iteratorError3;
            }
          }
        }
      }
      expect(actual).toEqual(expected);
    },
    flushNextYield: function () {
      var actual = null;
      // eslint-disable-next-line no-for-of-loops/no-for-of-loops
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = flushUnitsOfWork(Infinity)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var value = _step4.value;

          actual = value;
          break;
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4.return) {
            _iterator4.return();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }

      return actual !== null ? actual : [];
    },
    flushWithHostCounters: function (fn) {
      hostDiffCounter = 0;
      hostUpdateCounter = 0;
      hostCloneCounter = 0;
      try {
        ReactNoop.flush();
        return useMutation ? {
          hostDiffCounter: hostDiffCounter,
          hostUpdateCounter: hostUpdateCounter
        } : {
          hostDiffCounter: hostDiffCounter,
          hostCloneCounter: hostCloneCounter
        };
      } finally {
        hostDiffCounter = 0;
        hostUpdateCounter = 0;
        hostCloneCounter = 0;
      }
    },
    expire: function (ms) {
      ReactNoop.advanceTime(ms);
      return ReactNoop.flushExpired();
    },
    advanceTime: function (ms) {
      elapsedTimeInMs += ms;
    },
    flushExpired: function () {
      return ReactNoop.flushUnitsOfWork(0);
    },
    yield: function (value) {
      if (yieldedValues === null) {
        yieldedValues = [value];
      } else {
        yieldedValues.push(value);
      }
    },
    clearYields: function () {
      var values = yieldedValues;
      yieldedValues = null;
      return values;
    },
    hasScheduledCallback: function () {
      return !!scheduledCallback;
    },


    batchedUpdates: NoopRenderer.batchedUpdates,

    deferredUpdates: NoopRenderer.deferredUpdates,

    unbatchedUpdates: NoopRenderer.unbatchedUpdates,

    interactiveUpdates: NoopRenderer.interactiveUpdates,

    // maybe this should exist only in the test file
    act: function (callback) {
      // note: keep these warning messages in sync with
      // ReactTestRenderer.js and ReactTestUtils.js
      var result = NoopRenderer.batchedUpdates(callback);
      {
        if (result !== undefined) {
          var addendum = void 0;
          if (result !== null && typeof result.then === 'function') {
            addendum = "\n\nIt looks like you wrote ReactNoop.act(async () => ...) or returned a Promise from it's callback. " + 'Putting asynchronous logic inside ReactNoop.act(...) is not supported.\n';
          } else {
            addendum = ' You returned: ' + result;
          }
          warningWithoutStack$1(false, 'The callback passed to ReactNoop.act(...) function must not return anything.%s', addendum);
        }
      }
      ReactNoop.flushPassiveEffects();
      // we want the user to not expect a return,
      // but we want to warn if they use it like they can await on it.
      return {
        then: function () {
          {
            warningWithoutStack$1(false, 'Do not await the result of calling ReactNoop.act(...), it is not a Promise.');
          }
        }
      };
    },
    flushSync: function (fn) {
      yieldedValues = [];
      NoopRenderer.flushSync(fn);
      return yieldedValues;
    },
    flushPassiveEffects: function () {
      // Trick to flush passive effects without exposing an internal API:
      // Create a throwaway root and schedule a dummy update on it.
      var rootID = 'bloopandthenmoreletterstoavoidaconflict';
      var container = { rootID: rootID, children: [] };
      rootContainers.set(rootID, container);
      var root = NoopRenderer.createContainer(container, true, false);
      NoopRenderer.updateContainer(null, root, null, null);
    },


    // Logs the current state of the tree.
    dumpTree: function () {
      var _console;

      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      var root = roots.get(rootID);
      var rootContainer = rootContainers.get(rootID);
      if (!root || !rootContainer) {
        console.log('Nothing rendered yet.');
        return;
      }

      var bufferedLog = [];
      function log() {
        for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        bufferedLog.push.apply(bufferedLog, args.concat(['\n']));
      }

      function logHostInstances(children, depth) {
        for (var i = 0; i < children.length; i++) {
          var child = children[i];
          var indent = '  '.repeat(depth);
          if (typeof child.text === 'string') {
            log(indent + '- ' + child.text);
          } else {
            // $FlowFixMe - The child should've been refined now.
            log(indent + '- ' + child.type + '#' + child.id);
            // $FlowFixMe - The child should've been refined now.
            logHostInstances(child.children, depth + 1);
          }
        }
      }
      function logContainer(container, depth) {
        log('  '.repeat(depth) + '- [root#' + container.rootID + ']');
        logHostInstances(container.children, depth + 1);
      }

      function logUpdateQueue(updateQueue, depth) {
        log('  '.repeat(depth + 1) + 'QUEUED UPDATES');
        var firstUpdate = updateQueue.firstUpdate;
        if (!firstUpdate) {
          return;
        }

        log('  '.repeat(depth + 1) + '~', '[' + firstUpdate.expirationTime + ']');
        while (firstUpdate.next) {
          log('  '.repeat(depth + 1) + '~', '[' + firstUpdate.expirationTime + ']');
        }
      }

      function logFiber(fiber, depth) {
        log('  '.repeat(depth) + '- ' + (
        // need to explicitly coerce Symbol to a string
        fiber.type ? fiber.type.name || fiber.type.toString() : '[root]'), '[' + fiber.childExpirationTime + (fiber.pendingProps ? '*' : '') + ']');
        if (fiber.updateQueue) {
          logUpdateQueue(fiber.updateQueue, depth);
        }
        // const childInProgress = fiber.progressedChild;
        // if (childInProgress && childInProgress !== fiber.child) {
        //   log(
        //     '  '.repeat(depth + 1) + 'IN PROGRESS: ' + fiber.pendingWorkPriority,
        //   );
        //   logFiber(childInProgress, depth + 1);
        //   if (fiber.child) {
        //     log('  '.repeat(depth + 1) + 'CURRENT');
        //   }
        // } else if (fiber.child && fiber.updateQueue) {
        //   log('  '.repeat(depth + 1) + 'CHILDREN');
        // }
        if (fiber.child) {
          logFiber(fiber.child, depth + 1);
        }
        if (fiber.sibling) {
          logFiber(fiber.sibling, depth);
        }
      }

      log('HOST INSTANCES:');
      logContainer(rootContainer, 0);
      log('FIBERS:');
      logFiber(root.current, 0);

      (_console = console).log.apply(_console, bufferedLog);
    },
    flushWithoutCommitting: function (expectedFlush) {
      var rootID = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_ROOT_ID;

      var root = roots.get(rootID);
      var expiration = NoopRenderer.computeUniqueAsyncExpiration();
      var batch = {
        _defer: true,
        _expirationTime: expiration,
        _onComplete: function () {
          root.firstBatch = null;
        },
        _next: null
      };
      root.firstBatch = batch;
      var actual = ReactNoop.flush();
      expect(actual).toEqual(expectedFlush);
      return function (expectedCommit) {
        batch._defer = false;
        NoopRenderer.flushRoot(root, expiration);
        expect(yieldedValues).toEqual(expectedCommit);
      };
    },
    getRoot: function () {
      var rootID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_ROOT_ID;

      return roots.get(rootID);
    }
  };

  return ReactNoop;
}

/**
 * This is a renderer of React that doesn't have a render target output.
 * It is useful to demonstrate the internals of the reconciler in isolation
 * and for testing semantics of reconciliation separate from the host
 * environment.
 */

var ReactNoop = createReactNoop(ReactFiberReconciler, // reconciler
true // useMutation
);



var ReactNoop$2 = Object.freeze({
	default: ReactNoop
});

var ReactNoop$3 = ( ReactNoop$2 && ReactNoop ) || ReactNoop$2;

// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
var reactNoopRenderer = ReactNoop$3.default || ReactNoop$3;

module.exports = reactNoopRenderer;
  })();
}


================================================
FILE: vendors/react-noop-renderer/index.js
================================================
'use strict';

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./cjs/react-noop-renderer.production.min.js');
} else {
  module.exports = require('./cjs/react-noop-renderer.development.js');
}


================================================
FILE: vendors/react-noop-renderer/package.json
================================================
{
  "name": "react-noop-renderer",
  "version": "16.0.0",
  "private": true,
  "description": "React package for testing the Fiber reconciler.",
  "main": "index.js",
  "repository": {
    "type" : "git",
    "url" : "https://github.com/facebook/react.git",
    "directory": "packages/react-noop-renderer"
  },
  "license": "MIT",
  "dependencies": {
    "object-assign": "^4.1.1",
    "prop-types": "^15.6.2",
    "regenerator-runtime": "^0.11.0",
    "react-reconciler": "*",
    "react-stream": "*"
  },
  "peerDependencies": {
    "react": "^16.0.0"
  },
  "files": [
    "LICENSE",
    "README.md",
    "build-info.json",
    "index.js",
    "persistent.js",
    "server.js",
    "cjs/"
  ]
}


================================================
FILE: vendors/react-noop-renderer/persistent.js
================================================
'use strict';

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./cjs/react-noop-renderer-persistent.production.min.js');
} else {
  module.exports = require('./cjs/react-noop-renderer-persistent.development.js');
}


================================================
FILE: vendors/react-noop-renderer/server.js
================================================
'use strict';

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./cjs/react-noop-renderer-server.production.min.js');
} else {
  module.exports = require('./cjs/react-noop-renderer-server.development.js');
}
Download .txt
gitextract_5sudl4xz/

├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── babel.config.js
├── index.d.ts
├── package.json
├── polyfill.js
├── scripts/
│   ├── alertFlag.sh
│   └── jest/
│       ├── matchers/
│       │   └── toWarnDev.js
│       ├── setupTests.js
│       └── shouldIgnoreConsoleError.js
├── src/
│   ├── ReactCurrentDispatcher.js
│   ├── ReactHookEffectTags.js
│   ├── ReactHooks.js
│   ├── ReactSideEffectTags.js
│   ├── __mocks__/
│   │   └── scheduleCallback.js
│   ├── index.js
│   ├── objectIs.js
│   ├── polyfill.js
│   ├── scheduleCallback.js
│   └── withHooks.js
├── tests/
│   ├── ReactHooksWithNoopRenderer.test.js
│   └── ReactHooksWithReactDOM.test.js
└── vendors/
    └── react-noop-renderer/
        ├── LICENSE
        ├── README.md
        ├── cjs/
        │   ├── react-noop-renderer-persistent.development.js
        │   ├── react-noop-renderer-server.development.js
        │   └── react-noop-renderer.development.js
        ├── index.js
        ├── package.json
        ├── persistent.js
        └── server.js
Download .txt
SYMBOL INDEX (146 symbols across 13 files)

FILE: index.d.ts
  type WithHooks (line 3) | type WithHooks = <T>(component: React.SFC<T>) => React.SFC<T>;

FILE: scripts/jest/matchers/toWarnDev.js
  function normalizeCodeLocInfo (line 7) | function normalizeCodeLocInfo(str) {

FILE: scripts/jest/setupTests.js
  constant NODE_ENV (line 8) | const NODE_ENV = process.env.NODE_ENV;

FILE: src/ReactHooks.js
  function resolveDispatcher (line 13) | function resolveDispatcher() {
  function useContext (line 23) | function useContext(
  function useState (line 30) | function useState(initialState) {
  function useReducer (line 35) | function useReducer(
  function useRef (line 44) | function useRef(initialValue) {
  function useEffect (line 49) | function useEffect(
  function useLayoutEffect (line 57) | function useLayoutEffect(
  function useCallback (line 65) | function useCallback(
  function useMemo (line 73) | function useMemo(
  function useImperativeHandle (line 81) | function useImperativeHandle(

FILE: src/objectIs.js
  function is (line 13) | function is(x, y) {

FILE: src/polyfill.js
  function shouldConstruct (line 10) | function shouldConstruct(Component) {
  function isSimpleFunctionComponent (line 15) | function isSimpleFunctionComponent(type) {
  function hasHooks (line 19) | function hasHooks(fn) {

FILE: src/scheduleCallback.js
  function scheduleCallback (line 1) | function scheduleCallback(callback) {

FILE: src/withHooks.js
  constant RE_RENDER_LIMIT (line 17) | const RE_RENDER_LIMIT = 25;
  function markWorkInProgressReceivedUpdate (line 36) | function markWorkInProgressReceivedUpdate() {
  function basicStateReducer (line 40) | function basicStateReducer(state, action) {
  function prepareToUseHooks (line 44) | function prepareToUseHooks(current) {
  function resetHooks (line 49) | function resetHooks() {
  function mountWorkInProgressHook (line 64) | function mountWorkInProgressHook() {
  function updateWorkInProgressHook (line 85) | function updateWorkInProgressHook() {
  function createFunctionComponentUpdateQueue (line 125) | function createFunctionComponentUpdateQueue() {
  function areHookInputsEqual (line 131) | function areHookInputsEqual(nextDeps, prevDeps) {
  function mountState (line 145) | function mountState(initialState) {
  function updateState (line 161) | function updateState(initialState) {
  function pushEffect (line 165) | function pushEffect(tag, create, destroy, deps) {
  function pushContext (line 191) | function pushContext(context) {
  function mountRef (line 204) | function mountRef(initialValue) {
  function updateRef (line 211) | function updateRef() {
  function mountEffectImpl (line 216) | function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
  function updateEffectImpl (line 223) | function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) {
  function mountEffect (line 244) | function mountEffect(create, deps) {
  function updateEffect (line 248) | function updateEffect(create, deps) {
  function mountLayoutEffect (line 252) | function mountLayoutEffect(create, deps) {
  function updateLayoutEffect (line 256) | function updateLayoutEffect(create, deps) {
  function imperativeHandleEffect (line 260) | function imperativeHandleEffect(create, ref) {
  function mountImperativeHandle (line 278) | function mountImperativeHandle(ref, create, deps) {
  function updateImperativeHandle (line 290) | function updateImperativeHandle(ref, create, deps) {
  function mountContext (line 302) | function mountContext(Context) {
  function mountReducer (line 307) | function mountReducer(reducer, initialArg, init) {
  function updateReducer (line 331) | function updateReducer(reducer, initialArg, init) {
  function mountCallback (line 442) | function mountCallback(callback, deps) {
  function updateCallback (line 449) | function updateCallback(callback, deps) {
  function mountMemo (line 465) | function mountMemo(nextCreate, deps) {
  function updateMemo (line 473) | function updateMemo(nextCreate, deps) {
  function flushPassiveEffects (line 491) | function flushPassiveEffects() {
  function dispatchAction (line 499) | function dispatchAction(instance, queue, action) {
  function withHooks (line 604) | function withHooks(render) {

FILE: tests/ReactHooksWithNoopRenderer.test.js
  function span (line 22) | function span(prop) {
  function Text (line 26) | function Text(props) {
  function Counter (line 60) | function Counter(props, ref) {
  function Counter (line 81) | function Counter(props, ref) {
  function Counter (line 101) | function Counter(props, ref) {
  function Counter (line 122) | function Counter() {
  function Counter (line 144) | function Counter(props, ref) {
  function Counter (line 166) | function Counter(props) {
  function ScrollView (line 189) | function ScrollView({ row: newRow }) {
  function Counter (line 228) | function Counter({ row: newRow }) {
  function Counter (line 243) | function Counter({ row: newRow }) {
  function Counter (line 268) | function Counter({ row: newRow }) {
  function reducer (line 281) | function reducer(state, action) {
  function Counter (line 284) | function Counter({ row: newRow }) {
  function reducerA (line 302) | function reducerA(state, action) {
  function reducerB (line 310) | function reducerB(state, action) {
  function Counter (line 319) | function Counter({ row: newRow }, ref) {
  function reducer (line 363) | function reducer(state, action) {
  function Counter (line 374) | function Counter(props, ref) {
  function reducer (line 403) | function reducer(state, action) {
  function Counter (line 414) | function Counter(props, ref) {
  function reducer (line 446) | function reducer(state, action) {
  function Counter (line 450) | function Counter(props, ref) {
  function Counter (line 481) | function Counter(props) {
  function LayoutEffect (line 503) | function LayoutEffect(props) {
  function PassiveEffect (line 509) | function PassiveEffect(props) {
  function PassiveEffect (line 532) | function PassiveEffect(props) {
  function LayoutEffect (line 538) | function LayoutEffect(props) {
  function PassiveEffect (line 567) | function PassiveEffect(props) {
  function LayoutEffect (line 573) | function LayoutEffect(props) {
  function getCommittedText (line 589) | function getCommittedText() {
  function Counter (line 597) | function Counter(props) {
  function Counter (line 622) | function Counter(props) {
  function Counter (line 646) | function Counter(props) {
  function Counter (line 676) | function Counter(props) {
  function Counter (line 710) | function Counter(props) {
  function Counter (line 741) | function Counter(props) {
  function Counter (line 768) | function Counter(props) {
  function Counter (line 788) | function Counter(props) {
  function Counter (line 811) | function Counter(props) {
  function Counter (line 832) | function Counter(props) {
  function effect (line 859) | function effect() {
  function Counter (line 865) | function Counter(props) {
  function Counter (line 887) | function Counter(props) {
  function Counter (line 926) | function Counter(props) {
  function Counter (line 949) | function Counter(props) {
  function Counter (line 978) | function Counter(props) {
  function Counter (line 1011) | function Counter(props) {
  function Counter (line 1054) | function Counter(props) {
  function Counter (line 1092) | function Counter({ count }) {
  function getCommittedText (line 1117) | function getCommittedText() {
  function Counter (line 1125) | function Counter(props) {
  function Counter (line 1144) | function Counter(props) {
  class IncrementButton (line 1183) | class IncrementButton extends React.PureComponent {
    method render (line 1187) | render() {
  function Counter (line 1192) | function Counter({ incrementBy }) {
  function CapitalizedText (line 1234) | function CapitalizedText(props) {
  function LazyCompute (line 1261) | function LazyCompute(props) {
  function computeA (line 1266) | function computeA() {
  function computeB (line 1271) | function computeB() {
  function LazyCompute (line 1290) | function LazyCompute(props) {
  function compute (line 1299) | function compute(val) {
  function useDebouncedCallback (line 1319) | function useDebouncedCallback(callback, ms, inputs) {
  function App (line 1337) | function App() {
  function Counter (line 1374) | function Counter() {
  function reducer (line 1402) | function reducer(state, action) {
  function Counter (line 1406) | function Counter(props, ref) {
  function reducer (line 1432) | function reducer(state, action) {
  function Counter (line 1436) | function Counter(props, ref) {
  function reducer (line 1460) | function reducer(state, action) {
  function Counter (line 1465) | function Counter(props, ref) {
  function App (line 1509) | function App(props) {
  function App (line 1555) | function App(props) {
  function App (line 1591) | function App(props) {
  class Blank (line 1640) | class Blank extends React.PureComponent {
    method render (line 1641) | render() {
    method render (line 1667) | render() {
    method render (line 1698) | render() {
  class Blank (line 1666) | class Blank extends React.PureComponent {
    method render (line 1641) | render() {
    method render (line 1667) | render() {
    method render (line 1698) | render() {
  class Blank (line 1697) | class Blank extends React.PureComponent {
    method render (line 1641) | render() {
    method render (line 1667) | render() {
    method render (line 1698) | render() {

FILE: tests/ReactHooksWithReactDOM.test.js
  class Logger (line 6) | class Logger {
    method yield (line 9) | yield(value) {
    method flush (line 17) | flush() {
    method clearYields (line 23) | clearYields() {
  function Text (line 33) | function Text(props) {
  function LayoutEffect (line 52) | function LayoutEffect(props) {
  function PassiveEffect (line 58) | function PassiveEffect(props) {
  function PassiveEffect (line 83) | function PassiveEffect(props) {
  function LayoutEffect (line 90) | function LayoutEffect(props) {

FILE: vendors/react-noop-renderer/cjs/react-noop-renderer-persistent.development.js
  function createPortal (line 30) | function createPortal(children, containerInfo,
  function createReactNoop (line 105) | function createReactNoop(reconciler, useMutation) {

FILE: vendors/react-noop-renderer/cjs/react-noop-renderer-server.development.js
  function render (line 46) | function render(children) {

FILE: vendors/react-noop-renderer/cjs/react-noop-renderer.development.js
  function createPortal (line 30) | function createPortal(children, containerInfo,
  function createReactNoop (line 105) | function createReactNoop(reconciler, useMutation) {
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (192K chars).
[
  {
    "path": ".gitignore",
    "chars": 56,
    "preview": "/node_modules\n/lib\n/coverage\n/yarn.lock\n/yarn-error.log\n"
  },
  {
    "path": ".travis.yml",
    "chars": 118,
    "preview": "language: node_js\nnode_js:\n  - stable\nscript:\n  - npm test -- --coverage\n  - bash <(curl -s https://codecov.io/bash)\n\n"
  },
  {
    "path": "LICENSE",
    "chars": 1096,
    "preview": "The MIT License\n\nCopyright (c) 2018-present Wei Zhu <yesmeck@gmail.com>\n\nPermission is hereby granted, free of charge, t"
  },
  {
    "path": "README.md",
    "chars": 2594,
    "preview": "# react-with-hooks\n\n[![Build Status](https://img.shields.io/travis/yesmeck/react-with-hooks.svg?style=flat-square)](http"
  },
  {
    "path": "babel.config.js",
    "chars": 142,
    "preview": "module.exports = {\n  presets: ['@babel/preset-env', '@babel/preset-react'],\n  plugins: [\n    '@babel/plugin-proposal-cla"
  },
  {
    "path": "index.d.ts",
    "chars": 1428,
    "preview": "import * as React from 'react';\n\ntype WithHooks = <T>(component: React.SFC<T>) => React.SFC<T>;\n\ndeclare function useCon"
  },
  {
    "path": "package.json",
    "chars": 1408,
    "preview": "{\n  \"name\": \"react-with-hooks\",\n  \"version\": \"1.1.6\",\n  \"description\": \"react hooks polyfill\",\n  \"main\": \"lib/index.js\","
  },
  {
    "path": "polyfill.js",
    "chars": 44,
    "preview": "module.exports = require('./lib/polyfill');\n"
  },
  {
    "path": "scripts/alertFlag.sh",
    "chars": 202,
    "preview": "#!/bin/sh\n\n perl -i -pe's/var debugRenderPhaseSideEffectsForStrictMode = true;/var debugRenderPhaseSideEffectsForStrictM"
  },
  {
    "path": "scripts/jest/matchers/toWarnDev.js",
    "chars": 9749,
    "preview": "'use strict';\n\nconst jestDiff = require('jest-diff');\nconst util = require('util');\nconst shouldIgnoreConsoleError = req"
  },
  {
    "path": "scripts/jest/setupTests.js",
    "chars": 2369,
    "preview": "'use strict';\n\nconst chalk = require('chalk');\nconst util = require('util');\nconst shouldIgnoreConsoleError = require('."
  },
  {
    "path": "scripts/jest/shouldIgnoreConsoleError.js",
    "chars": 938,
    "preview": "'use strict';\n\nmodule.exports = function shouldIgnoreConsoleError(format, args) {\n  if (__DEV__) {\n    if (typeof format"
  },
  {
    "path": "src/ReactCurrentDispatcher.js",
    "chars": 391,
    "preview": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found i"
  },
  {
    "path": "src/ReactHookEffectTags.js",
    "chars": 432,
    "preview": "export const NoEffect = /*             */ 0b00000000;\nexport const UnmountSnapshot = /*      */ 0b00000010;\nexport const"
  },
  {
    "path": "src/ReactHooks.js",
    "chars": 1878,
    "preview": "/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n"
  },
  {
    "path": "src/ReactSideEffectTags.js",
    "chars": 1328,
    "preview": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found i"
  },
  {
    "path": "src/__mocks__/scheduleCallback.js",
    "chars": 368,
    "preview": "let pendingWorks = [];\n\nconst scheduleCallback = callback => {\n  pendingWorks.push(callback);\n  return () => {\n    pendi"
  },
  {
    "path": "src/index.js",
    "chars": 978,
    "preview": "import React from 'react';\nimport withHooks from './withHooks';\nimport * as hooks from './ReactHooks';\n\nconst useNative "
  },
  {
    "path": "src/objectIs.js",
    "chars": 536,
    "preview": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found i"
  },
  {
    "path": "src/polyfill.js",
    "chars": 1878,
    "preview": "import React from 'react';\nimport * as ReactIs from 'react-is';\nimport withHooks from './withHooks';\nimport * as hooks f"
  },
  {
    "path": "src/scheduleCallback.js",
    "chars": 159,
    "preview": "export default function scheduleCallback(callback) {\n  const timer = requestAnimationFrame(callback);\n  return () => {\n "
  },
  {
    "path": "src/withHooks.js",
    "chars": 23330,
    "preview": "import React, { createElement } from 'react';\nimport invariant from 'invariant';\nimport ReactCurrentDispatcher from './R"
  },
  {
    "path": "tests/ReactHooksWithNoopRenderer.test.js",
    "chars": 59185,
    "preview": "\njest.mock('../src/scheduleCallback');\n\nlet React;\nlet ReactNoop;\nlet scheduleCallback;\nlet useState;\nlet useReducer;\nle"
  },
  {
    "path": "tests/ReactHooksWithReactDOM.test.js",
    "chars": 3214,
    "preview": "import '../src/polyfill';\nimport React, { forwardRef, useState, useImperativeHandle, useLayoutEffect, useEffect } from '"
  },
  {
    "path": "vendors/react-noop-renderer/LICENSE",
    "chars": 1086,
    "preview": "MIT License\n\nCopyright (c) Facebook, Inc. and its affiliates.\n\nPermission is hereby granted, free of charge, to any pers"
  },
  {
    "path": "vendors/react-noop-renderer/README.md",
    "chars": 171,
    "preview": "# `react-noop-renderer`\n\nThis package is the renderer we use for debugging [Fiber](https://github.com/facebook/react/iss"
  },
  {
    "path": "vendors/react-noop-renderer/cjs/react-noop-renderer-persistent.development.js",
    "chars": 32977,
    "preview": "/** @license React v16.6.1\n * react-noop-renderer-persistent.development.js\n *\n * Copyright (c) Facebook, Inc. and its a"
  },
  {
    "path": "vendors/react-noop-renderer/cjs/react-noop-renderer-server.development.js",
    "chars": 1861,
    "preview": "/** @license React v16.6.1\n * react-noop-renderer-server.development.js\n *\n * Copyright (c) Facebook, Inc. and its affil"
  },
  {
    "path": "vendors/react-noop-renderer/cjs/react-noop-renderer.development.js",
    "chars": 32858,
    "preview": "/** @license React v16.6.1\n * react-noop-renderer.development.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n"
  },
  {
    "path": "vendors/react-noop-renderer/index.js",
    "chars": 218,
    "preview": "'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n  module.exports = require('./cjs/react-noop-renderer.produc"
  },
  {
    "path": "vendors/react-noop-renderer/package.json",
    "chars": 698,
    "preview": "{\n  \"name\": \"react-noop-renderer\",\n  \"version\": \"16.0.0\",\n  \"private\": true,\n  \"description\": \"React package for testing"
  },
  {
    "path": "vendors/react-noop-renderer/persistent.js",
    "chars": 240,
    "preview": "'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n  module.exports = require('./cjs/react-noop-renderer-persis"
  },
  {
    "path": "vendors/react-noop-renderer/server.js",
    "chars": 232,
    "preview": "'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n  module.exports = require('./cjs/react-noop-renderer-server"
  }
]

About this extraction

This page contains the full source code of the yesmeck/react-with-hooks GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (179.8 KB), approximately 44.5k tokens, and a symbol index with 146 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!