[
  {
    "path": ".gitignore",
    "content": "/build/\n/node_modules/\n"
  },
  {
    "path": ".prettierignore",
    "content": "package.json\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js: 8\ncache:\n  directories:\n  - \"$HOME/.npm\"\n  - \"$HOME/.pkg-cache\"\nenv:\n- NPM_TAG=$([[ \"$TRAVIS_TAG\" == *-* ]] && echo \"next\" || echo \"latest\")\nscript:\n- npm test\n- npm run build\ndeploy:\n- provider: npm\n  skip_cleanup: true\n  email: npm@mjackson.me\n  tag: \"$NPM_TAG\"\n  api_key:\n    secure: Ouhk1VI9D8JUihTJl16S2yVYHu1ngFEbmrrq6KJzTCD69N4NiyvXzMYhN97K/R0twQqnxS10aAufPvXnFtTvQz48/USGp34gSzLySSqWCXsCpOothsew4SUDqHZPdLIUJqwhpYyJsyCtDbwf8cOTgxlbXW+DE8Y1s0LTJjbbJrg2RlwNjIdYeAjfDQuO2nL3zHPAGJQ/mYJEyicZ6T2H46O4kLuzWvocvUYnEV/j/gtBtBCukg9UG//YxHJVlNfeRXYCiQ/mf5ReCY7zgghK+eJXiaKJZ+l/hV2sp7C893YwKs1IQJ5kn/liwtJfqLGSKrsw7jwu1AESx1jhQsdhCJx5pj61BUTtAGF1acetiD7/MmIHcuDUYqiVsK38UYUxW3XUIOOWH8FpcAJ3+tOpO34kDd4LCBxe09BMbDaGruuSh7+JmbBKNgvX+kJu8b4I80vRs0SrrF9lqdjQ9q/BqwnxbBWXhCZo6dDZEEwwNtLyz6hiuafnZKZgZGb9gcNQ/kwccSnZuifhnNU5nHJL9eJJrAL+XY0l8OWVOMbmuX+iSW7b0yVWqgf3bTiAez2fUUhx1bWFQlOPo/Z5I8y2zZjzCKdFOk59J4hFAhtMGkw3LJmoCyqkVGxR2x1TnH0z8R8ScBZafV8RK4/GDQnOxNIPHIPtdRn8XIXtGkev/YE=\n  on:\n    tags: true\n    condition: '\"$TRAVIS_TAG\" =~ ^v[0-9]'\n- provider: releases\n  skip_cleanup: true\n  file: build/*.zip\n  file_glob: true\n  prerelease: true\n  api_key:\n    secure: RFzhM7HoiSqoOt79Y1Obx7RkgO4UujKLTyqgci6vln0x5A/DchUh7rErpvDLNzvrDeIIp5S41MeQ+CJuVnL5BSWvhsf50/qmSfY2iky3Gl8r5qDG0uKffwPv5Pw+TmtiS3hy9n7PY4Py6u+2fIUChK7OKbPfvvjGLNWAqUi+B9U1c9qOBkHg2LkH+XdtO4dwsjHB/mZ4s10PntLfI6mA0RXIW8/mhYD4gYTWg/DtuenNMcZKDAP+z+GWZr8cen7haMOtoYqY9SA103VgeudXpSzZr5JKSMGnx6YrHicsGaRIal69sC6RspelJsW2+6yaQtIWH8zvb9IvFPv9QP3xYEftVkqxJXr9fsDBVFZIkrF3fCBf7at8UT1CVz3kEH07oc+RZahnVBNqvTbelO32whY2wSV7QBVg6xf0UEeP+un9eBIn1M9AUXiH90KskNVu+Gcs0kNqurpo/cEXXcAuGxK/2KGyfJkg9MKx1B6FmyW1QOIS8ZGOwiUha77fudDq+PUTrjByY2NEyk1GhUmildyoGx5Ds+vwqgBHHkGu7VVitltX7SnnMh48E3AeylYHE2iMSfDRujRefOgL3sEAnHjhU3yBnfRdPsD7jdi/Rux1qzbpVdK5u7gPxrr9SHYc49zVd6e7075UC7twiV99NQoYUpI+7f2q1KffRRt+q24=\n  on:\n    tags: true\n    condition: '\"$TRAVIS_TAG\" =~ ^v[0-9] && \"$NPM_TAG\" = \"next\"'\n- provider: releases\n  skip_cleanup: true\n  file: build/*.zip\n  file_glob: true\n  prerelease: false\n  api_key:\n    secure: RFzhM7HoiSqoOt79Y1Obx7RkgO4UujKLTyqgci6vln0x5A/DchUh7rErpvDLNzvrDeIIp5S41MeQ+CJuVnL5BSWvhsf50/qmSfY2iky3Gl8r5qDG0uKffwPv5Pw+TmtiS3hy9n7PY4Py6u+2fIUChK7OKbPfvvjGLNWAqUi+B9U1c9qOBkHg2LkH+XdtO4dwsjHB/mZ4s10PntLfI6mA0RXIW8/mhYD4gYTWg/DtuenNMcZKDAP+z+GWZr8cen7haMOtoYqY9SA103VgeudXpSzZr5JKSMGnx6YrHicsGaRIal69sC6RspelJsW2+6yaQtIWH8zvb9IvFPv9QP3xYEftVkqxJXr9fsDBVFZIkrF3fCBf7at8UT1CVz3kEH07oc+RZahnVBNqvTbelO32whY2wSV7QBVg6xf0UEeP+un9eBIn1M9AUXiH90KskNVu+Gcs0kNqurpo/cEXXcAuGxK/2KGyfJkg9MKx1B6FmyW1QOIS8ZGOwiUha77fudDq+PUTrjByY2NEyk1GhUmildyoGx5Ds+vwqgBHHkGu7VVitltX7SnnMh48E3AeylYHE2iMSfDRujRefOgL3sEAnHjhU3yBnfRdPsD7jdi/Rux1qzbpVdK5u7gPxrr9SHYc49zVd6e7075UC7twiV99NQoYUpI+7f2q1KffRRt+q24=\n  on:\n    tags: true\n    condition: '\"$TRAVIS_TAG\" =~ ^v[0-9] && \"$NPM_TAG\" = \"latest\"'\n"
  },
  {
    "path": "README.md",
    "content": "# react-stdio [![Travis][build-badge]][build] [![npm package][npm-badge]][npm]\n\n[build-badge]: https://img.shields.io/travis/ReactTraining/react-stdio/master.svg?style=flat-square\n[build]: https://travis-ci.org/ReactTraining/react-stdio\n[npm-badge]: https://img.shields.io/npm/v/react-stdio.svg?style=flat-square\n[npm]: https://www.npmjs.org/package/react-stdio\n\n[react-stdio](https://npmjs.org/package/react-stdio) lets you render [React](https://reactjs.org/) components on the server, regardless of the backend technology you're using.\n\nAs its name suggests, other processes communicate with react-stdio using standard streams. The protocol is JSON, so any environment that can spawn a child process and write JSON to its stdin can use the server. Requests are handled serially, so responses are issued in the same order requests are received.\n\n## Installation\n\nIf you have node installed, you can install using npm:\n\n    $ npm install -g react-stdio\n\nThis will put the `react-stdio` executable in your [`npm bin`](https://docs.npmjs.com/cli/bin).\n\nIf you don't have node installed, you can download the executable for your architecture from [the releases page](https://github.com/ReactTraining/react-stdio/releases).\n\n## Usage\n\nAfter installation, execute `react-stdio` to start the server.\n\nTo render a React component, write a JSON blob to stdin with any of the following properties:\n\n    component       The path to a file that exports a React component (required)\n    props           Any props you want to pass to the component (optional, default is {})\n    render          The type of rendering (optional, default is renderToString)\n\nIf the request is successful, the server will put a JSON blob with `{\"html\":\"...\",\"context\":...}` on stdout. If the request fails for some reason, the JSON will have an `error` property instead of `html`.\n\nExample:\n\n    $ echo '{\"component\":\"./MyComponent\",\"props\":{\"message\":\"hello\"}}' | react-stdio\n\nIf you'd like to use a render method other than [`renderToString`](https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostring) or [`renderToStaticMarkup`](https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostaticmarkup) you can pass a path to a file that exports your rendering function. The signature of your `render` function should be:\n\n```js\nfunction render(element, callback) {\n  // ...\n}\n```\n\nThis function is asynchronous so you have time to do data fetching before you render if you wish. Call `callback(error, html)` when you're finished.\n\n## Environment\n\nYour component file is loaded in a vanilla node.js environment. If you need additional code transforms to run (e.g. using webpack or Browserify) you should create your bundle first and tell react-stdio to load your bundle instead of the plain component file. If you're using webpack to build your bundle, you'll want to use `\"libraryTarget\": \"commonjs2\"` in your config so the bundle exports the component using `module.exports = MyComponent`.\n\nAlso, since react-stdio uses the `stdout` stream for all program output, all writes your code makes to `process.stdout` (including `console.log` statements) are redirected to `process.stderr`.\n\n## Integrations\n\n* [Elixir/Phoenix](http://blog.overstuffedgorilla.com/render-react-with-phoenix/)\n* [Ruby on Rails](https://github.com/aaronvb/rails_react_stdio)\n\nIf you'd like to add an integration here, please submit a PR.\n\n## About\n\nreact-stdio is developed and maintained by [React Training](https://reacttraining.com). If you're interested in learning more about what React can do for your company, please [get in touch](mailto:hello@reacttraining.com)!\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  testURL: 'http://localhost/'\n};\n"
  },
  {
    "path": "modules/__mocks__/ContextComponent.js",
    "content": "const React = require(\"react\");\n\nlet context = {};\n\nfunction ContextComponent() {\n  context.test = true;\n  return React.createElement(\"div\", null, \"I am a context component\");\n}\n\nContextComponent.context = context;\n\nmodule.exports = ContextComponent;\n"
  },
  {
    "path": "modules/__mocks__/TestComponent.js",
    "content": "const React = require(\"react\");\n\nfunction TestComponent() {\n  return React.createElement(\"div\", null, \"I am a test component\");\n}\n\nmodule.exports = TestComponent;\n"
  },
  {
    "path": "modules/__tests__/server-test.js",
    "content": "const path = require('path');\nconst childProcess = require('child_process');\n\nfunction mock(name) {\n  return path.join(__dirname, '..', '__mocks__', name);\n}\n\ndescribe('server', () => {\n  let proc;\n\n  beforeEach(() => {\n    proc = childProcess.spawn(path.join(__dirname, '..', 'cli.js'), {\n      stdio: 'pipe'\n    });\n  });\n\n  afterEach(() => {\n    proc.kill();\n  });\n\n  it('throws an error when component is missing', done => {\n    proc.stdin.write(JSON.stringify({}));\n\n    proc.stdout.once('data', out => {\n      expect(JSON.parse(out).error).toEqual('Missing { component } in request');\n      done();\n    });\n  });\n\n  it('throws an error when component cannot be found', done => {\n    proc.stdin.write(JSON.stringify({ component: 'component.js' }));\n\n    proc.stdout.once('data', out => {\n      expect(JSON.parse(out).error).toEqual(\n        'Cannot load component: component.js'\n      );\n      done();\n    });\n  });\n\n  it('renders the component', done => {\n    proc.stdin.write(\n      JSON.stringify({\n        component: mock('TestComponent.js')\n      })\n    );\n\n    proc.stdout.once('data', out => {\n      expect(JSON.parse(out).html).toMatch('I am a test component');\n      done();\n    });\n  });\n\n  it('renders a component and exposes additional context', done => {\n    proc.stdin.write(\n      JSON.stringify({\n        component: mock('ContextComponent.js')\n      })\n    );\n\n    proc.stdout.once('data', out => {\n      const result = JSON.parse(out);\n      expect(result.html).toMatch('I am a context component');\n      expect(result.context).toEqual({ test: true });\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "modules/cli.js",
    "content": "#!/usr/bin/env node\n\nconst EventStream = require(\"event-stream\");\nconst JSONStream = require(\"JSONStream\");\nconst createRequestHandler = require(\"./index\").createRequestHandler;\n\n// Redirect stdout to stderr, but save a reference so we can\n// still write to stdout.\nconst stdout = process.stdout;\nObject.defineProperty(process, \"stdout\", {\n  configurable: true,\n  enumerable: true,\n  value: process.stderr\n});\n\n// Ensure console.log knows about the new stdout.\nconst Console = require(\"console\").Console;\nObject.defineProperty(global, \"console\", {\n  configurable: true,\n  enumerable: true,\n  value: new Console(process.stdout, process.stderr)\n});\n\n// Read JSON blobs from stdin, pipe output to stdout.\nprocess.stdin\n  .pipe(JSONStream.parse())\n  .pipe(EventStream.map(createRequestHandler(process.cwd())))\n  .pipe(stdout);\n"
  },
  {
    "path": "modules/index.js",
    "content": "const path = require(\"path\");\nconst invariant = require(\"invariant\");\nconst ReactDOMServer = require(\"react-dom/server\");\nconst React = require(\"react\");\n\nfunction loadModule(moduleId) {\n  // Clear the require cache, in case the file was\n  // changed since the server was started.\n  const cacheKey = require.resolve(moduleId);\n  delete require.cache[cacheKey];\n\n  const moduleExports = require(moduleId);\n\n  // Return exports.default if using ES modules.\n  if (moduleExports && moduleExports.default) {\n    return moduleExports.default;\n  }\n\n  return moduleExports;\n}\n\nfunction renderToStaticMarkup(element, callback) {\n  callback(null, ReactDOMServer.renderToStaticMarkup(element));\n}\n\nfunction renderToString(element, callback) {\n  callback(null, ReactDOMServer.renderToString(element));\n}\n\nfunction handleRequest(workingDir, request, callback) {\n  const componentPath = request.component;\n  const renderMethod = request.render;\n  const props = request.props;\n\n  invariant(componentPath != null, \"Missing { component } in request\");\n\n  let render;\n  if (renderMethod == null || renderMethod === \"renderToString\") {\n    render = renderToString;\n  } else if (renderMethod === \"renderToStaticMarkup\") {\n    render = renderToStaticMarkup;\n  } else {\n    const methodFile = path.resolve(workingDir, renderMethod);\n\n    try {\n      render = loadModule(methodFile);\n    } catch (error) {\n      if (error.code !== \"MODULE_NOT_FOUND\") {\n        process.stderr.write(error.stack + \"\\n\");\n      }\n    }\n  }\n\n  invariant(\n    typeof render === \"function\",\n    \"Cannot load render method: %s\",\n    renderMethod\n  );\n\n  const componentFile = path.resolve(workingDir, componentPath);\n\n  let component;\n  try {\n    component = loadModule(componentFile);\n  } catch (error) {\n    if (error.code !== \"MODULE_NOT_FOUND\") {\n      process.stderr.write(error.stack + \"\\n\");\n    }\n  }\n\n  invariant(component != null, \"Cannot load component: %s\", componentPath);\n\n  render(React.createElement(component, props), function(err, html) {\n    callback(err, html, component.context);\n  });\n}\n\nfunction createRequestHandler(workingDir) {\n  return function(request, callback) {\n    try {\n      handleRequest(workingDir, request, function(error, html, context) {\n        if (error) {\n          callback(error);\n        } else if (typeof html !== \"string\") {\n          // Crash the server process.\n          callback(new Error(\"Render method must return a string\"));\n        } else {\n          callback(null, JSON.stringify({ html: html, context: context }));\n        }\n      });\n    } catch (error) {\n      callback(null, JSON.stringify({ error: error.message }));\n    }\n  };\n}\n\nmodule.exports = {\n  createRequestHandler\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-stdio\",\n  \"version\": \"3.4.8\",\n  \"description\": \"Render React.js components on any backend\",\n  \"author\": \"Michael Jackson\",\n  \"license\": \"MIT\",\n  \"bin\": {\n    \"react-stdio\": \"./modules/cli.js\"\n  },\n  \"files\": [\n    \"modules/cli.js\",\n    \"modules/index.js\"\n  ],\n  \"preferGlobal\": true,\n  \"repository\": \"ReactTraining/react-stdio\",\n  \"scripts\": {\n    \"build\": \"./scripts/build.sh\",\n    \"clean\": \"git clean -fdX .\",\n    \"test\": \"jest\"\n  },\n  \"dependencies\": {\n    \"JSONStream\": \"^1.0.7\",\n    \"event-stream\": \"3.3.4\",\n    \"invariant\": \"^2.2.0\",\n    \"react\": \"^16.2.0\",\n    \"react-dom\": \"^16.2.0\"\n  },\n  \"devDependencies\": {\n    \"jest\": \"^22.1.4\",\n    \"pkg\": \"^4.3.4\"\n  },\n  \"jest\": {\n    \"testPathIgnorePatterns\": [\n      \"/node_modules/\",\n      \"__tests__/mocks\"\n    ]\n  }\n}\n"
  },
  {
    "path": "scripts/build.sh",
    "content": "#!/bin/bash\n\nmkdir -p build\n\ntag=${TRAVIS_TAG:-\"v$npm_package_version\"}\n\n# TODO: Enable x86 builds when https://github.com/zeit/pkg/issues/310 is fixed\nplatforms=( win-x64 linux-x64 macos )\n\nfor platform in \"${platforms[@]}\"\ndo\n  archive=react-stdio-$tag-$platform\n\n  echo \"Creating $archive build...\"\n\n  pkg modules/cli.js -t $platform -o build/$archive/react-stdio\n  echo \"$tag\" > build/$archive/version\n\n  cd build\n  zip -q -r $archive.zip $archive\n  cd - > /dev/null\ndone\n"
  }
]