[
  {
    "path": ".editorconfig",
    "content": "# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with a newline ending every file\n[*]\nend_of_line = lf\ninsert_final_newline = true\n\n# Matches multiple files with brace expansion notation\n# Set default charset\n[*.{js,json,marko,yml}]\ncharset = utf-8\nindent_style = space\nindent_size = 4\n"
  },
  {
    "path": ".eslintrc",
    "content": "{\n  \"extends\": \"standard\",\n  \"rules\": {\n    \"indent\": [\"error\", 4],\n    \"semi\": [\"error\", \"always\"],\n    \"space-before-function-paren\": [\"off\"],\n    \"no-path-concat\": [\"off\"],\n    \"no-useless-escape\": [\"off\"],\n    \"no-eval\": [\"off\"]\n  }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "/work\n/build\n/.idea/\n/npm-debug.log\n/node_modules\n/*.sublime-workspace\n*.orig\n.DS_Store\ncoverage\n/test/build\n/test/static\n*.actual.js\n*.actual.html\n.lasso-cache\n.cache\n~*\n.nyc_output/\n.vscode\ntest/autotests/prebuild-page/*/static\ntest/autotests/prebuild-page/*/*.prebuild.json"
  },
  {
    "path": ".npmignore",
    "content": "/work\n/build\n/.idea/\n/npm-debug.log\n/node_modules\n/*.sublime-workspace\n*.orig\n.DS_Store\ncoverage\n/test/build\n*.actual.js\n*.actual.html\n.lasso-cache\n.cache\n/test\n*.marko.js\n*.dust.js\n.nyc_output/\ncoverage/\n"
  },
  {
    "path": ".travis.yml",
    "content": "node_js:\n- 10\n- 8\n- 6\n\nsudo: false\nlanguage: node_js\n# Use latest version of npm\nbefore_install: npm install -g npm@*\nscript: \"npm test\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Changelog\n=========\n\n# 4.0.3\n- Fix issue where the internal lasso context data was missing for image/resource assets.\n\n# 4.0.2\n- Fix issue with caching page results in production mode.\n\n# 4.0.1\n- Fix regression with the `getImageInfo` api.\n\n# 4.0.0\n- **BREAKING**: Requires a minimum of node 16\n- Upgrades internal dependencies (biggest user facing change being JS/CSS parsing and minification of newer features).\n\n# 3.4.0\n\n- Switches from esprima to espree to parse JavaScript (supports more modern JavaScript).\n\n# 3.3.1\n\n- Adds `.webp` to the list of browser-refresh extensions.\n\n# 3.3.0\n\n- use [terser](https://github.com/terser-js/terser) instead uglify-js because it's [no longer maintained](https://github.com/mishoo/UglifyJS2/issues/3156#issuecomment-392943058).\n\n# 3.2.8\n\n- Fix regression with inline scripts with `externalScriptAttrs`.\n\n# 3.2.7\n\n- Improve support for `defer` and `async` attributes on inline bundles.\n\n# 3.0.0\n\n- **BREAKING**: Remove support for Node 4\n    - Significant refactors. Move to async/await internally.\n    - Traspile for Node 4 support using Babel\n- **BREAKING**: API methods no longer expose callbacks.\n    - Plugins should no longer expect a callback\n    - Plugins should return promises for async tasks\n- **BREAKING**: Marko taglib and taglib-v2 removed\n    - Use `@lasso/marko-taglib` instead\n- Support for passing `cacheKey` property to lasso config\n- Merge `lasso-require` into Lasso\n    - Lasso config `lassoConfig.require.resolver` property has been split out\n    into its own property `lassoConfig.resolver`\n\n```js\nconst lassoConfig: {\n    require: {\n        transforms: ...\n    },\n    resolver: {\n        builtins: {\n            ...\n        }\n    }\n}\n\nconst lasso = lasso.create(lassoConfig);\n```\n\n- Lasso writers now support async `init` functions\n\n```js\nmodule.exports = function(lasso, config) {\n    lasso.config.writer = {\n        async init (lassoContext) {\n            await Promise.resolve();\n        },\n\n        async writeBundle (reader, lassoContext) {\n            const bundle = lassoContext.bundle;\n            bundle.url = 'test.com';\n        },\n\n        async writeResource (reader, lassoContext) {\n            return { url: 'test.com' };\n        }\n    };\n};\n```\n\n# 2.x\n\n## 2.9.x\n\n### 2.9.0\n\n- Fixes #186 - Allow custom require handler to implement getDependencies\n\n## 2.8.x\n\n### 2.8.5\n\n- Use [resolve-from](https://github.com/sindresorhus/resolve-from) to first try and resolve `browser.json`\n\n### 2.8.4\n\n- Fixes #185 - DependencyRegistry has an undefined stream when using `mask-define` for AMD dependencies\n- Increasing default timeout to 10s\n- Other minor internal changes\n\n### 2.8.3\n\n- Internal: use `renderToString` instead of `renderSync` ([PR #182](https://github.com/lasso-js/lasso/pull/182) by [@yomed](https://github.com/yomed))\n\n### 2.8.2\n\n- Fixed #180 - Defining bundles with \"intersection\" does not work for \"require\" dependencies\n\n### 2.8.2\n\n- Fixed #180 - Defining bundles with \"intersection\" does not work for \"require\" dependencies\n\n### 2.8.1\n\n- Fixed #178 - Cache key changes when lasso is reconfigured even if config did not change\n\n### 2.8.0\n\n- Fixed #173 - Bundle attributes\n\n## 2.7.x\n\n### 2.7.0\n\n- Restored Marko v2 compatibility\n\n## 2.6.x\n\n### 2.6.1\n\n- Fixes #171 - Write cache key information to disk for debugging purposes\n\n### 2.6.0\n\n- Added support for a new `relativeUrlsEnabled` configuration option ([PR #167](https://github.com/lasso-js/lasso/pull/167) by [@reid](https://github.com/reid))\n- Upgraded [glob](https://www.npmjs.com/package/glob) version ([PR #166](https://github.com/lasso-js/lasso/pull/166) by [@yomed](https://github.com/yomed))\n- Docs: various improvements to documentation by ([@yomed](https://github.com/yomed))\n\n## 2.5.x\n\n### 2.5.9\n\n- Introduced Koa-compatible middleware ([PR #163](https://github.com/lasso-js/lasso/pull/163) by [@yomed](https://github.com/yomed))\n\n### 2.5.8\n\n- Added tests for #160 - lastSlot configuration option for the require plugin\n\n### 2.5.7\n\n- Upgraded to `raptor-util@2.0.0`\n\n### 2.5.6\n\n- Fixed #156 - Lasso is generating very long names in development triggering `ENAMETOOLONG` error [PR #157](https://github.com/lasso-js/lasso/pull/157) from [@mlrawlings](https://github.com/mlrawlings)\n\n### 2.5.5\n\n- Fixes #147 - EPERM 'operation not permitted' on rename\n- Fixes #148 - css urls resolved incorrectly with multiple pages when bundling disabled\n- Testing: Don't actually read external URLs when running tests\n\n### 2.5.4\n\n- Fixes #149 - if-flag is ignored in async section of browser.json\n\n### 2.5.3\n\n- Updated taglib type and autocomplete information for tooling\n- Docs: Added [Michael Rawlings](https://github.com/mlrawlings) as a maintainer\n\n### 2.5.2\n\n- Added `null`/`undefined` when building async loader metadata\n\n### 2.5.1\n\n- Fixed #146 - Slot timeout causes other slots to timeout\n\n### 2.5.0\n\n- Loader metadata for lazily loading packages is no longer stored in a global variable and is instead integrated with the lasso modules client runtime. This change prevents separate lasso builds of JavaScript libraries from conflicting with each other when both added to the same web page.\n\n### 2.4.2\n\n- Code cleanup for base64 encoding\n\n### 2.4.1\n\n- Fixes #143 - Only encode new lines when using utf8 encoding for data uri\n\n### 2.4.0\n\n- Fixes #141 - Add support for UTF8 encoding inline images in CSS files\n\n## 2.3.x\n\n### 2.3.6\n\n- Fixes #137 - Don't allow double callbacks in case of multiple errors on the same read stream\n\n### 2.3.5\n\n- Fixes #136 - Just use a unique ID for packages if calculateKey() is not implemented\n- Added new events: `beforeAddDependencyToAsyncPageBundle`, `beforeAddDependencyToSyncPageBundle`\n\nExample plugin:\n\n```javascript\nmodule.exports = exports = function(lasso, config) {\n    lasso.on('beforeBuildPage', (event) => {\n        var context = event.context;\n\n        context.on('beforeAddDependencyToSyncPageBundle', (event) => {\n            var dependency = event.dependency;\n\n        });\n\n        context.on('beforeAddDependencyToAsyncPageBundle', (event) => {\n            var dependency = event.dependency;\n\n        });\n    });\n};\n```\n\n### 2.3.4\n\n- Fixed #135 - Incorrect key is calculated for require dependencies in `browser.json` files in some situations\n\n### 2.3.3\n\n- Fixed #134 - The `<lasso-img>` tag breaks bundling when included in a template sent to the browser\n- Fixed #133 - The dependency chain should be included in error messages when walking a dependency graph\n\n### 2.3.2\n\n- Fixed #130 - check inline minification config value ([@yomed](https://github.com/yomed))\n- Updated docs and tests\n\n### 2.3.1\n\n- Minor cleanup\n\n### 2.3.0\n\n- Fixes #84 - Allow minification to only be enabled for inline resources\n- Switched from `jsonminify` to `strip-json-comments`\n\n## 2.2.x\n\n### 2.2.2\n\n- Fixes #128 - getLastModified is broken when using registerRequireType\n\n### 2.2.1\n\n- JavaScript comments are now stripped before parsing JSON config files\n\n### 2.2.0\n\n- Significant improvements to performance and stability\n- Resolved issues related to caching and development mode\n\n## 2.1.x\n\n### 2.1.1\n\n- Fixes #116 - Conditional requireRemap is broken\n\n### 2.1.0\n\n- Fixes #115 - Allow conditional dependencies to be grouped\n\n## 2.0.x\n\n### 2.0.1\n\n- `registerRequireType`, switch condition blocks [PR #113](https://github.com/lasso-js/lasso/pull/113)\n\n### 2.0.0\n\n- Marko v3 compatibility\n\n# 1.x\n\n## 1.16.x\n\n### 1.16.1\n\n- Adds support for fingerprinting inline code blocks for purpose of creating Content Security Policy (CSP) that secures statically built app.\n\n### 1.16.0\n\n-  Added support for custom attributes on script and style tags for slots\n\n## 1.15.x\n\n### 1.15.0\n\n- Adds support for injecting a Content Security Policy nonce into inline script and style tags. Fixes [Issue #93](https://github.com/lasso-js/lasso/issues/93)\n\n## 1.14.x\n\n### 1.14.0\n\n- Fixed #100 - Removed type attributes from `<script>`, `<link>` and `<style>` tags, as recommended for HTML5 best practices.\n\n## 1.13.x\n\n### 1.13.4\n\n- Allow dependencies to choose default bundle name by implementing getDefaultBundleName(pageBundleName, lassoContext)\n\n### 1.13.3\n\n- Added test for https://github.com/lasso-js/lasso-require/issues/21\n\n### 1.13.2\n\n- Fixed #95 - Further sanitize relative bundle paths that are used to determine output file\n\n### 1.13.1\n\n- Improved name generation for unbundled dependencies\n- Better OS file separator handling\n\n### 1.13.0\n\n- Adds support for `noConflict` lasso configuration option\n\n## 1.12.x\n\n### 1.12.0\n\n- Fixes https://github.com/lasso-js/lasso-minify-js/issues/1 - Upgrade to the latest version of UglifyJS\n\n### 1.11.12\n\n- Fixes [#82](https://github.com/lasso-js/lasso/issues/82) - Make lasso a true singleton\n\n### 1.11.11\n\n- Minor correction in calculateConfigFingerprint code\n\n### 1.11.10\n\n- Added mask-define option for resource dependencies\n\n### 1.11.9\n\n- Changes to keep Lasso taglib compatible with older versions of `marko`\n\n### 1.11.8\n\n- Upgraded the marko dev dependency\n\n### 1.11.7\n\n- Documentation: Improved docs\n\n### 1.11.6\n\n- Documentation: Improved docs\n\n### 1.11.5\n\n- Fixesd [#77](https://github.com/lasso-js/lasso/issues/77) - <lasso-img> now works on the server and in the browser\n- Builtin es6 support for `.es6` files\n- Documentation: Added docs for #77\n\n### 1.11.4\n\n- Only enable the browser-refresh special reloads once\n\n### 1.11.3\n\n- Add web fonts to browser-refresh\n\n### 1.11.2\n\n- Fixed circular require issues for browser-refresh\n\n### 1.11.1\n\n- browser-refresh is now auto enabled.\n- Code and docs cleanup\n\n### 1.10.4\n\n- Fixed #76 Auto switch to development mode when browser-refresh is enabled\n\n### 1.10.3\n\n- Fixed #75 - Generate config cache key in a stable way\n- Documentation: new plugin: [lasso-autoprefixer](https://github.com/lasso-js/lasso-autoprefixer): Autoprefix CSS with vendor prefixes using [autoprefixer-core](https://github.com/postcss/autoprefixer-core)\n- Documentation: Fixed #61 - Improve documentation for external resource dependencies\n\n### 1.10.2\n\n- Documentation: new third party plugin: [lasso-clean-css](https://github.com/yomed/lasso-clean-css)\n\n### 1.10.1\n\n- Fixed [#62](https://github.com/lasso-js/lasso/issues/62) - Invalidate the default lasso instance on configure\n\n### 1.10.0\n\n- Fixed [#57](https://github.com/lasso-js/lasso/issues/57) - Allow non-JavaScript modules to be required:\n\n```javascript\nrequire('lasso/node-require-no-op').enable('.less', '.css');\n\n// ...\n\nrequire('./style.less');\n```\n\n### 1.9.0\n\n## 1.9.x\n\n### 1.9.1\n\n- Internal: Switched from \"raptor-async/DataHolder\" (deprecated) to \"raptor-async/AsyncValue\"\n\n### 1.9.0\n\n- [Issue #48](https://github.com/lasso-js/lasso/issues/48): Do not mangle bundle names\n- [Issue #49](https://github.com/lasso-js/lasso/issues/49): Enhance LassoPageResult to fetch info by bundle name\n\n## 1.8.x\n\n### 1.8.6\n\n- Renamed Optimizer to Lasso\n"
  },
  {
    "path": "README.md",
    "content": "Lasso.js\n==================\n\n[![Build Status](https://travis-ci.org/lasso-js/lasso.svg?branch=master)](https://travis-ci.org/lasso-js/lasso)\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/lasso-js/lasso)\n\nLasso.js is an eBay open source Node.js-style JavaScript module bundler that also provides first-level support for optimally delivering JavaScript, CSS, images and other assets to the browser.\n\nThis tool offers many different optimizations such as a bundling, code splitting, lazy loading, conditional dependencies, compression and fingerprinted resource URLs. Plugins are provided to support pre-processors and compilers such as Less, Stylus and [Marko](https://github.com/raptorjs/marko). This developer-friendly tool does not require that you change the way that you already code and can easily be adopted by existing applications.\n\n# Example\n\nInstall the command line interface for Lasso.js:\n\n```text\nnpm install lasso-cli --global\n```\n\nInstall a helper module from npm:\n\n```text\nnpm install change-case\n```\n\nCreate the main Node.js JavaScript module file:\n\n__main.js:__\n\n```javascript\nvar changeCase = require('change-case');\nconsole.log(changeCase.titleCase('hello world')); // Output: 'Hello World'\n```\n\nCreate a StyleSheet for the page:\n\n__style.css__\n\n```css\nbody {\n    background-color: #5B83AD;\n}\n```\n\nCreate an HTML page to host the application:\n\n__my-page.html:__\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Lasso.js Demo</title>\n</head>\n<body>\n    <h1>Lasso.js Demo</h1>\n</body>\n</html>\n```\n\nRun the following command:\n\n```bash\nlasso style.css \\\n    --main main.js \\\n    --inject-into my-page.html\n```\n\nOutput:\n\n```text\nOutput for page \"my-page\":\n  Resource bundle files:\n    static/my-page-9ac9985e.js\n    static/my-page-1ae3e9bf.css\n  HTML slots file:\n    build/my-page.html.json\n  Updated HTML file:\n    my-page.html\n```\n\nOpen up `my-page.html` in your web browser and in the JavaScript console you will see the output of our program running in the browser, as well as a page styled by `style.css`.\n\nAs you can see, with Lasso.js you no longer have to struggle with managing complex build scripts. Simply let Lasso.js worry about generating all of the required resource bundles and injecting them into your page so that you can just focus on writing clean and modular code.\n\nThere's also a JavaScript API, taglib and a collection of plugins to make your job as a front-end web developer easier. Please read on to learn how you can easily utilize Lasso.js in your application.\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n# Table of Contents\n\n- [Design Philosophy](#design-philosophy)\n- [Features](#features)\n- [Another Client-side Bundler?](#another-client-side-bundler)\n- [Installation](#installation)\n- [Usage](#usage)\n\t- [Command Line Interface](#command-line-interface)\n\t- [JSON Configuration File](#json-configuration-file)\n\t- [Dependencies](#dependencies)\n\t\t- [External Dependencies](#external-dependencies)\n\t\t- [Dependency Attributes](#dependency-attributes)\n\t\t- [Conditional Dependencies](#conditional-dependencies)\n\t\t- [Enabling Flags](#enabling-flags)\n\t- [Asynchronous/Lazy Loading](#asynchronouslazy-loading)\n\t- [Using the JavaScript API](#using-the-javascript-api)\n\t\t- [Configuring the Default Lasso](#configuring-the-default-lasso)\n\t\t- [Optimizing a Page](#optimizing-a-page)\n\t\t- [Creating a New Lasso](#creating-a-new-lasso)\n\t- [Lasso.js Taglib](#lassojs-taglib)\n\t\t- [Using Lasso.js Taglib with Marko](#using-lassojs-taglib-with-marko)\n\t\t- [`<lasso-img>`](#<lasso-img>)\n\t- [Client/Server Template Rendering](#clientserver-template-rendering)\n\t- [Runtime Optimization with Express](#runtime-optimization-with-express)\n\t- [Bundling](#bundling)\n\t- [Code Splitting](#code-splitting)\n- [Configuration](#configuration)\n\t- [Default Configuration](#default-configuration)\n\t- [Complete Configuration](#complete-configuration)\n- [Node.js-style Module Support](#nodejs-style-module-support)\n- [Babel Support](#babel-support)\n- [No Conflict Builds](#no-conflict-builds)\n- [Custom attributes for Script & Style tags](#custom-attributes-for-script--style-tags)\n    - [Use of defer/async with script tags](#use-of-deferasync-with-script-tags)\n- [Content Security Policy Support](#content-security-policy-support)\n- [Available Plugins](#available-plugins)\n- [Extending Lasso.js](#extending-lassojs)\n\t- [Custom Plugins](#custom-plugins)\n\t- [Custom Dependency Types](#custom-dependency-types)\n\t\t- [Custom JavaScript Dependency Type](#custom-javascript-dependency-type)\n\t\t- [Custom CSS Dependency Type](#custom-css-dependency-type)\n\t\t- [Custom Package Type](#custom-package-type)\n\t- [Custom Output Transforms](#custom-output-transforms)\n- [JavaScript API](#javascript-api)\n- [AMD Compatibility](#amd-compatibility)\n- [Sample Projects](#sample-projects)\n- [Discuss](#discuss)\n- [Maintainers](#maintainers)\n- [Contributors](#contributors)\n- [Contribute](#contribute)\n- [License](#license)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# Design Philosophy\n\n* Dependencies should be **declarative** _or_ discovered via **static code analysis**\n* Common **module loading** patterns should be supported\n* Must be **extensible** to support all types of resources\n* **Maximize productivity** in development\n* **Maximize performance** in production\n* Must be **easy to adopt** and not change how you write your code\n* Can be used at **runtime or build time**\n* Must be **configurable**\n\n# Features\n\n* Bundle Client-side Dependencies\n    * Supports all types of front-end resources (JavaScript, CSS, images, Less, CoffeeScript, etc.)\n    * Asynchronous/lazy loading of JS/CSS\n    * Configurable resource bundling\n    * Code splitting\n    * JavaScript minification\n    * CSS minification\n    * [Fingerprinted](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching) resource URLs\n    * Prefix resources with CDN host name\n    * Optional Base64 image encoding inside CSS files\n    * Custom output transforms\n    * Declarative browser-side package dependencies using simple `browser.json` files\n\t* endencies\n\t* Image minification\n    * etc.\n* Browser-side Node.js Module Loader\n    * Full support for [Isomorphic JavaScript](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)\n    * Conflict-free CommonJS module loader for the browser\n    * Complete compatibility with Node.js\n        * Supports `module.exports`, `exports`, `require`, `require.resolve`, `__dirname`, `__filename`, `process`, etc.\n    * Supports the [package.json `browser` field](https://gist.github.com/defunctzombie/4339901)\n    * Full support for [browserify](http://browserify.org/) shims and transforms\n    * Maintains line numbers in wrapped code\n* Developer Friendly\n    * Generates the HTML markup required to include bundled resources\n    * Disable bundling and minification in development\n    * Line numbers are maintained for Node.js modules source\n    * Extremely fast _incremental builds_!\n        * Only modified bundles are written to disk\n        * Disk caches are utilized to avoid repeating the same work\n* Dependency Compilation\n    * Less\n    * [Marko](https://github.com/marko-js/marko)\n    * Dust\n    * etc.\n* Extensible\n    * Custom dependency compilers\n    * Custom code transforms\n    * Custom bundle writers\n    * Custom plugins\n* Configurable\n    * Configurable resource bundles\n    * Enable/disable transforms\n    * Development-mode versus production-mode\n    * Enable/disable fingerprints\n    * etc.\n* Flexible\n    * Integrate with build tools\n    * Use with Express or any other web development framework\n    * JavaScript API, CLI and taglib\n* Security\n    * Supports the [nonce attribute](https://www.w3.org/TR/CSP2/#script-src-the-nonce-attribute) when using Content Security Policy for extra security.\n* _Future_\n    * Automatic image sprites\n\n# Another Client-side Bundler?\n\n[Browserify](http://browserify.org/) is an excellent JavaScript module bundler. We are huge supporters of writing Node.js-style modules (i.e. CommonJS), and we also believe [npm](https://www.npmjs.org/) is an excellent package manager. If you are not using a JavaScript module bundler then you are absolutely missing out. Modularity is equally important for client-side code as it is for server-side code, and a JavaScript module bundler should be part of every front-end developer's toolbox.\n\nSo why did we create Lasso.js if Browserify is such a great tool? We created Lasso.js because we wanted a top-notch JavaScript module bundler that _also_ provides first-level support for transporting CSS, \"plain\" JavaScript, images, fonts and other front-end assets to the browser in the most optimal way. In addition, we want to enable developers to easily create web applications that follow [widely accepted rules for creating faster-loading websites](http://stevesouders.com/examples/rules.php) (such as putting StyleSheets at the top, and JavaScript at the bottom). We also want to allow for developers to easily load additional JavaScript and StyleSheets after the initial page load.\n\nWhile high performance is very important for production systems, we want to also provide a more developer-friendly experience by offering fast, incremental builds, simplifying development and by producing debuggable output code. And, of course, we do not want developers to have to learn how to code their applications in a new way so Lasso.js was built to not change how you already code. You'll even find support for Browserify shims and transforms. Therefore, if you try out Lasso.js and it is not the tool for you, then feel free to switch back to something else (it'll of course be ready if your application's requirements change in the future). eBay and other large companies rely on Lasso.js for delivering high performance websites and are committed to its success. If you try it out and find gaps, please let us know!\n\n# Installation\n\nThe following command should be used to install the `lasso` module into your project:\n\n```bash\nnpm install lasso --save\n```\n\nIf you would like to use the available command line interface, then you should install the [lasso-cli](https://github.com/lasso-js/lasso-cli) module globally using the following command:\n\n```bash\nnpm install lasso-cli --global\n```\n\n# Usage\n\n## Command Line Interface\n\n<hr>\n\n[__Sample App:__](https://github.com/lasso-js-samples/lasso-cli) To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-cli](https://github.com/lasso-js-samples/lasso-cli)\n\n<hr>\n\nInstall the command line interface for Lasso.js:\n\n```bash\nnpm install lasso-cli --global\n```\n\nIn an empty directory, initialize a new Node.js project using the following command:\n\n```bash\nmkdir my-app\ncd my-app\nnpm init\n```\n\nInstall required modules into the new project:\n\n```bash\nnpm install jquery\nnpm install lasso-less\n```\n\nCreate the following files:\n\n__add.js:__\n\n```javascript\nmodule.exports = function(a, b) {\n    return a + b;\n};\n```\n\n__main.js:__\n\n```javascript\nvar add = require('./add');\nvar jquery = require('jquery');\n\njquery(function() {\n    $(document.body).append('2+2=' + add(2, 2));\n});\n```\n\n__style.less:__\n\n```css\n@headerColor: #5B83AD;\n\nh1 {\n    color: @headerColor;\n}\n```\n\n__my-page.html:__\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Lasso.js Demo</title>\n</head>\n<body>\n    <h1>Lasso.js Demo</h1>\n</body>\n</html>\n```\n\nFinally, run the following command to generate the resource bundles for the page and to also inject the required `<script>` and `<link>` tags into the HTML page:\n\n```bash\nlasso style.less \\\n    --main main.js \\\n    --inject-into my-page.html \\\n    --plugins lasso-less \\\n    --development\n```\n\nIf everything worked correctly then you should see output similar to the following:\n\n```text\nOutput for page \"my-page\":\n  Resource bundle files:\n    static/add.js\n    static/raptor-modules-meta.js\n    static/main.js\n    static/node_modules/jquery/dist/jquery.js\n    static/raptor-modules-1.0.1/client/lib/raptor-modules-client.js\n    static/style.less.css\n  HTML slots file:\n    build/my-page.html.json\n  Updated HTML file:\n    my-page.html\n```\n\nThe updated `my-page.html` file should be similar to the following:\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Lasso.js Demo</title>\n    <!-- <lasso-head> -->\n    <link rel=\"stylesheet\" href=\"static/style.less.css\">\n    <!-- </lasso-head> -->\n</head>\n<body>\n    <h1>Lasso.js Demo</h1>\n    <!-- <lasso-body> -->\n    <script src=\"static/raptor-modules-1.0.1/client/lib/raptor-modules-client.js\"></script>\n    <script src=\"static/add.js\"></script>\n    <script src=\"static/raptor-modules-meta.js\"></script>\n    <script src=\"static/node_modules/jquery/dist/jquery.js\"></script>\n    <script src=\"static/main.js\"></script>\n    <script>$_mod.ready();</script>\n    <!-- </lasso-body> -->\n</body>\n</html>\n```\n\nIf you open up `my-page.html` in your web browser you should see a page styled with Less and the output of running `main.js`.\n\nNow try again with `production` mode:\n\n```bash\nlasso style.less \\\n    --main main.js \\\n    --inject-into my-page.html \\\n    --plugins lasso-less \\\n    --production\n```\n\n```\nOutput for page \"my-page\":\n  Resource bundle files:\n    static/my-page-2e3e9936.js\n    static/my-page-169ab5d9.css\n  HTML slots file:\n    build/my-page.html.json\n  Updated HTML file:\n    my-page.html\n```\n\nThe updated `my-page.html` file should be similar to the following:\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Lasso.js Demo</title>\n    <!-- <lasso-head> -->\n    <link rel=\"stylesheet\" href=\"static/my-page-169ab5d9.css\">\n    <!-- </lasso-head> -->\n</head>\n<body>\n    <h1>Lasso.js Demo</h1>\n    <!-- <lasso-body> -->\n    <script src=\"static/my-page-2e3e9936.js\"></script>\n    <script>$_mod.ready();</script>\n    <!-- </lasso-body> -->\n</body>\n</html>\n```\n\nWith the `--production` option enabled, all of the resources are concatenated together, minified and fingerprinted – perfect for high performance web applications running in production.\n\nFor more documentation on the Command Line Interface please see the [lasso-cli docs](https://github.com/lasso-js/lasso-cli).\n\n## JSON Configuration File\n\n<hr>\n\n[__Sample App__](https://github.com/lasso-js-samples/lasso-config) To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-config](https://github.com/lasso-js-samples/lasso-config)\n\n<hr>\n\nThe number of command line arguments can get unwieldy so it is better to split out configuration into a separate JSON file. Let's now create a configuration file and configure a few bundles to make things more interesting:\n\n__lasso-config.json:__\n\n```json\n{\n\n    \"plugins\": [\n        \"lasso-less\"\n    ],\n    \"outputDir\": \"static\",\n\t\"fingerprintsEnabled\": true,\n    \"minify\": true,\n    \"resolveCssUrls\": true,\n    \"bundlingEnabled\": true,\n    \"bundles\": [\n        {\n            \"name\": \"jquery\",\n            \"dependencies\": [\n                \"require: jquery\"\n            ]\n        },\n        {\n            \"name\": \"math\",\n            \"dependencies\": [\n                \"require: ./add\"\n            ]\n        }\n    ]\n}\n```\n\nIn addition, let's put our page dependencies in their own JSON file:\n\n__my-page.browser.json:__\n\n```json\n{\n    \"dependencies\": [\n        \"./style.less\",\n        \"require-run: ./main\"\n    ]\n}\n```\n\nNow run the page lasso using the newly created JSON config file and JSON dependencies file:\n\n```bash\nlasso ./my-page.browser.json \\\n    --inject-into my-page.html \\\n    --config lasso-config.json\n```\n\nBecause of the newly configured bundles, we'll see additional JavaScript bundles written to disk as shown below:\n\n```\nOutput for page \"my-page\":\n  Resource bundle files:\n    static/math-169c956d.js\n    static/jquery-24db89d9.js\n    static/my-page-beed0921.js\n    static/my-page-169ab5d9.css\n  HTML slots file:\n    build/my-page.html.json\n  Updated HTML file:\n    my-page.html\n```\n\n## Dependencies\n\nLasso.js walks a dependency graph to find all of the resources that need to be bundled. A dependency can either be a JavaScript or CSS resource (or a file that compiles to either JavaScript or CSS) or a dependency can be a reference to a set of transitive dependencies. Some dependencies are inferred from scanning source code and other dependencies can be made explicit by listing them out in the code of JavaScript modules or in separate `browser.json` files.\n\nIt's also possible to register your own [custom dependency types](#custom-dependency-types). With custom dependency types, you can control how resources are compiled or a custom dependency type can be used to resolve additional dependencies during optimization.\n\nBrowser dependencies can be described as shown in the following sample `browser.json` file:\n\n```json\n{\n    \"dependencies\": [\n        \"./style.less\",\n        \"../third-party/jquery.js\",\n        \"**/*.css\",\n        {\n            \"type\": \"js\",\n            \"url\": \"https://code.jquery.com/jquery-2.1.4.min.js\"\n        },\n        {\n            \"type\": \"css\",\n            \"url\": \"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css\"\n        }\n    ]\n}\n```\n\nAlternatively, dependencies can be \"required\" inside a JavaScript module as shown in the following sample JavaScript code:\n\n```javascript\nrequire('./style.less');\n\n// ...\n```\n\nThe only caveat to using a `require()` call to add a non-JavaScript module dependency is that by default Node.js will try to load the required file as a JavaScript module if the code runs on the server. To prevent Node.js from trying to load a Less file or other non-JavaScript files as JavaScript modules you can add the following code to your main script:\n\n```javascript\nrequire('lasso/node-require-no-op').enable('.less', '.css');\n```\n\n\nFor simple paths, the dependency type is inferred from the filename extension. Alternatively, the dependency type can be made explicit using either one of the following formats:\n\n```json\n[\n    \"./style.less\",\n    \"less: ./style.less\",\n    { \"type\": \"less\", \"path\": \"./style.less\" }\n]\n```\n\n_NOTE: all of the above are equivalent_\n\nYou can also create a dependency that references dependencies in a separate `browser.json` file. Dependencies that have the `browser.json` extension are automatically resolved using the require resolver if they are not relative paths. For example:\n```js\n[\n    // Relative path:\n    \"./some-module/browser.json\",\n\n    // Look for \"my-module/browser.json\" in \"node_modules\":\n    \"my-module/browser.json\"\n]\n```\n\nIf the path does not have a file extension then it is assumed to be a path to an `browser.json` file so the following short-hand works as well:\n```js\n[\n    \"./some-module\"\n    \"my-module\"\n]\n```\nIf you use the short-hand notation for `browser.json` dependencies, the paths will still be resolved using the require resolver as long as they are not relative paths.\n\n### External Dependencies\n\nLasso.js does allow referencing external JS/CSS files in your `browser.json` files as shown below:\n\n```json\n{\n    \"dependencies\": [\n        {\n            \"type\": \"js\",\n            \"url\": \"https://code.jquery.com/jquery-2.1.4.min.js\"\n        },\n        {\n            \"type\": \"css\",\n            \"url\": \"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css\"\n        }\n    ]\n}\n```\n\nBy default, Lasso.js will not bundle external resources with your application's JavaScript and CSS bundles. If you would prefer for an external resource to be downloaded from the remote server and bundled with your other application code during the lassoing then you can set the `external` property to `false` as shown below (`external` defaults to `true`):\n\n```json\n{\n    \"dependencies\": [\n        {\n            \"type\": \"js\",\n            \"url\": \"https://code.jquery.com/jquery-2.1.4.min.js\",\n            \"external\": false\n        }\n    ]\n}\n```\n\nSetting `external` to `false` in the above example will result in jQuery being downloaded from the CDN and bundled with all of the other JS code for the app. That is, the code for jQuery will not be served up by the jQuery CDN.\n\n### Dependency Attributes\n\nAdding an `attributes` object to a dependency definition will result in those attributes being defined on the html tag for that dependency.  For bundled dependencies, these attributes will be merged with latter dependencies taking priority.\n\nThe following is an example using the `integrity` and `crossorigin` attributes for [Subresource Integrity (SRI) checking](https://www.w3.org/TR/SRI/). This allows browsers to ensure that resources hosted on third-party servers have not been tampered with. Use of SRI is recommended as a best-practice, whenever libraries are loaded from a third-party source.\n\n```json\n{\n    \"dependencies\": [{\n        \"type\": \"js\",\n        \"url\": \"https://code.jquery.com/jquery-3.1.1.min.js\",\n        \"attributes\":{\n            \"integrity\":\"sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=\",\n            \"crossorigin\":\"anonymous\"\n        }\n    }]\n}\n```\n\n**Generated Output:**\n```html\n<script\n  src=\"https://code.jquery.com/jquery-3.1.1.min.js\"\n  integrity=\"sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=\"\n  crossorigin=\"anonymous\"></script>\n```\n\n### Conditional Dependencies\n\nLasso.js supports conditional dependencies. Conditional dependencies is a powerful feature that allows for a page to be built differently based on certain flags (e.g. \"mobile device\" versus \"desktop\"). For caching reasons, the flags for conditional dependencies should be based on a set of enabled flag. A flag is just an arbitrary name that can be enabled/disabled before optimizing a page. For example, to make a dependency conditional such that is only included for mobile devices you can do the following:\n\n```json\n{\n    \"dependencies\": [\n        { \"path\": \"./hello-mobile.js\", \"if-flag\": \"mobile\" }\n    ]\n}\n```\n\nAlternatively, you can also include the desktop version of a file if the \"mobile\" extension is not enabled using `if-not-flag`.\n```json\n{\n    \"dependencies\": [\n        { \"path\": \"./hello-desktop.js\", \"if-not-flag\": \"mobile\" }\n    ]\n}\n```\n\nIf needed, a JavaScript expression can be used to describe a more complex condition as shown in the following sample code:\n\n```json\n{\n    \"dependencies\": [\n        {\n            \"path\": \"./hello-mobile.js\",\n            \"if\": \"flags.contains('phone') || flags.contains('tablet')\"\n        }\n    ]\n}\n```\n\nFinally, if you prefer, you can group your conditional dependencies if needed:\n\n```json\n{\n    \"dependencies\": [\n        {\n            \"if-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./style-mobile.css\",\n                \"./client-mobile.js\"\n            ]\n        }\n    ]\n}\n```\n\n### Enabling Flags\n\nThe code below shows how to enable flags when optimizing a page:\n\n__Using the JavaScript API:__\n\n```javascript\nmyLasso.lassoPage({\n    dependencies: [\n        { path: './hello-mobile.js', 'if-flag': 'mobile' }\n    ],\n    flags: ['mobile', 'foo', 'bar']\n})\n```\n\n__Using the Marko taglib:__\n\n```marko\n<lasso-page ... flags=['mobile', 'foo', 'bar']>\n    ...\n</lasso-page>\n```\n\n## Asynchronous/Lazy Loading\n\n<hr>\n\n[__Sample App__](https://github.com/lasso-js-samples/lasso-async)To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-async](https://github.com/lasso-js-samples/lasso-async)\n\n<hr>\n\n\nLasso.js supports asynchronously loading dependencies using the lightweight [lasso-loader](https://github.com/lasso-js/lasso-loader) module as shown in the following sample code:\n\n```javascript\nvar lassoLoader = require('lasso-loader');\n\nlassoLoader.async(function(err) {\n    // Any modules that are required within the scope\n    // of this function will be loaded asynchronously*.\n    // Lasso.js ensures that modules are only\n    // loaded once from the server.\n    //\n    // *Modules that were included as part of the initial\n    // page load will automatically be de-duped.\n\n    if (err) {\n        // Handle the case where one or more of the\n        // dependencies failed to load.\n    }\n\n    var add = require('./add');\n    var jquery = require('jquery');\n\n    jquery(function() {\n        $(document.body).append('2+2=' + add(2, 2));\n    });\n});\n```\n\nDuring optimization, Lasso.js detects the call to `require('lasso-loader').async(...)` and transforms the code such that the function is not invoked until all of the required modules referenced in the body of callback function are completely loaded.\n\nYou can also specify additional explicit dependencies if necessary:\n\n```javascript\nrequire('lasso-loader').async(\n    [\n        './style.less',\n        'some/other/browser.json'\n    ],\n    function() {\n        // All of the requires nested in this function block will be lazily loaded.\n        // When all of the required resources are loaded then the function will be invoked.\n        var foo = require('foo');\n        var bar = require('bar');\n    });\n```\n\nYou can also choose to declare async dependencies in an `browser.json` file:\n\n```json\n{\n    \"dependencies\": [\n        ...\n    ],\n    \"async\": {\n        \"my-module/lazy\": [\n            \"require: foo\",\n            \"require: bar\",\n            \"./style.less\",\n            \"some/other/browser.json\"\n        ]\n    }\n}\n```\n\nThe async dependencies can then be referenced in code:\n```javascript\nrequire('lasso-loader').async(\n    'my-module/lazy',\n    function() {\n        var foo = require('foo');\n        var bar = require('bar');\n    });\n```\n\n## Using the JavaScript API\n\n<hr>\n\n[__Sample App__](https://github.com/lasso-js-samples/lasso-js-api) To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-js-api](https://github.com/lasso-js-samples/lasso-js-api)\n\n<hr>\n\nFor added flexibility there is a JavaScript API that can be used to lasso pages as shown in the following sample code:\n\n```javascript\nvar lasso = require('lasso');\nlasso.configure('lasso-config.json');\nlasso.lassoPage({\n        name: 'my-page',\n        dependencies: [\n            \"./style.less\",\n            \"require-run: ./main\"\n        ]\n    },\n    function(err, lassoPageResult) {\n        if (err) {\n            // Handle the error\n        }\n\n        var headHtml = lassoPageResult.getHeadHtml();\n        // headHtml will contain something similar to the following:\n        // <link rel=\"stylesheet\" href=\"static/my-page-169ab5d9.css\">\n\n        var bodyHtml = lassoPageResult.getBodyHtml();\n        // bodyHtml will contain something similar to the following:\n        //  <script src=\"static/my-page-2e3e9936.js\"></script>\n    });\n```\n\nThe `lassoPage(options)` method supports the following options:\n\n- `data` (`Object`) - Arbitrary data that can be made available to plugins via `lassoContext.data`.\n- `cacheKey` (`String`) - A unique String to use for cache reads and writes. Defaults to `name`.\n- `dependencies` (`Array`) - An array of top-level page dependencies (e.g. `['foo.js', 'foo.css', 'require: jquery']`).\n- `flags` (`Array`) - The set of enabled flags (e.g. `['mobile', 'touch']`).\n- `from` (`String`) - The base path for resolving relative paths for top-level dependencies.\n- `name` (`String`) - The page name. Used for determining the names of the output JS/CSS bundles.\n- `packagePath` (`String`) - The path to an `browser.json` file that describes the top-level dependencies.\n\n### Configuring the Default Lasso\n```javascript\nvar lasso = require('lasso');\nlasso.configure(config);\n```\n\nIf the value of the `config` argument is a `String` then it is treated as a path to a JSON configuration file.\n\n\n### Optimizing a Page\n\nThe following code illustrates how to lasso a simple set of JavaScript and CSS dependencies using the default configured lasso:\n\n```javascript\nvar lasso = require('lasso');\nlasso.lassoPage({\n        name: 'my-page',\n        dependencies: [\n            './foo.js',\n            './bar.js',\n            './baz.js',\n            './qux.css'\n        ]\n    },\n    function(err, lassoPageResult) {\n        if (err) {\n            console.log('Failed to lasso page: ', err);\n            return;\n        }\n\n        var headHtml = lassoPageResult.getHeadHtml();\n        /*\n        String with a value similar to the following:\n        <link rel=\"stylesheet\" href=\"/static/my-page-85e3288e.css\">\n        */\n\n        var bodyHtml = lassoPageResult.getBodyHtml();\n        /*\n        String with a value similar to the following:\n        <script src=\"/static/bundle1-6df28666.js\"></script>\n        <script src=\"/static/bundle2-132d1091.js\"></script>\n        <script src=\"/static/my-page-1de22b65.js\"></script>\n        */\n\n        // Inject the generated HTML into the <head> and <body> sections of a page...\n    });\n```\n\n### Creating a New Lasso\n\n```javascript\nvar myLasso = lasso.create(config);\nmyLasso.lassoPage(...);\n```\n\n\n## Lasso.js Taglib\n\n<hr>\n\n[__Sample App__](https://github.com/lasso-js-samples/lasso-taglib) To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-taglib](https://github.com/lasso-js-samples/lasso-taglib)\n\n<hr>\n\nFor the ultimate in usability, a taglib is provided for Marko (and Dust) to automatically lasso a page _and_ inject the required HTML markup to include the JavaScript and CSS bundles.\n\nIf you are using [Marko](https://github.com/marko-js/marko) you can utilize the available taglib for Lasso.js to easily lasso page dependencies and embed them into your page.\n\n### Using Lasso.js Taglib with Marko\n\n1. `npm install lasso --save`\n2. `npm install marko --save`\n\nYou can now add the lasso tags to your page templates. For example:\n\n```marko\n<lasso-page package-path=\"./browser.json\"/>\n\n<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Test Page</title>\n    <lasso-head/>\n</head>\n<body>\n    <h1>Test Page</h1>\n    <lasso-body/>\n</body>\n</html>\n```\n\nYou will then need to create an `browser.json` in the same directory as your page template. For example:\n\n_browser.json_:\n```json\n{\n    \"dependencies\": [\n        \"./jquery.js\",\n        \"./foo.js\",\n        \"./bar.js\",\n        \"./style.less\"\n    ]\n}\n```\n\nUsing Marko and Lasso.js taglib, you can simply render the page using code similar to the following:\n\n```javascript\nvar template = require('marko').load('my-page.marko');\ntemplate.render({}, function(err, html) {\n    // html will include all of the required <link> and <script> tags\n});\n```\n\nThe output of the page rendering will be similar to the following:\n\n```html\n<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>Test Page</title>\n    <link rel=\"stylesheet\" href=\"/static/my-page-85e3288e.css\">\n</head>\n<body>\n    <h1>Test Page</h1>\n    <script src=\"/static/bundle1-6df28666.js\"></script>\n    <script src=\"/static/bundle2-132d1091.js\"></script>\n    <script src=\"/static/my-page-1de22b65.js\"></script>\n</body>\n</html>\n```\n\nThe lasso result is cached so you can skip the build step!\n\nYou can also configure the default page lasso used by the lasso tags:\n\n```javascript\nrequire('lasso').configure({...});\n```\n\nFor more details, please see following documentation: [Lasso.js Taglib for Marko](taglib-marko.md)\n\n<a name=\"<lasso-img\"></a>\n\n### `<lasso-img>`\n\nThe `<lasso-img>` tag can be used to render `<img>` tags while also having the image referenced by the `src` attribute automatically go through the Lasso.js asset pipeline. In addition, if the `width` and `height` attributes are not specified then those attributes will automatically be added. This tag can be rendered on both the server and in the browser.\n\nExample:\n\n```marko\n<lasso-img src=\"./foo.jpg\"/>\n```\n\nThis might produce the following HTML output depending on how Lasso.js is configured:\n\n```html\n<img src=\"/static/foo-25b047cc.jpg\" width=\"100\" height=\"100\">\n```\n\n## Client/Server Template Rendering\n\n<hr>\n\n[__Sample App__](https://github.com/lasso-js-samples/lasso-templates) To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-templates](https://github.com/lasso-js-samples/lasso-templates)\n\n<hr>\n\nTo demonstrate rendering of the same template on the server and the client we will start with the following Marko template:\n\n__template.marko__\n\n```marko\n-- Hello ${data.name}!\n```\n\n_NOTE: The sample app includes sample code that illustrates how to also render both a Dust template and a Handlebars template on both the client and server._\n\nWe will then create a `main.js` file to render the template to the console:\n\n__main.js:__\n\n```javascript\nvar template = require('marko')\n    .load(require.resolve('./template.marko'));\n\ntemplate.render(\n    {\n        name: 'Frank'\n    },\n    function(err, html) {\n        console.log('Template output: ' + html);\n    });\n```\n\n_NOTE: The reason we use `require.resolve('./template.marko')` instead of `require('template.marko')` is that Node.js does not understand how to load `.marko` modules and the use of the `require.extensions` has been [deprecated](http://nodejs.org/api/globals.html#globals_require_extensions). `require.resolve()` is used to get the resolved path for the template and the [marko](https://github.com/marko-js/marko) module uses that path to load template into memory._\n\nRunning `node main.js` on the server will produce the following output in the console:\n\n```html\nTemplate output: Hello Frank!\n```\n\nIn order to automatically detect and compile required `*.marko` templates we\nwill need to install the [lasso-marko](https://github.com/lasso-js/lasso-marko)\nplugin and [@lasso/marko-taglib](https://github.com/lasso-js/lasso-marko-taglib)\ntaglib using the following commands:\n\n```bash\nnpm install lasso-marko\nnpm install @lasso/marko-taglib\n```\n\nWe can then lasso the page using the following command:\n\n```bash\nlasso style.less \\\n    --main main.js \\\n    --inject-into my-page.html \\\n    --plugins lasso-marko\n```\n\nAfter opening `my-page.html` in your web browser you should then see the same output written to the browser's JavaScript console.\n\n## Middleware for Express and Koa\n\nLasso includes optional middleware for both Express and Koa that can be used to serve up the static files that it generates.\n\n### `serveStatic(options)`\n\nThe `serveStatic` middleware provided by Lasso is a small wrapper around the [send](https://github.com/pillarjs/send) package.\n\nSupported options:\n\n- __lasso__ - The configured lasso instance (defaults to `require('lasso').getDefaultLasso()`)\n- __sendOptions__ - Pass through options for the `send` module. See [send » options](https://github.com/pillarjs/send#optionsd)\n\n### Using `serveStatic` with Express\n\n```javascript\napp.use(require('lasso/middleware').serveStatic(options));\n```\n\n### Using `serveStatic` with Koa\n\n```javascript\napp.use(require('lasso/middleware/koa').serveStatic(options));\n```\n\n## Runtime Optimization with Express and Koa\n\n<hr>\n\n[__Sample App__](https://github.com/lasso-js-samples/lasso-express) To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-express](https://github.com/lasso-js-samples/lasso-express)\n\n<hr>\n\nLasso.js has a smart caching layer and is fast enough so that it can be used at runtime as part of your server application. The easiest way to use Lasso.js at runtime is to use the Marko taglib and simply render the page template to the response output stream.\n\nThe first time the page renders, the page will be lassoed and cached and the output of the lasso will be used to produce the final page HTML. After the first page rendering, the only work that will be done by Lasso.js is a simple cache lookup.\n\nBy default, Lasso.js writes all resource bundles into the `static/` directory at the root of your application. In addition, by default, all resource URLs will be prefixed with `/static`. If resources are to be served up by the local Express server we will need to register the appropriate middleware as shown in the following sample code:\n\n__server.js__\n\n```javascript\nrequire('marko/node-require');\nrequire('marko/express');\n\nvar express = require('express');\nvar compression = require('compression');\nvar serveStatic = require('serve-static');\n\n// Load the page template:\nvar template = require('./template.marko');\n\n// Configure the default lasso\nrequire('lasso').configure({\n\n});\n\nvar app = express();\n\n// Enable gzip compression for all HTTP responses:\napp.use(compression());\n\n// Any URL that begins with \"/static\" will be served up\n// out of the \"static/\" directory:\napp.use(require('lasso/middleware').serveStatic());\n\napp.get('/', function(req, res) {\n    // Render the page template as normal:\n    res.marko(template, {\n            name: 'Frank'\n        });\n});\n...\n\napp.listen(8080);\n```\n\n## Bundling\n\nBy default, all dependencies required for a page will be bundled into a single JavaScript bundle and a single CSS bundle. However, Lasso.js allows application-level bundles to be configured to allow for consistent bundles across pages and for multiple bundles to be included on a single page. Because Lasso.js also generates the HTML markup to include page bundles, the page itself does not need to be changed if the bundle configuration is changed.\n\nIf a page has a dependency that is part of an application-level bundle then the dependency will be included as part of the application-level bundle instead of being aggregated with the page-level bundle.\n\nBundles can be configured using the `\"bundles\"` configuration property that accepts an array of bundle configurations. Each bundle should consist of a name and a set of dependencies to assign to that bundle.\n\n__Bundling Example:__\n\nGiven the following configured bundles:\n\n```json\n{\n    ...\n    \"bundles\": [\n        {\n            \"name\": \"bundle1\",\n            \"dependencies\": [\n                \"./foo.js\",\n                \"./baz.js\"\n            ]\n        },\n        {\n            \"name\": \"bundle2\",\n            \"dependencies\": [\n                \"./bar.js\"\n            ]\n        }\n    ]\n}\n```\n\n\nOptimizing a page that does not include any dependencies in application-level bundles:\n\n```bash\nlasso app.js style.css --name my-page -c lasso-config.json\n```\n\nOutput:\n\n```\nOutput for page \"my-page\":\n  Resource bundle files:\n    static/my-page.js\n    static/my-page.css\n  HTML slots file:\n    build/my-page.html.json\n```\n\n\nOptimizing a page that includes \"foo.js\" that is part of \"bundle1\":\n```bash\nlasso app.js foo.js style.css --name my-page -c lasso-config.json\n```\n\nOutput:\n\n```\nOutput for page \"my-page\":\n  Resource bundle files:\n    static/my-page.js\n    static/bundle1.js\n    static/my-page.css\n  HTML slots file:\n    build/my-page.html.json\n```\n\nFor more information on working with bundles. Please see the [bundling docs](docs/bundling.md).\n\n## Code Splitting\n\n<hr>\n\n[__Sample App__](https://github.com/lasso-js-samples/lasso-code-splitting) To try out and experiment with the code, please see the following project:<br>[lasso-js-samples/lasso-code-splitting](https://github.com/lasso-js-samples/lasso-code-splitting)\n\n<hr>\n\nLasso.js supports splitting out code that multiple pages/entry points have in common into separate bundles. This is accomplished by assigning an `intersection` dependency to a bundle. The `intersection` dependency is a package dependency that produces a set of dependencies that is the intersection of one or more packages. Code splitting ensures that the same code is not downloaded twice by the user when navigating a web application.\n\nThe following bundle configuration illustrates how to split out common code into a separate bundle:\n\n```json\n{\n    \"bundles\": [\n        {\n            \"name\": \"common\",\n            \"dependencies\": [\n                {\n                    \"intersection\": [\n                        \"./src/pages/home/browser.json\",\n                        \"./src/pages/profile/browser.json\"\n                    ]\n                }\n            ]\n        }\n    ]\n}\n```\nA less strict intersection condition is also supported via a `threshold` property.\n\nFor example, to find those dependencies that are among *at least two* of the widgets:\n```json\n{\n    \"bundles\": [\n        {\n            \"name\": \"common\",\n            \"dependencies\": [\n                {\n                    \"threshold\": 2,\n                    \"intersection\": [\n                        \"require: ./a/widget\",\n                        \"require: ./b/widget\",\n                        \"require: ./c/widget\"\n                    ]\n                }\n            ]\n        }\n    ]\n}\n```\n\nThis could also be expressed as a percentage:\n```json\n{\n    \"bundles\": [\n        {\n            \"name\": \"common\",\n            \"dependencies\": [\n                {\n                    \"threshold\": \"66%\",\n                    \"intersection\": [\n                        \"require: ./a/widget\",\n                        \"require: ./b/widget\",\n                        \"require: ./c/widget\"\n                    ]\n                }\n            ]\n        }\n    ]\n}\n```\n\n# Configuration\n\n## Default Configuration\n```javascript\n{\n    // Write all bundles into the \"static\" directory\n    \"outputDir\": \"static\",\n\n    // URL prefix for all bundles\n    \"urlPrefix\": \"/static\",\n\n    // Include fingerprint in output files\n    \"fingerprintsEnabled\": true\n}\n```\n\n## Complete Configuration\n\n```javascript\n{\n    // Configure Lasso.js plugins\n    \"plugins\": [\n        // Plugin with a default config:\n        \"lasso-less\",\n        // Plugin with custom configuration:\n        {\n            \"plugin\": \"lasso-my-plugin\",\n            \"config\": { ... }\n        },\n        ...\n    ],\n    // The base output directory for generated bundles\n\t\"outputDir\": \"static\",\n\n\t// Optional URL prefix to prepend to relative bundle paths\n\t\"urlPrefix\": \"http://mycdn/static\",\n\n\t// If fingerprints are enabled then a shasum will be included in the URL.\n\t// This feature is used for cache busting.\n\t\"fingerprintsEnabled\": true,\n\n\t// If fingerprints are not enabled then the same output file would be\n\t// used for bundles that go into the head and bundles that go in the\n\t// body. Enabling this option will ensure that bundles have unique names\n\t// even if fingerprints are disabled.\n\t\"includeSlotNames\": false\n\n    // If \"minify\" is set to true then output CSS and JavaScript will run\n    // through a minification transform. (defaults to false)\n    \"minify\": false,\n\n    \"minifyJS\": false, // Minify JavaScript\n\n    \"minifyCSS\": false, // Minify CSS\n\n    \"minifyInlineOnly\": false, // Only minify inline resources\n\n    \"minifyInlineJSOnly\": false, // Only minify inline JavaScript resources\n\n    \"minifyInlineCSSOnly\": false, // Only minify inline CSS resources\n\n    // If \"resolveCssUrls\" is set to true then URLs found in CSS files will be\n    // resolved and the original URLs will be replaced with the resolved URLs.\n    // (defaults to true)\n    \"resolveCssUrls\": true,\n\n    // If \"relativeUrlsEnabled\" is set to false then URLs found in CSS files will\n    // be absolute based on the urlPrefix. This default is false, which creates\n    // relative URLs in CSS files.\n    \"relativeUrlsEnabled\": true,\n\n    // If \"bundlingEnabled\" is set to true then dependencies will be concatenated\n    // together into one or more bundles. If set to false then each dependency\n    // will be written to a separate file. (defaults to true)\n    \"bundlingEnabled\": true,\n\n    // If you want consistent bundles across pages then those shared bundles\n    // can be specified below. If a page dependency is part of a shared\n    // bundle then the shared bundle will be added to the page (instead of\n    // adding the dependency to the page bundle).\n    \"bundles\": [\n        {\n            // Name of the bundle (used for determining the output filename)\n            \"name\": \"bundle1\",\n\n            // Set of dependencies to add to the bundle\n            \"dependencies\": [\n                \"./foo.js\",\n                \"./baz.js\"\n            ]\n        },\n        {\n            \"name\": \"bundle2\",\n            \"dependencies\": [\n                \"./style/*.css\",\n                \"require: **/*.js\"\n            ]\n        }\n    ],\n\n    // The default name of the modules runtime variable is\n    // \"\"$_mod\" but you can change that with the noConflict option.\n    // This is necessary if you have a webpage that loads\n    // multiple JavaScript bundles that were\n    // built at different times with Lasso.\n    // The string you provide will be used to create\n    // a unique name for the modules runtime variable name by\n    // removing or replacing illegal characters.\n    \"noConflict\": \"myapp\"\n}\n```\n\n# Node.js-style Module Support\n\nLasso.js provides full support for transporting Node.js modules to the browser. If you write your modules in the standard Node.js way (i.e. using `require`, `module.exports` and `exports`) then the module will be able to be loaded on both the server and in the browser.\n\nThis functionality is offered by the core [lasso-require](https://github.com/lasso-js/lasso-require) plugin which introduces a new `require` dependency type. For example:\n\n```json\n[\n    \"require: ./path-to-some-module\"\n]\n```\n\nIf you want to include a module and have it run when loaded (i.e. self-executing) then you should use the `require-run` dependency type:\n\n```json\n[\n    \"require-run: ./main\"\n]\n```\n\nExamples of conditional requires:\n\n```json\n[\n    {\n        \"require-run\": \"./foo\",\n        \"if-flag\": \"bar\"\n    },\n    {\n        \"require\": \"./foo\",\n        \"if-flag\": \"bar\"\n    }\n]\n```\n\nIt's also possible to remap a require based on a flag:\n\n```json\n{\n    \"dependencies\": [\n        ...\n    ],\n    \"requireRemap\": [\n        {\n            \"from\": \"./foo.js\",\n            \"to\": \"./foo-mobile.js\",\n            \"if-flag\": \"mobile\"\n        }\n    ]\n}\n```\n\nThe [lasso-require](https://github.com/lasso-js/lasso-require) plugin will automatically scan the source to find all `require(path)` calls to determine which additional modules need to be included in the output bundles (done recursively). For a `require` to automatically be detected it must be in the form `require(\"<module-name>\")` or `require.resolve(\"<module-name>\")`.\n\nThe [lasso-require](https://github.com/lasso-js/lasso-require) plugin will automatically wrap all Node.js modules so that the psuedo globals (i.e. `require`, `module`, `exports`, `__filename` and `__dirname`) are made available to the module source code.\n\nThe `lasso-require` plugin also supports [browserify shims](https://github.com/substack/node-browserify#compatibility) and [browserify transforms](https://github.com/substack/node-browserify/wiki/list-of-transforms).\n\nFor more details on how the Node.js modules are supported on the browser, please see the documentation for the [lasso-js-samples/lasso-require](https://github.com/lasso-js/lasso-require) plugin.\n\n# Babel Support\n\nThe [lasso-babel-transform](https://github.com/lasso-js/lasso-babel-transform) module provides support for transpiling JavaScript/JSX code using [babel](https://babeljs.io/). Please see the [lasso-babel-transform](https://github.com/lasso-js/lasso-babel-transform) docs for information on how to use that transform.\n\n# No Conflict Builds\n\nIf you're using CommonJS modules in your project then this will cause the\nCommonJS runtime to be included in your build. The CommonJS runtime utilizes\na global variable (`$_mod` by default). If your build output files need to\nco-exist with other JavaScript files that were built by Lasso separately\nthen you need to make sure that your build produces a CommonJS runtime\nthat is isolated from other builds. That is, you should not use the default\n`$_mod` global.\n\nTo enable no-conflict build, you need to configure Lasso to use a unique\nCommonJS runtime global name. This can be done by setting the `noConflict`\nconfiguration property to string that is unique to your application or project.\n\nIf you're using the JavaScript API then this is possible via:\n\n```javascript\n// To configure the default Lasso for no-conflict builds:\nrequire('lasso').configure({\n    ...\n    noConflict: 'myapp'\n});\n\n// To create a new Lasso for no-conflict builds\nrequire('lasso').create({\n    ...\n    noConflict: 'myapp'\n});\n\n```\n\nSee [Configuration](#configuration) for full list of configuration options.\n\n# Custom attributes for Script & Style tags\nIt is also possible to add custom attributes to script and style tags for both inline and external resources. It is done using the attributes `inline-script-attrs`, `inline-style-attrs`, `external-style-attrs` and `external-script-attrs` as shown below.\n\n__page.marko__\n```marko\n<lasso-page name=\"page\" package-path=\"./browser.json\"/>\n\n<html>\n    <head>\n        <lasso-head external-style-attrs={'css-custom1': true}/>\n        <lasso-slot name=\"ext-css-slot\" external-style-attrs={'css-custom2': true}/>\n        <lasso-slot name=\"css-slot\" inline-style-attrs={'css-custom3': true}/>\n    </head>\n    <body>\n        <lasso-body external-script-attrs={'js-custom1': true}/>\n        <lasso-slot name=\"ext-js-slot\" external-script-attrs={'js-custom2': true}/>\n        <lasso-slot name=\"js-slot\" inline-script-attrs={'js-custom3': true}/>\n    </body>\n</html>\n\n```\n__browser.json__\n```json\n{\n    \"dependencies\": [\n        { \"path\": \"style-ext.css\", \"slot\": \"ext-css-slot\" },\n        { \"path\": \"test-ext.js\", \"slot\": \"ext-js-slot\" },\n        \"style.css\",\n        \"test.js\",\n        { \"path\": \"style-inline.css\", \"inline\": true, \"slot\": \"css-slot\" },\n        { \"path\": \"test-inline.js\", \"inline\": true, \"slot\": \"js-slot\" }\n    ]\n}\n```\n__Output HTML__\n```html\n<html>\n    <head>\n        <link rel=\"stylesheet\" href=\"/static/page-1ae3e9bf.css\" css-custom1>\n        <link rel=\"stylesheet\" href=\"/static/page-244694d6.css\" css-custom2>\n        <style css-custom3>\n            body .inline {\n    \t        background-color: red;\n\t    }\n\t</style>\n    </head>\n    <body>\n        <script src=\"/static/page-ce0ad224.js\" js-custom1></script>\n        <script src=\"/static/page-c3a331b0.js\" js-custom2></script>\n        <script js-custom3>\n            console.log('hello-inline');\n        </script>\n    </body>\n</html>\n```\n\n## Use of defer/async with script tags\n\nIf you add `async` or `defer` to a slot for external script attrs and Lasso encounters an inline script in that slot, it will wrap the code in a listener for `DOMContentLoaded` (for defer) or `load` (for async) to ensure that the script does not execute until the rest of the deferred scripts in that slot are loaded.\n\n__page.marko__\n```marko\n<lasso-page name=\"page\" package-path=\"./browser.json\"/>\n\n<html>\n    <body>\n        <lasso-body external-script-attrs={defer: true}/>\n    </body>\n</html>\n\n```\n\n__browser.json__\n```json\n{\n    \"dependencies\": [\n        \"test.js\",\n        { \"path\": \"test-inline.js\", \"inline\": true }\n    ]\n}\n```\n\n__Output HTML__\n```html\n<html>\n    <body>\n        <script src=\"/static/page-ce0ad224.js\" defer></script>\n        <script>\n            (function() { var run = function() { console.log('hello-inline'); }; if (document.readyState === \"loading\") { document.addEventListener(\"DOMContentLoaded\", run); } else { run(); } })();\n        </script>\n    </body>\n</html>\n```\n\n# Content Security Policy Support\n\nNewer browsers support a web standard called Content Security Policy that\nprevents, among other things, cross-site scripting attacks by whitelisting\ninline `<script>` and `<style>` tags (see\n[HTML5 Rocks: An Introduction to Content Security Policy](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)).\n\n## Securing Dynamically Built Pages\nThe Lasso.js taglib for Marko is used to inject the `<script>` and `<style>`\ntags into the HTML output and Lasso.js provides support for injecting a nonce\nattribute. When Lasso.js is configured you just need to register a\n`cspNonceProvider` as shown below:\n\n```javascript\nrequire('lasso').configure({\n    cspNonceProvider: function(out) {\n        // Logic for determining the nonce will vary, but the following is one option:\n        var res = out.stream;\n        var nonce = res.csp && res.csp.nonce;\n\n        // NOTE:\n        // The code above assumes that there is some middleware that\n        // stores the nonce into a [non-standard] `res.csp.nonce` variable.\n        // Use whatever is appropriate for your app.\n        return nonce; // A string value\n    }\n});\n```\n\nA Lasso.js plugin can also be used to register the CSP nonce provider as shown below:\n\n```javascript\nmodule.exports = function(lasso, pluginConfig) {\n    lasso.setCSPNonceProvider(function(out) {\n        return 'abc123';\n    })\n};\n```\n\nRegistering a `cspNonceProvider` will result in a `nonce` attribute being added to all inline `<script>` and `<style>` tags rendered in either the `head` slot (`<lasso-head/>`) or the `body` slot (`<lasso-body/>`).\n\n\nWith a CSP nonce enable, the HTML output for a page rendered using Marko might be similar to the following:\n\n```html\n<html>\n    <head>\n        <!-- BEGIN head slot: -->\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/page1-8b866529.css\">\n        <style type=\"text/css\" nonce=\"abc123\">\n            body .inline {\n                background-color: red;\n            }\n        </style>\n        <!-- END head slot -->\n    </head>\n    <body>\n        <!-- BEGIN body slot: -->\n        <script type=\"text/javascript\" src=\"/static/page1-1097e0f6.js\"></script>\n        <script type=\"text/javascript\" nonce=\"abc123\">\n            console.log('hello-inline');\n        </script>\n        <!-- END body slot -->\n    </body>\n</html>\n```\n\nNOTE: A `nonce` attribute is only added to inline `<script>` and `<style>` tags.\n\nAs an extra convenience, Lasso.js also supports a custom `lasso-nonce`\nattribute that can be dropped onto any HTML tag in your Marko template\nfiles as shown below:\n\n```xml\n<script type=\"text/javascript\" lasso-nonce>console.log('My inline script')</script>\n<style type=\"text/css\" lasso-nonce>.my-inline-style { }</style>\n```\n\nThe output HTML will be similar to the following:\n\n```html\n<script type=\"text/javascript\" nonce=\"abc123\">console.log('My inline script')</script>\n<style type=\"text/css\" nonce=\"abc123\">.my-inline-style { }</style>\n```\n\n## Securing Statically Built Pages\n\nIf your page is statically built (such as when creating a Single Page App)\nthen you should enable inline code fingerprinting which is way to whitelist\nexactly which inline code blocks should be allowed. It is important to\nemphasize, that a _nonce_ (\"number once\") will not properly secure a\nstatically built application since the HTML is built once which prevents\nthe nonce from changing. To secure your statically built application,\nyou should instead fingerprint all of the inline code blocks and include\nthese fingerprints in your CSP.\n\nHere is an example of what CSP might look like if using SHA256 fingerprints:\n`script-src 'self' 'sha256-viOn97JiWZ/fvh2VGIpROjZabjdtdrgtfO1wlPz9w7w='`\n\n```javascript\nrequire('lasso').configure({\n    /* typical configuration goes here */\n\n    // Configure Lasso with a function that will be called for fingerprinting\n    // each inline code block...\n    fingerprintInlineCode: function(code) {\n        var shasum = crypto.createHash('sha256');\n        shasum.update(code);\n        return shasum.digest('base64');\n    }\n});\n\n// This is the full list of fingerprints that were captured\n// across all page builds\nvar inlineCodeFingerprints = [];\n\n// Collect all of the fingerprints as each page is built\nrequire('lasso').getDefaultLasso().on('afterLassoPage', function(event) {\n    var lassoPageResult = event.result;\n    var fingerprints = lassoPageResult.getInlineCodeFingerprints();\n    fingerprints.forEach(function(fingerprint) {\n        inlineCodeFingerprints.push(fingerprint);\n    });\n})\n\n// NOW BUILD YOUR PAGES HERE\n// ... build code goes here ...\n\n// NOW BUILD YOUR CONTENT SECURITY POLICY:\nvar csp = inlineCodeFingerprints.map(function(fingerprint) {\n    return `script-src 'self' 'sha256-${fingerprint}'`\n}).join('; ');\n\n```\n\n# Available Plugins\n\nBelow is a list of plugins that are currently available:\n\n__Core plugins:__\n\n* [lasso-require](https://github.com/lasso-js/lasso-require): Node.js-style require for the browser (similar to [browserify](https://github.com/substack/node-browserify))\n* [lasso-minify-css](https://github.com/lasso-js/lasso-minify-css): Minify CSS files using [sqwish](https://github.com/ded/sqwish)\n* [lasso-minify-js](https://github.com/lasso-js/lasso-minify-js): Minify JavaScript files using [terser](https://github.com/terser-js/terser)\n* [lasso-resolve-css-urls](https://github.com/lasso-js/lasso-resolve-css-urls): Replace each resource URL in a CSS file with an lassoed resource URL\n\n__Third-party plugins__\n\n* [lasso-dust](https://github.com/lasso-js/lasso-dust): Compile [Dust](https://github.com/linkedin/dustjs) template files to JavaScript\n* [lasso-handlebars](https://github.com/lasso-js/lasso-handlebars): Compile [Handlebars](http://handlebarsjs.com/) template files to JavaScript\n* [lasso-image](https://github.com/lasso-js/lasso-image): Get image info (including URL, width and height) for any image on both the server and client\n* [lasso-imagemin](https://github.com/lasso-js/lasso-imagemin): Minify GIF, PNG, JPG and SVG images during optimization\n* [lasso-jade](https://github.com/lasso-js/lasso-jade): Compile [Jade](http://jade-lang.com/) templates to JavaScript\n* [lasso-jsx](https://github.com/lasso-js/lasso-jsx): Compile [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) files to JavaScript\n* [lasso-less](https://github.com/lasso-js/lasso-less): Compile [Less](http://lesscss.org/) files to CSS\n* [lasso-lodash](https://github.com/lasso-js/lasso-lodash): Compile [Lo-Dash](https://lodash.com/) files to JavaScript\n* [lasso-marko](https://github.com/lasso-js/lasso-marko): Compile [Marko template](https://github.com/marko-js/marko) files to JavaScript\n* [lasso-sass](https://github.com/lasso-js/lasso-sass): Compile [Sass](https://github.com/sass/node-sass) files to CSS\n* [lasso-stylus](https://github.com/lasso-js/lasso-stylus): Compile [Stylus](http://learnboost.github.io/stylus/) files to CSS\n* [lasso-clean-css](https://github.com/yomed/lasso-clean-css): Minify CSS files using [clean-css](https://github.com/jakubpawlowicz/clean-css)\n* [lasso-autoprefixer](https://github.com/lasso-js/lasso-autoprefixer): Autoprefix CSS with vendor prefixes using [autoprefixer-core](https://github.com/postcss/autoprefixer-core)\n* [lasso-modernizr](https://github.com/darkwebdev/lasso-modernizr): Generate custom [Modernizr](https://modernizr.com) build\n* [lasso-optimize-iife](https://github.com/austinkelleher/lasso-optimize-iife): Optimize JavaScript immediately-invoked functions using [optimize-js](https://github.com/nolanlawson/optimize-js)\n* [lasso-rtl-css](https://github.com/shadiabuhilal/lasso-rtl-css): Transform CSS from left-to-right to right-to-left using [rtlcss](https://github.com/MohammadYounes/rtlcss)\n* [lasso-prepack](https://github.com/austinkelleher/lasso-prepack): Optimize JavaScript using [prepack](https://prepack.io/)\n* [lasso-typescript](https://github.com/ajay2507/lasso-typescript): compile [Typescript](https://www.typescriptlang.org/) in to Javascript.\n* [grunt-lasso](https://github.com/ajay2507/grunt-lasso): [Grunt](https://gruntjs.com/) plugin for Lasso js.\n* [lasso-analyzer](https://github.com/ajay2507/lasso-analyzer): Bundle Analyzer plugin for Lasso js.\n* [lasso-unpack](https://github.com/ajay2507/lasso-unpack): Generating an asset manifest for all source files .\n* [lasso-minify-transpile-inline](https://github.com/dsathyakumar/lasso-minify-transpile-inline): Lasso JS plugin to minify & transpile `inline` single file dependency assets that are not of `type: require`.\n* [rollup-plugin-lasso](https://github.com/dsathyakumar/rollup-plugin-lasso/): Bundles with Rollup (in cases where Lasso cannot be used) and pipes the output to Lasso - to be a part of Lasso's lifecycle.\n\nTo use a third-party plugin, you must first install it using `npm install`. For example:\n\n```bash\nnpm install lasso-less --save\n```\n\nIf you create your own plugin please send a Pull Request and it will show up above. Also, do not forget to tag your plugin with `lasso-plugin` and `lasso` in your `package.json` so that others can browse for it using [npm](https://www.npmjs.org/)\n\n# Extending Lasso.js\n\nOnly read below if you are building plugins or transforms to further enhance the `lasso` module.\n\n## Custom Plugins\n\nA plugin can be used to change how the lasso operates. This includes the following:\n\n* Register a custom dependency to support dependencies that compile to JS or CSS\n    * Examples:\n        * Register a dependency handler for \"less\" files to compiles Less to CSS\n        * Register a dependency handler for \"marko\" files to compiles Marko template files to JS\n* Register a custom bundle writer\n    * Examples:\n        * Upload bundles to a resource server that backs a CDN instead of writing them to disk\n* Register output transforms\n    * Examples:\n        * Add an output transform to minify JavaScript code\n        * Add an output transform to minify CSS code\n        * Add an output transform to remove `console.log` from JS code\n        * Add an output transform to resolve image URLs in CSS files\n* Configure the lasso\n    * Examples:\n        * Allow a plugin to automatically configure the lasso for production usage\n\nA plugin is simply a Node.js module that exports a function with the following signature:\n\n```javascript\n/**\n * A plugin for Lasso.js\n * @param  {lasso/lib/Lasso} lasso An instance of a Lasso that can be configured\n * @param  {Object} The plugin configuration provided by the user\n */\nmodule.exports = function(lasso, config) {\n    // Register dependency types:\n    lasso.dependencies.registerJavaScriptType('my-js-type', require('./dependency-my-js-type'));\n    lasso.dependencies.registerStyleSheetType('my-css-type', require('./dependency-my-css-type'));\n    lasso.dependencies.registerPackageType('my-package-type', require('./dependency-my-package-type'));\n\n    // Add an output transform\n    lasso.addTransform(require('./my-transform'));\n\n    // Register a custom Node.js/CommonJS module compiler for a custom filename extension\n    // var myModule = require('./hello.test');\n    lasso.dependencies.registerRequireExtension('test', function(path, context, callback) {\n        callback(null, \"exports.sayHello = function() { console.log('Hello!'); }\");\n    });\n};\n```\n\n## Custom Dependency Types\n\nThere are three types of dependencies that are supported:\n\n* __JavaScript dependency:__ Produces JavaScript code\n* __CSS dependency:__ Produces CSS code\n* __Package dependency:__ Produces a package of additional JavaScript and CSS dependencies\n\nEach of these dependencies is described in the next few sections. However, it is recommended to also check out the source code of [available plugins](#available-plugins) listed above (e.g. [lasso-less](https://github.com/lasso-js/lasso-less)).\n\n### Custom JavaScript Dependency Type\n\nIf you would like to introduce your own custom dependency types then you will need to have your plugin register a dependency handler. This is illustrated in the following sample code:\n\n```javascript\nconst fs = require('fs');\n\nmodule.exports = function myPlugin(lasso, config) {\n    lasso.dependencies.registerJavaScriptType(\n        'my-custom-type',\n        {\n            // Declare which properties can be passed to the dependency type\n            properties: {\n                'path': 'string'\n            },\n\n            // Validation checks and initialization based on properties:\n            async init (context) {\n                if (!this.path) {\n                    throw new Error('\"path\" is required');\n                }\n\n                // NOTE: resolvePath can be used to resolve a provided relative path to a full path\n                this.path = this.resolvePath(this.path);\n            },\n\n            // Read the resource:\n            async read (context) {\n                const src = await fs.promises.readFile(this.path, {encoding: 'utf8'});\n                return myCompiler.compile(src);\n                // NOTE: A stream can also be returned\n            },\n\n            // getSourceFile is optional and is only used to determine the last modified time\n            // stamp and to give the output file a reasonable name when bundling is disabled\n            getSourceFile: function() {\n                return this.path;\n            }\n        });\n};\n```\n\nOnce registered, the above dependency can then be referenced from an `browser.json` as shown in the following code:\n\n```json\n{\n    \"dependencies\": [\n        \"my-custom-type: hello.file\"\n    ]\n}\n```\n\nIf a custom dependency supports more than just a `path` property, additional properties could be provided as shown in the following sample code:\n\n```json\n{\n    \"dependencies\": [\n        {\n            \"type\": \"my-custom-type\",\n            \"path\": \"hello.file\",\n            \"foo\": \"bar\",\n            \"hello\": true\n        }\n    ]\n}\n```\n\n\n### Custom CSS Dependency Type\n\nIf you would like to introduce your own custom dependency types then you will need to have your plugin register a dependency handler as shown in the following sample code:\n\n```javascript\nmodule.exports = function myPlugin(lasso, config) {\n    lasso.dependencies.registerStyleSheetType(\n        'my-custom-type',\n        handler);\n};\n```\n\nThe `handler` argument for a CSS dependency has the exact same interface as a handler for a JavaScript dependency (described earlier).\n\n### Custom Package Type\n\nA custom package dependency can be used to dynamically resolve additional dependencies at optimization time. The sample package dependency handler below illustrates how a package dependency can be used to automatically include every file in a directory as a dependency:\n\n```javascript\nconst { promisify } = require('util');\nconst fs = promisify(require('fs'));\nconst path = promisify(require('path'));\n\nlasso.dependencies.registerPackageType('dir', {\n    properties: {\n        'path': 'string'\n    },\n\n    async init (context) {\n        let path = this.path;\n\n        if (!path) {\n            callback(new Error('\"path\" is required'));\n        }\n\n        this.path = path = this.resolvePath(path); // Convert the relative path to an absolute path\n\n        const stat = await fs.stat(path);\n        if (!stat.isDirectory()) {\n            throw new Error('Directory expected: ' + path);\n        }\n    },\n\n    async getDependencies (context) {\n        const dir = this.path;\n        const filenames = await fs.readdir(dir);\n\n        // Convert the filenames to full paths\n        var dependencies = filenames.map(function(filename) {\n            return path.join(dir, filename);\n        });\n\n        return dependencies;\n    },\n\n    getDir: function() {\n        // If the dependencies are associated with a directory then return that directory.\n        // Otherwise, return null\n        return this.path;\n    }\n});\n```\n\n## Custom Output Transforms\n\nRegistered output transforms are used to process bundles as they are written to disk. As an example, an output transform can be used to minify a JavaScript or CSS bundle. Another example is that an output transform may be used to remove `console.log` statements from output JavaScript code. Transforms should be registered by a plugin using the `lasso.addTransform(transform)` method.\n\nAs an example, the following unhelpful transform will convert all JavaScript source code to upper case:\n\n```javascript\nmodule.exports = function (lasso, pluginConfig) {\n    lasso.addTransform({\n\n        // Only apply to JavaScript code\n        contentType: 'js', //  'css' is the other option\n\n        // Give your module a friendly name (helpful for debugging in case something goes wrong in your code)\n        name: module.id,\n\n        // If stream is set to false then a String will be provided. Otherwise, a readable stream will be provided\n        stream: false,\n\n        // Do the magic:\n        transform: function(code, lassoContext) {\n            return code.toUpperCase();\n        }\n    });\n};\n```\n\nBelow is the streaming version of the same transform:\n\n```javascript\nvar through = require('through');\n\nmodule.exports = function (lasso, pluginConfig) {\n    lasso.addTransform({\n\n        // Only apply to JavaScript code\n        contentType: 'js', // 'css' is the other option\n\n        // Give your module a friendly name (helpful for debugging in case something goes wrong in your code)\n        name: module.id,\n\n        stream: true, // We want the code to be streamed to us\n\n        // Do the magic:\n        transform: function(inStream, lassoContext) {\n            return inStream.pipe(through(\n                function write(data) {\n                    this.queue(data.toUpperCase());\n                }));\n        }\n    });\n};\n```\n\n# JavaScript API\n\nSee [JavaScript API](./docs/javascript-api.md).\n\n# AMD Compatibility\n\nSee [AMD Compatibility](./docs/amd.md).\n\n# Sample Projects\n\n* [lasso-js-samples/lasso-async](https://github.com/lasso-js-samples/lasso-async): Demonstrates asynchronous/lazy dependency loading.\n* [lasso-js-samples/lasso-cli](https://github.com/lasso-js-samples/lasso-cli): Demonstrates the command-line interface.\n* [lasso-js-samples/lasso-code-splitting](https://github.com/lasso-js-samples/lasso-code-splitting): Demonstrates splitting out dependencies that are common across pages into a separate bundle.\n* [lasso-js-samples/lasso-config](https://github.com/lasso-js-samples/lasso-config): Demonstrates the usage of a JSON config file.\n* [lasso-js-samples/lasso-express](https://github.com/lasso-js-samples/lasso-express): Demonstrates using Lasso.js at runtime as part of an Express server app.\n* [lasso-js-samples/lasso-js-api](https://github.com/lasso-js-samples/lasso-js-api): Demonstrates how to use JavaScript API to lasso a page and inject the resulting head and body markup into a page.\n* [lasso-js-samples/lasso-taglib](https://github.com/lasso-js-samples/lasso-taglib): Demonstrates the use of the lasso taglib for Marko.\n* [lasso-js-samples/lasso-templates](https://github.com/lasso-js-samples/lasso-templates): Demonstrates the use of rendering the same templates on both the server and the client.\n\n# Discuss\n\nPlease join us in the [Gitter chat room for Lasso.js](https://gitter.im/lasso-js/lasso) or [open a new Github issue](https://github.com/lasso-js/lasso/issues).\n\n# Maintainers\n\n* [Patrick Steele-Idem](https://github.com/patrick-steele-idem) (Twitter: [@psteeleidem](http://twitter.com/psteeleidem))\n* [Phillip Gates-Idem](https://github.com/philidem/) (Twitter: [@philidem](https://twitter.com/philidem))\n* [Michael Rawlings](https://github.com/mlrawlings) (Twitter: [@mlrawlings](https://twitter.com/mlrawlings))\n\n# Contributors\n\n* Vinod Kumar (Twitter: [@vinodl](https://twitter.com/vinodl))\n    - [gulp-lasso](https://github.com/lasso-js/gulp-lasso)\n    - [lasso-jsx](https://github.com/lasso-js/lasso-jsx)\n* Merwan Rodriguez (Twitter: [@uno7](https://twitter.com/uno7))\n    - [lasso-autoprefixer](https://github.com/lasso-js/lasso-autoprefixer)\n\n# Contribute\n\nPull Requests welcome. Please submit Github issues for any feature enhancements, bugs or documentation problems.\n\n# License\n\nApache License v2.0\n"
  },
  {
    "path": "browser-refresh/index.js",
    "content": "module.exports = require('../src/browser-refresh');\n"
  },
  {
    "path": "docs/amd.md",
    "content": "# AMD Compatibility\n\nLasso.js does not support the AMD module syntax. You can, however, use the [deamdify](https://github.com/jaredhanson/deamdify) Browserify transform if you have third-party AMD code that should be transformed to CommonJS syntax.\n\n## raptor-amd\n\nIf you need a lightweight AMD runtime to support external code, you can also include the [raptor-amd](https://github.com/raptorjs/raptor-amd) module on your page. However, that module is no longer maintained and is only kept around for legacy reasons.\n\n## Masking the AMD define function\n\nIf you have both an AMD runtime and a CommonJS runtime on the same page then modules wrapped using a UMD wrapper that first checks for `define` (instead of `module.exports`) will attempt to define the module as an AMD module instead of using CommonJS. If you find that this issue is causing problems you can add a special `\"mask-define\": true` property as shown below:\n\n_browser.json_\n\n```json\n{\n    \"dependencies\": [\n        {\n            \"path\": \"path/to/some-umd-module.js\",\n            \"mask-define\": true\n        }\n    ]\n}\n```\n\nThis will result in code similar to the following:\n\n```javascript\n(function(define) { /* mask define */\n    // typeof define === 'undefined'\n    // ...third-party goes here\n}()); // END: mask define wrapper\n```"
  },
  {
    "path": "docs/bundling.md",
    "content": "Lasso.js Bundling\n====================================\n\nBundling can either be enabled or disabled during page optimization. If bundling is disabled then every dependency will be written to its own file. If bundling is enabled then dependencies will be concatenated together based on the bundles configured for the application and page. Lasso.js allows both application-level and page-level bundles to be configured.\n\n# Application-level Bundles\n\nApplication-level bundles are bundles that apply to every page that are lassoed. Application-level bundles allow for consistant bundles across pages when pages have common dependencies. Application-level bundles are typically configured as part of the lasso configuration as show below:\n\n```json\n{\n    ...\n    \"bundles\": [\n        {\n            \"name\": \"jquery\",\n            \"dependencies\": [\n                \"require: jquery\"\n            ]\n        },\n        {\n            \"name\": \"math\",\n            \"dependencies\": [\n                \"require: ./add\"\n            ]\n        }\n    ]\n}\n```\n\nWhile assigning dependencies to bundles during a page optimization, if the lasso detects that a dependency is part of a application-level bundle then that bundle will be added to the list of output bundles for the page and result in either a `<script>` or `<link>` tag including the resource associated with the application-level bundle.\n\n# Page-level Bundles\n\nThe lasso also allows for page-level to be configured when optimizing a particular page. Application-level bundles always take precedence over page-level bundles. Page-level bundles can be configured when optimizing a page as shown in the following example JavaScript code:\n\n```javascript\nrequire('lasso').lassoPage({\n        name: \"my-page\",\n        dependencies: [\n            ...\n        ],\n        bundles: [\n            {\n                name: \"foo\",\n                dependencies: [\n                    \"require: ./foo\"\n                ]\n            }\n        ]\n    });\n```\n\nIf you are using the taglib, page-level bundles can be passed in as part of the attributes. For example, with Marko:\n\n```html\n<lasso-page package-path=\"./browser.json\" bundles=\"./lasso-bundles.json\"/>\n```\n\n# Recursive Dependencies and Bundling\n\nWhen assigning a dependency to a bundle it is possible that a particular package dependency might have additional dependencies. Lasso.js gives you control over how transitive dependencies are handled via a special \"recurse into\" option. The possible values for \"recurse into\" option are the following:\n\n* __`\"all\"`:__ All transitive dependencies, regardless of where they are located on disk, will be added to the bundle.\n* __`\"dir\"`:__ Only transitive dependencies that are in the exact same directory associated with the root dependency will be added to the bundle.\n* __`\"dirtree\"`:__ Only transitive dependencies that are in the same directory associated with the root dependency _or_ within a nested directory associated with the root dependency will be added to the bundle.\n* __`\"module\"`:__ Only dependencies that are within the root directory of the module associated with the root dependency will be added to the bundle unless the transitive dependency is a directory under the root module's `node_modules` directory.\n\nThe \"recurse into\" option can be specified using the `recurseInto` property at the bundle level or at the dependency level as shown in the following sample code:\n\n```javascript\nrequire('lasso').lassoPage({\n        name: \"my-page\",\n        dependencies: [\n            ...\n        ],\n        bundles: [\n            {\n                name: \"foo\",\n                dependencies: [\n                    // Specified for a single dependency:\n                    { path: \"require: foo\", recurseInto: \"dir\" }\n                ]\n            },\n            {\n                name: \"bar\",\n                dependencies: [\n                    \"require: bar\"\n                ],\n                // Specified at the bundle level:\n                reurseInto: \"dir\"\n            }\n        ]\n    });\n```\n\n_NOTE: the \"require\" dependency type is implemented as a package dependency since it can resolve to additional transitive dependencies based on which modules are required inside the JavaScript source code._\n\nTo hopefully make things clear, let's assume we have the following project structure:\n\n```\n.\n├── main.js\n└── node_modules\n    ├── foo\n    │   ├── index.js\n    │   ├── lib\n    │   │   └── foo.js\n    │   └── node_modules\n    │       └── bar\n    │           └── index.js\n    └── baz\n        └── index.js\n```\n\nLet's assume that we have the following transitive dependencies:\n\n```\nrequire('./main.js') →\n└── require('foo') →\n    └── require('node_modules/foo/index.js')\n        └── require('node_modules/foo/lib/foo.js')\n            ├── require('bar')\n            │   └── require('node_modules/foo/node_modules/bar/index.js')\n            └── require('baz')\n                └── require('node_modules/baz/index.js')\n```\n\nLet's try optimizing our `main.js` with different bundling options:\n\n__Option 1) all:__\n\n```json\n{\n    ...\n    \"bundles\": [\n        {\n            \"name\": \"foo\",\n            \"dependencies\": [\n                { \"path\": \"require: foo\", \"recurseInto\": \"all\" }\n            ]\n        }\n    ]\n}\n```\n\nContent of the \"foo\" bundle:\n\n* `node_modules/foo/index.js`\n* `node_modules/foo/lib/foo.js`\n* `node_modules/foo/node_modules/bar/index.js`\n* `node_modules/baz/index.js`\n\n__Option 2) dir:__\n\n```json\n{\n    ...\n    \"bundles\": [\n        {\n            \"name\": \"foo\",\n            \"dependencies\": [\n                { \"path\": \"require: foo\", \"recurseInto\": \"dir\" }\n            ]\n        }\n    ]\n}\n```\n\nContent of the \"foo\" bundle:\n\n* `node_modules/foo/index.js`\n\n__Option 3) dirtree:__\n\n```json\n{\n    ...\n    \"bundles\": [\n        {\n            \"name\": \"foo\",\n            \"dependencies\": [\n                { \"path\": \"require: foo\", \"recurseInto\": \"dirtree\" }\n            ]\n        }\n    ]\n}\n```\n\nContent of the \"foo\" bundle:\n\n* `node_modules/foo/index.js`\n* `node_modules/foo/lib/foo.js`\n* `node_modules/foo/node_modules/bar/index.js`\n\n__Option 4) module:__\n\n```json\n{\n    ...\n    \"bundles\": [\n        {\n            \"name\": \"foo\",\n            \"dependencies\": [\n                { \"path\": \"require: foo\", \"recurseInto\": \"module\" }\n            ]\n        }\n    ]\n}\n```\n\nContent of the \"foo\" bundle:\n\n* `node_modules/foo/index.js`\n* `node_modules/foo/lib/foo.js`\n"
  },
  {
    "path": "docs/javascript-api.md",
    "content": "JavaScript API\n==============\n\n## require('lasso')\n\n### Methods\n\n#### configure(config)\n\nConfigures the default lasso instance using the provided `config`. The `config` can either be an object or a path to a JSON file.\n\n#### create(config)\n\nCreates a new configured [Lasso](#Lasso-type) instance.\n\n#### getDefaultLasso()\n\nReturns the default [Lasso](#Lasso-type) instance.\n\n#### lassoPage(options, callback)\n\nEquivalent to `require('lasso').getDefaultLasso().lassoPage(options, callback)`. See [Lasso » lassoPage](#Lasso-lassoPage) below.\n\n#### lassoResource(pageConfig, callback)\n\nEquivalent to `require('lasso').getDefaultLasso().lassoResource(options, callback)`. See [Lasso » lassoResource](#Lasso-lassoResource) below.\n\n## require('lasso/middleware')\n\n### serveStatic(options)\n\nExpress middleware to serve up static files generated by Lasso.js.\n\nExample usage:\n\n```javascript\napp.use(require('lasso/middleware').serveStatic());\n```\n\n- Supported options:\n    - __lasso__ - The configured lasso instance (defaults to `require('lasso').getDefaultLasso()`)\n    - __sendOptions__ - Options passed to the [send](https://github.com/pillarjs/send) module that is used to serve up static assets\n\n<a name=\"Config-type\"></a>\n\n## Config\n\nSee [./lib/Config.js](./lib/Config.js)\n\n<a name=\"Lasso-type\"></a>\n\n## Lasso\n\n### Methods\n\n<a name=\"Lasso-lassoPage\"></a>\n\n#### lassoPage(options, callback)\n\nProcesses all of the dependencies for a page to produce a set of static JS and CSS bundles, as well as any other static assets.\n\nThe result will be a [LassoPageResult](#LassoPageResult-type) instance that provides the list of generated URLs for all of the static bundles, as well as a list of the generated files.\n\nSupported options:\n\n- __dependencies__ - An array of dependencies\n- __from__ - The base directory for calculating relative paths (optional)\n- __packagePath__ - A path to a `browser.json` file\n- __packagePaths__ - An array of paths to `browser.json` files\n\n<a name=\"Lasso-lassoResource\"></a>\n\n#### lassoResource(path|buffer[, options]) : Promise\n\nSends any type of resource through the Lasso.js asset pipeline and returns a `Promise` that eventually resolves to a result object with the URL. If Lasso is configured to use the default file writer then the resource referenced by the path will be copied to the static output directory. The callback will be invoked when the resource is fully written and the URL to the output resource will be part of the object that the returned promise eventually resolves to. In addition, if Lasso is configured with fingerprints enabled then a fingerprint will be added to the output resource URL.\n\nExample usage passing an asset path:\n\n```javascript\nconst myLasso = require('lasso').getDefaultLasso();\n\nmyLasso.lassoResource('path/to/foo.png')\n    .then(function(result) {\n        var url = result.url; // URL for the output resource\n    });\n```\n\nExample usage passing a buffer:\n\n```javascript\nconst fs = require('fs');\nconst myLasso = require('lasso').getDefaultLasso();\n\nconst imgPath = nodePath.join(__dirname, 'ebay.png');\n\n;(async function() {\n  const buffer = await fs.promises.readFile(imgPath);\n\n  const result = await lasso.lassoResource(buffer, {\n      name: 'test',\n      extension: 'png'\n  });\n\n   // URL for the output resource (e.g. /static/test-02827b0c.png)\n  const { url } = await myLasso.lassoResource(buffer)\n})();\n```\n\nSupported options:\n\n- __cache__ (boolean) - Whether or not the result should be cached (the resource path will be used as the cache key). The default value is `true`.\n- __name__ (string) - Name to prefix the buffer path\n- __extension__ (string) - File extension to append to the end of a buffer path\n\n#### lassoResource(path[, options], callback)\n\nThis method is similar to the other version that returns a `Promise` (`lassoResource(path[, options]) : Promise`), but if a `callback` function is provided as the last argument then the usage will be as follows:\n\n```javascript\nvar myLasso = require('lasso').getDefaultLasso();\nmyLasso.lassoResource('path/to/foo.png', function(err, result) {\n    if (err) {\n        // Handle the error\n    } else {\n        var url = result.url; // URL for the output resource\n    }\n});\n```\n\n### Properties\n\n#### config\n\nThe loaded [Config](#Config-type) config instance\n\n<a name=\"LassoPageResult-type\"></a>\n\n## LassoPageResult\n\n### Methods\n\n#### getBodyHtml()\n\nShort-hand for `lassoPageResult.getHtmlForSlot('body')`.\n\n#### getCSSFiles()\n\nReturns an array of all of file paths for all of the generated JavaScript bundles\n\n#### getCSSUrls()\n\nReturns an array of all of URLs for all of the generated CSS bundles\n\n#### getHeadHtml()\n\nShort-hand for `lassoPageResult.getHtmlForSlot('head')`.\n\n#### getHtmlBySlot()\n\nReturns the HTML markup for each slot. The returned object will be an object. For each property of the returned object, the name will be the slot name (e.g. `head`) and the value will be the HTML markup (e.g. `<link rel=\"stylesheet\" type=\"text/css\" href=\"static/style.less.css\">`).\n\n#### getHtmlForSlot(slotName)\n\nExample usage:\n\n```javascript\nvar headHtml = lassoPageResult.getHtmlForSlot('head');\nvar bodyHtml = lassoPageResult.getHtmlForSlot('body');\n```\n\n#### getJavaScriptFiles()\n\nReturns an array of all of file paths for all of the generated JavaScript bundles\n\n#### getJavaScriptUrls()\n\nReturns an array of all of URLs for all of the generated JavaScript bundles\n\n#### getOutputFiles()\n\nReturns an array of all of file paths for all of the generated files\n"
  },
  {
    "path": "docs/migration-optimizer-to-lasso.md",
    "content": "Optimizer.js to Lasso.js Upgrade Guide\n======================================\n\n- Uninstall old modules:\n  - `npm uninstall optimizer --save`\n  - `npm uninstall optimizer-marko --save`\n  - etc.\n- Install new modules\n  - `npm install lasso --save`\n  - `npm install lasso-marko --save`\n  - etc.\n- API changes\n  - `require('optimizer')` → `require('lasso')`\n  - `optimizer.optimizePage(...)` → `lasso.lassoPage(...)`\n- Rename `optimizer.json` files to `browser.json`\n- Rename `*.optimizer.json` files to `*.browser.json`\n- Update Marko custom tags:\n  - Rename `<optimizer-page>` to `<lasso-page>`\n  - Rename `<optimizer-head>` to `<lasso-head>`\n  - Rename `<optimizer-body>` to `<lasso-body>`\n- browser.json changes\n  - remove unnecessary spacing:  e.g. convert \"require :\" to \"require:\"\n"
  },
  {
    "path": "getImageInfo.js",
    "content": "module.exports = require('./src/plugins/lasso-image').getImageInfo;\n"
  },
  {
    "path": "index.js",
    "content": "module.exports = require('./src');\n"
  },
  {
    "path": "middleware/index.js",
    "content": "module.exports = require('../src/middleware');\n"
  },
  {
    "path": "middleware/koa/serveStatic.js",
    "content": "module.exports = require('../../src/middleware/koa/serveStatic');\n"
  },
  {
    "path": "middleware/serveStatic.js",
    "content": "module.exports = require('../src/middleware/serveStatic');\n"
  },
  {
    "path": "node-require-no-op.js",
    "content": "module.exports = require('./src/node-require-no-op');\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"lasso\",\n  \"description\": \"Lasso.js is a build tool and runtime library for building and bundling all of the resources needed by a web application\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/lasso-js/lasso.git\"\n  },\n  \"scripts\": {\n    \"test-coverage-report\": \"nyc npm run mocha && nyc report --reporter=html && open ./coverage/index.html\",\n    \"test\": \"nyc npm run mocha && npm run eslint\",\n    \"mocha\": \"rm -rf .cache && mocha --timeout 4000 --ui bdd --reporter spec ./test ./test/unit\",\n    \"eslint\": \"eslint src/ browser-refresh/ middleware/\"\n  },\n  \"author\": \"Patrick Steele-Idem <pnidem@gmail.com>\",\n  \"maintainers\": \"Patrick Steele-Idem <pnidem@gmail.com>\",\n  \"dependencies\": {\n    \"@babel/code-frame\": \"^7.18.6\",\n    \"app-root-dir\": \"^1.0.2\",\n    \"assert\": \"^2.0.0\",\n    \"browser-refresh-client\": \"^1.1.4\",\n    \"buffer\": \"^6.0.3\",\n    \"clean-css\": \"^5.3.1\",\n    \"complain\": \"^1.6.0\",\n    \"espree\": \"^9.4.0\",\n    \"estraverse\": \"^5.3.0\",\n    \"events\": \"^3.3.0\",\n    \"glob\": \"^8.0.3\",\n    \"image-size\": \"^1.0.2\",\n    \"lasso-caching-fs\": \"^1.0.2\",\n    \"lasso-loader\": \"^3.0.2\",\n    \"lasso-modules-client\": \"^2.0.7\",\n    \"lasso-package-root\": \"^1.0.1\",\n    \"lasso-resolve-from\": \"^1.2.0\",\n    \"mime\": \"^3.0.0\",\n    \"mkdirp\": \"^1.0.4\",\n    \"path-browserify\": \"1.0.1\",\n    \"process\": \"^0.11.10\",\n    \"property-handlers\": \"^1.1.1\",\n    \"raptor-async\": \"^1.1.3\",\n    \"raptor-cache\": \"^2.0.4\",\n    \"raptor-css-parser\": \"^1.1.6\",\n    \"raptor-logging\": \"^1.1.3\",\n    \"raptor-regexp\": \"^1.0.1\",\n    \"raptor-util\": \"^3.2.0\",\n    \"resolve-from\": \"^4.0.0\",\n    \"send\": \"^0.18.0\",\n    \"stream-browserify\": \"^3.0.0\",\n    \"string_decoder\": \"^1.3.0\",\n    \"strip-json-comments\": \"^3.1.1\",\n    \"terser\": \"^5.15.0\",\n    \"through\": \"^2.3.8\",\n    \"url\": \"^0.11.0\",\n    \"util\": \"^0.12.4\"\n  },\n  \"devDependencies\": {\n    \"chai\": \"^4.3.6\",\n    \"eslint\": \"^8.24.0\",\n    \"eslint-config-standard\": \"^17.0.0\",\n    \"eslint-plugin-import\": \"^2.26.0\",\n    \"eslint-plugin-node\": \"^11.1.0\",\n    \"eslint-plugin-promise\": \"^6.0.1\",\n    \"eslint-plugin-standard\": \"^4.1.0\",\n    \"mocha\": \"^10.0.0\",\n    \"nyc\": \"^15.1.0\",\n    \"require-self-ref\": \"^2.0.1\",\n    \"sinon\": \"^14.0.0\",\n    \"strip-ansi\": \"^6.0.0\"\n  },\n  \"engines\": {\n    \"node\": \">=16\"\n  },\n  \"nyc\": {\n    \"exclude\": [\n      \"**/coverage/**\",\n      \"**/test/**\",\n      \"**/cache/**\"\n    ]\n  },\n  \"license\": \"Apache-2.0\",\n  \"main\": \"./index.js\",\n  \"publishConfig\": {\n    \"registry\": \"https://registry.npmjs.org/\"\n  },\n  \"keywords\": [\n    \"bundler\",\n    \"build\",\n    \"css\",\n    \"javascript\",\n    \"concat\",\n    \"minify\"\n  ],\n  \"version\": \"4.0.4\"\n}\n"
  },
  {
    "path": "src/AsyncPackage.js",
    "content": "function AsyncPackage(name) {\n    this.name = name;\n    this.bundles = [];\n    this.bundlesByKey = {};\n}\n\nAsyncPackage.prototype = {\n    getName: function() {\n        return this.name;\n    },\n\n    addBundle: function(bundle) {\n        const bundleKey = bundle.getKey();\n\n        if (!this.bundlesByKey[bundleKey]) {\n            this.bundlesByKey[bundleKey] = true;\n            this.bundles.push(bundle);\n        }\n    },\n\n    getMeta: function(context) {\n        const meta = {\n            css: [],\n            js: []\n        };\n\n        const bundles = this.bundles;\n\n        for (let i = 0, len = bundles.length; i < len; i++) {\n            const bundle = bundles[i];\n            let url;\n            if (!bundle.hasContent() || !(url = bundle.getUrl(context))) {\n                // skip bundles without content or bundles that don't have a URL.\n                // TODO: Figure out what to do with inline dependencies that belong to an async bundle\n                //       These dependencies don't have a URL but code should still be included, right?\n                continue;\n            }\n            if (bundle.isJavaScript()) {\n                meta.js.push(url);\n            } else if (bundle.isStyleSheet()) {\n                meta.css.push(url);\n            } else {\n                throw new Error('Invalid bundle content type: ' + bundle.getContentType());\n            }\n        }\n\n        if (!meta.js.length) {\n            delete meta.js;\n        }\n\n        if (!meta.css.length) {\n            delete meta.css;\n        }\n\n        return meta;\n    }\n};\n\nmodule.exports = AsyncPackage;\n"
  },
  {
    "path": "src/Bundle.js",
    "content": "const contentTypes = require('./content-types');\n\nconst Bundle = function(name) {\n    this.name = name;\n    this.dependencies = [];\n    this.slot = 'body';\n    this.contentType = null;\n    this.written = false;\n    this.fingerprint = undefined;\n    this.inlinePos = false;\n    this.url = null;\n    this.mergeInline = true;\n    this.key = null;\n\n    this.config = {};\n\n    this.code = null;\n\n    this.data = {};\n};\n\nBundle.getKey = function(dependencySlot, contentType, inlinePos, targetBundleName) {\n    return [dependencySlot, contentType, (inlinePos == null) ? '' : inlinePos.toString(), targetBundleName].join('/');\n};\n\nBundle.prototype = {\n    isInline: function() {\n        return this.inlinePos != null;\n    },\n\n    setInlinePos: function(inlinePos) {\n        this.inlinePos = inlinePos;\n    },\n\n    getInlinePos: function(inline) {\n        return this.inlinePos;\n    },\n\n    isAsyncOnly: function() {\n        return this.config.asyncOnly;\n    },\n\n    /**\n     * This property controls whether or not the inline content\n     * gets merged with other inline content targeted for the same position\n     * or if remains in standalone <script> or <style> block in the\n     * order that it is added\n     */\n    setMergeInline: function(mergeInline) {\n        this.mergeInline = mergeInline;\n    },\n\n    isMergeInline: function() {\n        return this.mergeInline;\n    },\n\n    addDependency: function(dependency) {\n        const index = this.dependencies.length;\n        this.dependencies.push(dependency);\n        return index;\n    },\n\n    removeDependencyByIndex: function(index) {\n        this.dependencies[index] = undefined;\n    },\n\n    getDependencies: function() {\n        return this.dependencies;\n    },\n\n    hasDependencies: function() {\n        return this.dependencies.length !== 0;\n    },\n\n    getName: function() {\n        return this.name;\n    },\n\n    getHtmlAttributes: function() {\n        const attributes = {};\n        this.dependencies.forEach(function(dependency) {\n            if (typeof dependency.attributes === 'object') {\n                Object.keys(dependency.attributes).forEach(function(key) {\n                    attributes[key] = dependency.attributes[key];\n                });\n            }\n        });\n        return attributes;\n    },\n\n    getLabel: function() {\n        let contentType;\n\n        if (this.isJavaScript()) {\n            contentType = contentTypes.JS;\n        } else if (this.isStyleSheet()) {\n            contentType = contentTypes.CSS;\n        } else {\n            contentType = this.getContentType();\n        }\n        return '\"' + this.getName() + '\" (' + contentType + ', ' + this.slot + (this.inlinePos ? ', inlinePos=' + this.inlinePos : '') + ')';\n    },\n\n    getKey: function() {\n        if (!this.key) {\n            this.key = Bundle.getKey(this.slot, this.contentType, this.inline, this.name);\n        }\n        return this.key;\n    },\n\n    getSlot: function() {\n        return this.slot;\n    },\n\n    setSlot: function(slot) {\n        this.slot = slot;\n    },\n\n    getContentType: function() {\n        return this.contentType;\n    },\n\n    setContentType: function(contentType) {\n        this.contentType = contentType;\n    },\n\n    hasContent: function() {\n        return (this.contentType !== contentTypes.NONE);\n    },\n\n    isJavaScript: function() {\n        return this.contentType === contentTypes.JS;\n    },\n\n    isStyleSheet: function() {\n        return this.contentType === contentTypes.CSS;\n    },\n\n    forEachDependency: function(callback, thisObj) {\n        this.dependencies.forEach(callback, thisObj);\n    },\n\n    getFingerprint: function() {\n        return this.fingerprint;\n    },\n\n    setFingerprint: function(fingerprint) {\n        this.fingerprint = fingerprint;\n    },\n\n    getCode: function() {\n        return this.code;\n    },\n\n    setCode: function(code) {\n        this.code = code;\n    },\n\n    isWritten: function() {\n        return this.written;\n    },\n\n    setWritten: function(written) {\n        this.written = written !== false;\n    },\n\n    setUrl: function(url) {\n        this.url = url;\n    },\n\n    getUrl: function() {\n        return this.url;\n    },\n\n    setConfig: function(config) {\n        this.config = config || {};\n    },\n\n    getConfig: function() {\n        return this.config;\n    },\n\n    toString: function() {\n        const details = [this.slot, this.contentType];\n        if (this.inlinePos) {\n            details.push('inlinePos=' + this.inlinePos);\n        }\n\n        return this.name + ' (' + details.join(', ') + ')';\n    }\n};\n\nmodule.exports = Bundle;\n"
  },
  {
    "path": "src/BundleConfig.js",
    "content": "const ok = require('assert').ok;\nconst DependencyList = require('./DependencyList');\n\nconst BundleConfig = function(dirname, filename) {\n    ok(dirname, '\"dirname\" is required');\n    ok(typeof dirname === 'string', '\"dirname\" is required');\n\n    this.name = null;\n    this.fingerprintsEnabled = undefined;\n    this.dependencies = [];\n    this.dirname = dirname;\n    this.filename = filename;\n    this.enabled = true;\n};\n\nBundleConfig.prototype = {\n    getRecurseInto: function() {\n        // recurseInto is set by config-loader.js\n        return this.recurseInto;\n    },\n\n    getDependencies: function(dependencyRegistry) {\n        return new DependencyList(this.dependencies, dependencyRegistry, this.dirname, this.filename);\n    },\n    addDependency: function(dependency) {\n        this.dependencies.push(dependency);\n    },\n    addDependencies: function(dependencies) {\n        dependencies.forEach(this.addDependency, this);\n    },\n    toString: function() {\n        return '[BundleConfig name=' + this.name + ', dependencies=[' + this.dependencies.toString() + ']]';\n    }\n};\n\nmodule.exports = BundleConfig;\n"
  },
  {
    "path": "src/BundleMappings.js",
    "content": "const Bundle = require('./Bundle');\nconst InlinePos = require('./InlinePos');\nconst EventEmitter = require('events').EventEmitter;\nconst ok = require('assert').ok;\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction safeRelativePath(path) {\n    return path.replace(/[^A-Za-z0-9_.\\-\\/\\\\$@]/g, '_');\n}\n\nfunction BundleMappings(config, pageName) {\n    BundleMappings.$super.call(this);\n\n    ok(pageName == null || typeof pageName === 'string', 'pageName should be a String');\n\n    this.config = config;\n    this.dependencyToBundleMapping = {};\n    this.bundlesByKey = {};\n    this.inPlaceDeploymentEnabled = config.isInPlaceDeploymentEnabled();\n    this.bundlingEnabled = config.bundlingEnabled !== false;\n    this.pageName = pageName;\n};\n\nBundleMappings.prototype = {\n    __BundleMappings: true,\n\n    setParentBundleMappings: function(parentBundleMappings) {\n        if (parentBundleMappings && !parentBundleMappings.__BundleMappings) {\n            throw new Error('Invalid parent bundle mappings');\n        }\n\n        if (parentBundleMappings === this) {\n            throw new Error('parent bundle mappings cannot be self');\n        }\n\n        // The parent bundle mappings are those defined at configuration time\n        // and we may not have actually\n        this.parentBundleMappings = parentBundleMappings;\n    },\n\n    getBundleMappingForDependency: function(dependency) {\n        const key = dependency.getKey();\n        const bundleMapping = this.dependencyToBundleMapping[key];\n        if (bundleMapping) {\n            return bundleMapping;\n        } else if (this.parentBundleMappings) {\n            return this.parentBundleMappings.getBundleMappingForDependency(dependency);\n        } else {\n            return undefined;\n        }\n    },\n\n    getBundleForDependency: function(dependency) {\n        const key = dependency.getKey();\n        const bundleMapping = this.dependencyToBundleMapping[key];\n        if (bundleMapping) {\n            return bundleMapping.bundle;\n        } else if (this.parentBundleMappings) {\n            return this.parentBundleMappings.getBundleForDependency(dependency);\n        } else {\n            return undefined;\n        }\n    },\n\n    removeBundleMapping: function(bundleMapping) {\n        const dependency = bundleMapping.dependency;\n        delete bundleMapping.bundleMappings.dependencyToBundleMapping[dependency.getKey()];\n        bundleMapping.bundle.removeDependencyByIndex(bundleMapping.index);\n    },\n\n    addDependencyToBundle: function(dependency, targetBundleName, dependencySlot, bundleConfig, lassoContext) {\n        ok(lassoContext, 'lassoContext expected');\n\n        let targetBundle;\n\n        if (dependency.isPackageDependency()) {\n            throw new Error('Illegal argument. Dependency cannot be a package dependency. Dependency: ' + dependency.toString());\n        }\n\n        let inlinePos = dependency.inline;\n\n        if (inlinePos != null) {\n            if (inlinePos === 'true' || inlinePos === true || inlinePos === 'end') {\n                inlinePos = InlinePos.END;\n            } else if (inlinePos === 'beginning') {\n                inlinePos = InlinePos.BEGINNING;\n            } else if (inlinePos === 'in-place') {\n                inlinePos = InlinePos.IN_PLACE;\n            } else if (inlinePos === 'false' || inlinePos === false) {\n                // normalize false to undefined (really no need to set inline to false since it is the default)\n                inlinePos = undefined;\n            } else {\n                throw new Error('Invalid value for \"inline\": ' + inlinePos);\n            }\n        }\n\n        const bundleKey = Bundle.getKey(dependencySlot, dependency.getContentType(), inlinePos, targetBundleName);\n\n        targetBundle = this.bundlesByKey[bundleKey];\n\n        if (!targetBundle) {\n            targetBundle = new Bundle(targetBundleName);\n            targetBundle.key = bundleKey;\n            targetBundle.setInlinePos(inlinePos);\n            targetBundle.setSlot(dependencySlot);\n            targetBundle.setContentType(dependency.getContentType());\n            targetBundle.setUrl(dependency.getUrl ? dependency.getUrl() : dependency.url);\n            if (bundleConfig) {\n                targetBundle.setConfig(bundleConfig);\n            }\n\n            this.bundlesByKey[bundleKey] = targetBundle;\n        }\n\n        const index = targetBundle.addDependency(dependency);\n\n        const bundleMapping = {\n            // store the index of the dependency within the bundle\n            index,\n\n            // store the bundle associated with the mapping\n            bundle: targetBundle,\n\n            // store the bundle mapping\n            bundleMappings: this,\n\n            // store the dependency associated with the mapping\n            dependency\n        };\n\n        this.dependencyToBundleMapping[dependency.getKey()] = bundleMapping;\n\n        dependency.emit('addedToBundle', {\n            bundle: targetBundle,\n            lassoContext\n        });\n\n        return targetBundle;\n    },\n\n    addDependencyToPageBundle: function(dependency, pageBundleName, dependencySlot, bundleConfig, lassoContext) {\n        ok(lassoContext, 'lassoContext expected');\n\n        if (dependency.isPackageDependency()) {\n            throw new Error('Illegal argument. Dependency cannot be a package dependency. Dependency: ' + dependency.toString());\n        }\n\n        let bundle;\n        const defaultBundleName = dependency.getDefaultBundleName(pageBundleName, lassoContext);\n        const flags = lassoContext.flags;\n\n        if (this.inPlaceDeploymentEnabled && dependency.isInPlaceDeploymentAllowed()) {\n            // Create a bundle with a single dependency for each dependency\n            // that allows in-place deployment\n            if (!dependency.getSourceFile) {\n                throw new Error('getSourceFile() is required when in-place deployment is allowed. Dependency: ' + dependency);\n            }\n\n            bundle = this.addDependencyToBundle(\n                dependency,\n                dependency.getSourceFile(),\n                dependencySlot,\n                bundleConfig,\n                lassoContext);\n\n            bundle.dependency = dependency;\n            bundle.inPlaceDeployment = true;\n        } else if (dependency.isExternalResource()) {\n            bundle = this.addDependencyToBundle(\n                dependency,\n                dependency.getUrl(),\n                dependencySlot,\n                bundleConfig,\n                lassoContext);\n\n            bundle.dependency = dependency;\n            bundle.isExternalResource = true;\n        } else if (this.bundlingEnabled === false) {\n            // Bundling is NOT enabled\n\n            // We will try to find a relative path that will be used for\n            // the output file of the bundle.\n            // This relative path might be different from the bundle name\n            // if a defaultBundleName is provided\n            //\n            // NOTE: If we don't have a defaultBundleName for this dependency\n            // and if we don't find a relative path then we will use\n            // `${dependencyType}-${pageBundleName}` as the\n            // bundle name.\n\n            let targetBundle;\n\n            if (dependency.getUnbundledTarget) {\n                targetBundle = dependency.getUnbundledTarget(lassoContext);\n            }\n\n            if (!targetBundle && dependency.getSourceFile) {\n                const sourceFile = dependency.getSourceFile();\n\n                if (sourceFile) {\n                    targetBundle = lassoContext.getClientPath(sourceFile);\n                }\n            }\n\n            if (targetBundle) {\n                targetBundle = safeRelativePath(targetBundle);\n\n                let prefix = pageBundleName.replace(/[\\\\\\/]/g, '-');\n\n                if (flags && !flags.isEmpty()) {\n                    prefix += '-' + flags.getKey();\n                }\n\n                if (dependency.getUnbundledTargetPrefix) {\n                    const unbundledTargetPrefix = dependency.getUnbundledTargetPrefix(lassoContext);\n                    if (unbundledTargetPrefix) {\n                        prefix += '/' + unbundledTargetPrefix;\n                    }\n                }\n\n                targetBundle = prefix + '/' + targetBundle;\n            }\n\n            let finalBundleName = defaultBundleName || targetBundle;\n            if (!finalBundleName) {\n                finalBundleName = dependency.type + '-' + pageBundleName;\n\n                if (flags && !flags.isEmpty()) {\n                    finalBundleName += '-' + flags.getKey();\n                }\n            }\n\n            bundle = this.addDependencyToBundle(\n                dependency,\n                finalBundleName,\n                dependencySlot,\n                null,\n                lassoContext);\n\n            // bundle.dependency = dependency;\n            if (targetBundle) {\n                // We associate this bundle with a relative path which will\n                // be used as the output file for the bundle\n                bundle.relativeOutputPath = targetBundle;\n            }\n        } else {\n            // Bundling is enabled\n            // Make sure the dependency is part of a bundle. If it not part of a preconfigured bundle then put it in a page-specific bundle\n            bundle = this.addDependencyToBundle(\n                dependency,\n                defaultBundleName || pageBundleName,\n                dependencySlot,\n                bundleConfig,\n                lassoContext);\n        }\n\n        return bundle;\n    },\n\n    toString: function() {\n        const lines = [];\n        for (const k in this.dependencyToBundleMapping) {\n            if (hasOwn.call(this.dependencyToBundleMapping, k)) {\n                const targetBundle = this.dependencyToBundleMapping[k].bundle;\n                lines.push(k + ' --> ' + targetBundle.toString());\n            }\n        }\n\n        return lines.join('\\n');\n    }\n};\n\nrequire('raptor-util').inherit(BundleMappings, EventEmitter);\n\nmodule.exports = BundleMappings;\n"
  },
  {
    "path": "src/BundleSetConfig.js",
    "content": "let nextId = 0;\n\nfunction BundleSetConfig(name) {\n    this._id = nextId++;\n    this.name = name;\n    this.bundleConfigs = [];\n}\n\nBundleSetConfig.prototype = {\n    addBundleConfig: function(bundleConfig) {\n        this.bundleConfigs.push(bundleConfig);\n    },\n    forEachBundleConfig: function(callback, thisObj) {\n        this.bundleConfigs.forEach(callback, thisObj);\n    }\n};\n\nmodule.exports = BundleSetConfig;\n"
  },
  {
    "path": "src/Config.js",
    "content": "const extend = require('raptor-util').extend;\nconst BundleSetConfig = require('./BundleSetConfig');\nconst flags = require('./flags');\nconst ok = require('assert').ok;\nconst lassoRequirePlugin = require('./require');\nconst lassoImagePlugin = require('./plugins/lasso-image');\nconst crypto = require('crypto');\n\nfunction createFilterFromContentType(contentType) {\n    const contentTypeMap = {};\n\n    if (Array.isArray(contentType)) {\n        // Include this array if the actual content type is in the array of supported content types\n        const contentTypeArray = contentType;\n        if (contentTypeArray.length === 0) {\n            return async function (lassoContext) {\n                return true;\n            };\n        }\n\n        for (let i = 0, len = contentTypeArray.length; i < len; i++) {\n            contentTypeMap[contentTypeArray[i]] = true;\n        }\n    } else {\n        contentTypeMap[contentType] = true;\n    }\n\n    return async function(lassoContext) {\n        const contentType = lassoContext.contentType;\n        return contentTypeMap[contentType] === true;\n    };\n}\n\nconst MAX_FINGERPRINT_DEPTH = 4;\n\nfunction calculateConfigFingerprint(config) {\n    // Instead of trying to be clever we we just going to hard code\n    // handling of each support configuration for now...\n    const hash = crypto.createHash('sha1');\n\n    function hashObject(o, depth) {\n        if (depth > MAX_FINGERPRINT_DEPTH) {\n            return;\n        }\n\n        const keys = Object.keys(o);\n        keys.sort();\n\n        for (let i = 0; i < keys.length; i++) {\n            const k = keys[i];\n            const v = o[k];\n            update(k, depth + 1);\n            update(v, depth + 1);\n        }\n    }\n\n    function hashArray(o, depth) {\n        if (depth > MAX_FINGERPRINT_DEPTH) {\n            return;\n        }\n\n        const len = o.length;\n\n        for (let i = 0; i < len; i++) {\n            update(o[i], depth + 1);\n        }\n    }\n\n    function update(value, depth) {\n        if (depth === undefined) {\n            depth = 0;\n        }\n\n        if (depth > 0 && typeof v === 'function') {\n            return;\n        }\n\n        if (value == null) {\n            hash.update('');\n            return;\n        }\n\n        if (Array.isArray(value)) {\n            hashArray(value, depth);\n        } else if (typeof value === 'object') {\n            hashObject(value, depth);\n        } else {\n            hash.update(value.toString());\n        }\n    }\n\n    update(config.rawConfig);\n\n    return hash.digest('hex');\n}\n\nfunction Config(params) {\n    this.configResource = null;\n\n    this.bundlingEnabled = true;\n\n    this.projectRoot = null;\n\n    this.flags = flags.createFlagSet();\n    this.params = {};\n    this.bundleSetConfigsByName = {};\n    this.fileWriterConfig = null;\n    this.transforms = [];\n    this.bundlingEnabled = true;\n    this.basePath = null;\n    this.writer = null;\n    this.includeSlotNameForBundles = false;\n    this._plugins = [];\n    this.cacheProfiles = null;\n    this.cacheProfile = null;\n    this.cacheDir = null;\n    this._requirePluginConfig = {};\n    this._minifyJSPluginConfig = {};\n    this._minifyCSSPluginConfig = {};\n    this._imagePluginConfig = {};\n    this.cspNonceProvider = null;\n    this.fingerprintInlineCode = null;\n    this.cacheKey = null; // The unique key to uniquely identify this lasso for caching purposes\n    this.resolver = null;\n    this.loadPrebuild = false; // Whether Lasso should load from a prebuild configuration or not\n\n    if (params) {\n        extend(this.params, params);\n    }\n\n    this.addDefaultPlugins();\n\n    this._configFingerprint = null;\n}\n\nConfig.prototype = {\n    __Config: true,\n\n    get outputDir() {\n        return this.fileWriterConfig && this.fileWriterConfig.outputDir;\n    },\n\n    get urlPrefix() {\n        return this.fileWriterConfig && this.fileWriterConfig.urlPrefix;\n    },\n\n    /**\n     * The goal of this method is to return a String that uniquely identifies\n     * this configuration. This is needed for caching purposes in that we want\n     * to discard cached items if the configuration changes. For example, if\n     * a new transform is added then the previously cached transformed items\n     * should not be used.\n     */\n    getConfigFingerprint: function() {\n        if (!this._configFingerprint) {\n            this._configFingerprint = calculateConfigFingerprint(this);\n        }\n\n        return this._configFingerprint;\n    },\n\n    addDefaultPlugins: function() {\n        this.addPlugin(lassoRequirePlugin, this._requirePluginConfig);\n        this.addPlugin(lassoImagePlugin, this._imagePluginConfig);\n    },\n\n    getPlugins: function(pluginInfo) {\n        return this._plugins;\n    },\n\n    addPlugin: function(func, config) {\n        // Don't add if this is a duplicate plugin\n        for (let i = 0; i < this._plugins.length; i++) {\n            const curPlugin = this._plugins[i];\n            if (curPlugin.func === func && curPlugin.config === config) {\n                return;\n            }\n        }\n\n        ok(typeof func === 'function', 'Plugin should be a function. Actual: ' + func);\n        this._plugins.push({\n            func,\n            config: config || {}\n        });\n    },\n\n    addTransform: function(transform) {\n        if (!transform) {\n            throw new Error('transform is required');\n        }\n\n        if (transform.enabled === false) {\n            // Don't add transforms that are disabled\n            return;\n        }\n\n        if (typeof transform === 'function') {\n            transform = {\n                transform\n            };\n        }\n\n        if (typeof transform.transform !== 'function') {\n            throw new Error('Invalid transform: ' + require('util').inspect(transform));\n        }\n\n        transform.name = transform.name || transform.transform.name || '(anonymous)'; // Use the function name\n\n        if (transform.contentType) {\n            // Convert the contentType to a filter\n            transform = extend({}, transform);\n            transform.filter = createFilterFromContentType(transform.contentType);\n            delete transform.contentType;\n        }\n\n        this.transforms.push(transform);\n    },\n\n    getResolver () {\n        return this.resolver;\n    },\n\n    getTransforms: function() {\n        return this.transforms;\n    },\n\n    isInPlaceDeploymentEnabled: function() {\n        return this.inPlaceDeploymentEnabled === true;\n    },\n\n    isBundlingEnabled: function() {\n        return this.bundlingEnabled;\n    },\n\n    addBundleSetConfig: function(bundleSetConfig) {\n        if (!bundleSetConfig.name) {\n            bundleSetConfig.name = 'default';\n        }\n\n        if (this.bundleSetConfigsByName[bundleSetConfig.name]) {\n            throw new Error('Bundles with name \"' + bundleSetConfig.name + '\" defined multiple times');\n        }\n\n        this.bundleSetConfigsByName[bundleSetConfig.name] = bundleSetConfig;\n\n        return bundleSetConfig;\n    },\n\n    getBundleSetConfig: function(name) {\n        return this.bundleSetConfigsByName[name];\n    },\n\n    enableFlag: function(name) {\n        this.flags.add(name);\n    },\n\n    /**\n     * @deprecated\n     */\n    enableExtension: function(name) {\n        this.flags.add(name);\n    },\n\n    getFlags: function() {\n        return this.flags;\n    },\n\n    setFlags: function(newFlags) {\n        this.flags = flags.createFlagSet(newFlags);\n    },\n\n    getPageBundleSetConfig: function(pageName) {\n        let bundleSetConfig = this.getBundleSetConfig('default');\n\n        if (!bundleSetConfig) {\n            bundleSetConfig = this.addBundleSetConfig(new BundleSetConfig('default'));\n        }\n\n        return bundleSetConfig;\n    },\n\n    setInPlaceDeploymentEnabled: function(inPlaceDeploymentEnabled) {\n        this.inPlaceDeploymentEnabled = inPlaceDeploymentEnabled;\n    },\n\n    setInPlaceUrlPrefix: function(inPlaceUrlPrefix) {\n        this.inPlaceUrlPrefix = inPlaceUrlPrefix;\n    },\n\n    getInPlaceUrlPrefix: function() {\n        return this.inPlaceUrlPrefix;\n    },\n\n    getBasePath: function() {\n        return this.basePath;\n    },\n\n    setBasePath: function(basePath) {\n        this.basePath = basePath;\n    },\n\n    getWriter: function() {\n        return this.writer;\n    },\n\n    setResolver (resolver) {\n        this.resolver = resolver;\n    },\n\n    setWriter: function(writer) {\n        this.writer = writer;\n    },\n\n    getProjectRoot: function() {\n        return this.projectRoot;\n    },\n\n    setProjectRoot: function(projectRoot) {\n        if (projectRoot != null) {\n            const len = projectRoot.length;\n            // chop off trailing slash so that our path operations are consistent\n            if (projectRoot.charAt(len - 1) === '/' || projectRoot.charAt(len - 1) === '\\\\') {\n                projectRoot = projectRoot.substring(0, len - 1);\n            }\n        }\n        this.projectRoot = projectRoot;\n    },\n\n    setBundlingEnabled: function(bundlingEnabled) {\n        this.bundlingEnabled = bundlingEnabled;\n    },\n\n    setBundlingStrategy: function(bundlingStrategy) {\n        this.bundlingStrategy = bundlingStrategy;\n    },\n\n    getBundlingStrategy: function() {\n        return this.bundlingStrategy;\n    },\n\n    setCacheProfiles: function(cacheProfiles) {\n        this.cacheProfiles = cacheProfiles;\n    },\n\n    getCacheProfiles: function() {\n        return this.cacheProfiles;\n    },\n\n    setCacheProfile: function(cacheProfile) {\n        this.cacheProfile = cacheProfile;\n    },\n\n    getCacheProfile: function() {\n        return this.cacheProfile;\n    },\n\n    setCacheDir: function(cacheDir) {\n        this.cacheDir = cacheDir;\n    },\n\n    getCacheDir: function() {\n        return this.cacheDir;\n    },\n\n    toString: function() {\n        return '[' + __filename + ']'; // eslint-disable-line no-path-concat\n    },\n\n    setBundleReadTimeout: function(timeout) {\n        this.bundleReadTimeout = timeout;\n    },\n\n    getBundleReadTimeout: function() {\n        return this.bundleReadTimeout;\n    },\n\n    setCSPNonceProvider: function(func) {\n        this.cspNonceProvider = func;\n    },\n\n    setFingerprintInlineCode: function(func) {\n        this.fingerprintInlineCode = func;\n    },\n\n    setCacheKey (value) {\n        this.cacheKey = value;\n    },\n\n    /**\n    * Whether Lasso should load from a prebuild configuration or not\n    */\n    setLoadPrebuild (value) {\n        this.loadPrebuild = value;\n    },\n\n    getLoadPrebuild () {\n        return this.loadPrebuild;\n    }\n};\n\nmodule.exports = Config;\n"
  },
  {
    "path": "src/DependencyList.js",
    "content": "const dependenciesModule = require('./dependencies');\nconst ok = require('assert').ok;\n\nfunction DependencyList(dependencies, dependencyRegistry, dirname, filename) {\n    ok(dirname && typeof dirname === 'string', '\"dirname\" argument should be a string');\n    ok(!filename || typeof filename === 'string', '\"filename\" argument should be a string');\n    ok(dependencyRegistry && dependenciesModule.isRegistry(dependencyRegistry), 'dependencyRegistry argument is not valid');\n\n    if (dependencies) {\n        if (dependencies.__DependencyList) {\n            dependencies = dependencies._dependencies;\n        } else if (!Array.isArray(dependencies)) {\n            throw new Error('Invalid dependencies: ' + dependencies);\n        }\n    }\n\n    this._dependencyRegistry = dependencyRegistry;\n    this._dependencies = dependencies || [];\n    this._normalized = null;\n\n    this._dirname = dirname;\n    this._filename = filename;\n}\n\nDependencyList.prototype = {\n    __DependencyList: true,\n\n    addDependency: function(config) {\n        if (this._converted) {\n            config = this.dependencyRegistry.createDependency(config, this._dirname, this._filename);\n        }\n\n        this._dependencies.push(config);\n    },\n\n    async normalize () {\n        if (!this._normalized) {\n            this._normalized = await this._dependencyRegistry.normalizeDependencies(\n                this._dependencies,\n                this._dirname,\n                this._filename);\n        }\n        return this._normalized;\n    },\n\n    toString: function() {\n        return '[DependencyList: ' + this._dependencies.join(',') + ']';\n    },\n\n    inspect() {\n        return this._dependencies;\n    }\n};\n\nDependencyList.prototype.push = DependencyList.prototype.addDependency;\n\nDependencyList.isDependencyList = function(o) {\n    return o && o.__DependencyList;\n};\n\nmodule.exports = DependencyList;\n"
  },
  {
    "path": "src/DependencyTree.js",
    "content": "const hasOwn = Object.prototype.hasOwnProperty;\n\nfunction Node(dependency, parent) {\n    this.dependency = dependency;\n    this.children = [];\n    this.parent = parent;\n}\n\nfunction DependencyTree() {\n    this._root = new Node();\n    this._root.isRoot = true;\n    this._nodes = {};\n    this._bundleTrees = {};\n}\n\nDependencyTree.prototype = {\n    add: function(dependency, parentDependency) {\n        const parentNode = parentDependency\n            ? this._nodes[parentDependency.getKey()]\n            : this._root;\n\n        if (!parentNode) {\n            throw new Error('parentNode node not found: ' + parentDependency.getKey());\n        }\n\n        const node = new Node(dependency, parentNode);\n\n        parentNode.children.push(node);\n        this._nodes[dependency.getKey()] = node;\n    },\n\n    addToBundle: function(bundle, dependency, parentDependency) {\n        let bundleTree = this._bundleTrees[bundle.getKey()];\n        if (!bundleTree) {\n            bundleTree = this._bundleTrees[bundle.getKey()] = new DependencyTree();\n            bundleTree.bundle = bundle;\n        }\n\n        const parentNode = parentDependency\n            ? this._nodes[parentDependency.getKey()]\n            : this._root;\n\n        function copyNodes(node) {\n            if (node.isRoot || bundleTree._nodes[node.dependency.getKey()]) {\n                return;\n            }\n\n            if (node.parent) {\n                copyNodes(node.parent);\n            }\n\n            bundleTree.add(node.dependency, node.parent ? node.parent.dependency : null);\n        };\n\n        copyNodes(parentNode);\n\n        bundleTree.add(dependency, parentDependency);\n    },\n\n    bundlesToString: function() {\n        const lines = [];\n\n        for (const k in this._bundleTrees) {\n            if (hasOwn.call(this._bundleTrees, k)) {\n                const bundleTree = this._bundleTrees[k];\n                lines.push('Bundle ' + bundleTree.bundle.toString() + ':');\n                lines.push(bundleTree.toString());\n            }\n        }\n\n        return lines.join('\\n');\n    },\n\n    toString: function(indent) {\n        const lines = [];\n\n        function toStringHelper(node, indent) {\n            for (let i = 0, len = node.children.length; i < len; i++) {\n                const child = node.children[i];\n                let line = indent;\n                if (!child.dependency.isPackageDependency()) {\n                    line += '+ ';\n                }\n                line += child.dependency.toString();\n\n                lines.push(line);\n\n                toStringHelper(child, indent + '  ');\n            }\n        }\n\n        toStringHelper(this._root, indent || '');\n\n        return lines.join('\\n');\n    }\n};\n\nmodule.exports = DependencyTree;\n"
  },
  {
    "path": "src/FlagSet.js",
    "content": "/*\n * Copyright 2011 eBay Software Foundation\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *    http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * The FlagSet class is used to maintain a set\n * of flags and provides methods for adding\n * extension names and checking if an extension\n * is an enabled. It also exposes a <code>getKey()</code>\n * method that can be used to return a String\n * key that uniquely identifies the set of\n * enabled flags.\n */\nconst forEachEntry = require('raptor-util').forEachEntry;\nconst raptorRegexp = require('raptor-regexp');\n\nfunction FlagSet(flags) {\n    this.flagMap = {};\n    this.flagList = [];\n    this.key = null;\n\n    if (flags) {\n        this.addAll(flags);\n    }\n}\n\nFlagSet.prototype = {\n    __FlagSet: true,\n\n    isEmpty: function() {\n        return this.flagList.length === 0;\n    },\n\n    /**\n     *\n     * @param ext\n     */\n    add: function(ext) {\n        if (Array.isArray(ext)) {\n            this.addAll(ext);\n            return;\n        }\n\n        this.flagMap[ext] = true; // Add the extension to a map for quick lookup\n        this.flagList.push(ext); // Maintain an array of flags\n        this.key = null; // Clear out the key so that it is regenerated since the collection changed\n    },\n\n    remove: function(ext) {\n        if (this.flagMap[ext]) {\n            delete this.flagMap[ext];\n            this.flagList = Object.keys(this.flagMap);\n            this.key = null; // Clear the key since the collection changed\n        }\n    },\n\n    /**\n     * Adds one or more flags to the collection. This method\n     * supports an array of extension names, as well as an\n     * object map with extension names as property names.\n     *\n     * @param flags {Array|Object|packaging.FlagSet}\n     */\n    addAll: function(flags) {\n        if (!flags) {\n            return;\n        }\n\n        if (flags instanceof FlagSet) {\n            flags = flags.flagList;\n        }\n\n        if (Array.isArray(flags)) {\n            flags.forEach(function(ext) {\n                this.add(ext);\n            }, this);\n        } else if (typeof flags === 'object') {\n            forEachEntry(flags, function(ext) {\n                this.add(ext);\n            }, this);\n        }\n    },\n\n    /**\n     * Returns a string that can be used to uniquely\n     * identify a set of flags. If two\n     * FlagSet instances contain the same set\n     * of flags then the same key will be returned.\n     * @returns\n     */\n    getKey: function() {\n        if (this.key == null) {\n            this.flagList.sort();\n            this.key = this.flagList.join('-');\n        }\n\n        return this.key;\n    },\n\n    /**\n     *\n     * @param ext\n     * @returns {Boolean}\n     */\n    contains: function(ext) {\n        return this.flagMap[ext] === true;\n    },\n\n    /**\n     *\n     * @param ext\n     * @returns {Boolean}\n     */\n    containsMatch: function(ext) {\n        let regExp;\n\n        if (ext instanceof RegExp) {\n            regExp = ext;\n        } else if (ext === '*') {\n            return this.flagList.length !== 0;\n        } else {\n            regExp = raptorRegexp.simple(ext);\n        }\n\n        const flags = this.flagList;\n        for (let i = 0, len = flags.length; i < len; i++) {\n            if (regExp.test(flags[i])) {\n                return true;\n            }\n        }\n\n        return false;\n    },\n\n    getAll: function() {\n        return this.flagList;\n    },\n\n    toString: function() {\n        return this.getKey();\n    }\n};\n\nmodule.exports = FlagSet;\n"
  },
  {
    "path": "src/InlinePos.js",
    "content": "module.exports = require('raptor-util').makeEnum([\n    'IN_PLACE',\n    'BEGINNING',\n    'END'\n]);\n"
  },
  {
    "path": "src/Lasso.js",
    "content": "const assert = require('assert');\nconst nodePath = require('path');\nconst LassoCache = require('./LassoCache');\nconst LassoPageResult = require('./LassoPageResult');\nconst LassoContext = require('./LassoContext');\nconst SlotTracker = require('./SlotTracker');\nconst logger = require('raptor-logging').logger(module);\nconst EventEmitter = require('events').EventEmitter;\nconst mime = require('mime');\nconst raptorUtil = require('raptor-util');\nconst pageBundlesBuilder = require('./page-bundles-builder');\nconst BundleMappings = require('./BundleMappings');\nconst manifestLoader = require('./manifest-loader');\nconst LassoManifest = require('./LassoManifest');\nconst flags = require('./flags');\nconst dependencies = require('./dependencies');\nconst fs = require('fs');\nconst commaSeparatedRegExp = /\\s*,\\s*/;\nconst ok = require('assert').ok;\nconst bundleBuilder = require('./bundle-builder');\nconst isAbsolute = require('./path').isAbsolute;\nconst createWriter = require('./writers').createWriter;\nconst perfLogger = require('raptor-logging').logger('lasso/perf');\nconst extend = require('raptor-util/extend');\nconst cachingFs = require('./caching-fs');\nconst createError = require('raptor-util/createError');\nconst resolveFrom = require('resolve-from');\nconst LassoPrebuildResult = require('./LassoPrebuildResult');\nconst { buildPrebuildName, buildPrebuildFileName } = require('./util/prebuild.js');\nconst hashUtil = require('./util/hash');\n\n/**\n* Cache of prebuilds by path. If there are multiple slots for the same\n* path, we do not need to load the prebuild more than once.\n*/\nconst prebuildToPath = {};\n\nconst urlRegExp = /^[^:\\/]{0,5}[:]?\\/\\//;\n\nconst resourceHandlersByType = {\n    string: {\n        resource: doLassoResourceString,\n        calculateKey (data, theLasso, lassoContext, options) {\n            if (!isAbsolute(data)) {\n                data += lassoContext.dir;\n            }\n\n            return _buildResourceCacheKey(data, theLasso, lassoContext);\n        }\n    },\n    object: {\n        resource: doLassoResourceBuffer,\n        hashPath: true,\n        calculateKey (data, theLasso, lassoContext, options) {\n            let hash = hashUtil.generate(\n                data.toString(), hashUtil.HASH_OVERFLOW_LENGTH);\n\n            let name;\n            let ext;\n\n            if ((name = options.name)) {\n                hash = `${name}-${hash}`;\n            }\n\n            if ((ext = options.extension)) {\n                hash += `.${ext}`;\n            }\n\n            return hash;\n        }\n    }\n};\n\nfunction isExternalUrl(path) {\n    return urlRegExp.test(path);\n}\n\nasync function getLassoManifestFromOptions (options, dependencyRegistry) {\n    let lassoManifest;\n    const from = options.from;\n    let fromFilename;\n    let fromDirname;\n\n    if (from) {\n        if (typeof from === 'object') {\n            if (!from.filename) {\n                throw new Error('Invalid \"from\" object.');\n            }\n            fromFilename = from.filename;\n            fromDirname = nodePath.dirname(fromFilename);\n        } else if (typeof from === 'string') {\n            const stat = cachingFs.statSync(from);\n            if (!stat.exists()) {\n                throw new Error('No directory exists at given \"from\" path (\"' + from + '\")');\n            }\n\n            if (stat.isDirectory()) {\n                fromDirname = from;\n            } else {\n                fromFilename = from;\n                fromDirname = nodePath.dirname(from);\n            }\n        }\n    }\n\n    let lassoManifestOptions;\n\n    if (options.packagePath) {\n        const packagePath = options.packagePath;\n\n        if (typeof packagePath !== 'string') {\n            throw new Error('\"packagePath\" option should be a string');\n        }\n\n        if (!fromDirname) {\n            fromDirname = nodePath.dirname(packagePath);\n        }\n\n        lassoManifest = manifestLoader.load(packagePath, fromDirname);\n        if (lassoManifest) {\n            lassoManifestOptions = {\n                manifest: lassoManifest,\n                dependencyRegistry,\n                dirname: lassoManifest.dirname,\n                filename: lassoManifest.filename\n            };\n        }\n    } else if (options.dependencies) {\n        let dependencies = options.dependencies;\n\n        if (!fromDirname) {\n            fromDirname = process.cwd();\n        }\n\n        if (typeof dependencies === 'function') {\n            const resolvedDependencies = await dependencies();\n            return new LassoManifest({\n                manifest: {\n                    dependencies: resolvedDependencies\n                },\n                dependencyRegistry,\n                dirname: fromDirname,\n                filename: fromFilename\n            });\n        } else if (!Array.isArray(dependencies)) {\n            dependencies = [dependencies];\n        }\n\n        lassoManifestOptions = {\n            manifest: {\n                dependencies\n            },\n            dependencyRegistry,\n            dirname: fromDirname,\n            filename: fromFilename\n        };\n    } else if (options.lassoManifest) {\n        lassoManifestOptions = {\n            manifest: options.lassoManifest,\n            dependencyRegistry,\n            dirname: options.lassoManifest.dirname || process.cwd(),\n            filename: options.lassoManifest.filename\n        };\n    } else if (options.packagePaths) {\n        lassoManifestOptions = {\n            manifest: {\n                dependencies: options.packagePaths\n            },\n            dependencyRegistry,\n            dirname: process.cwd(),\n            filename: undefined\n        };\n    }\n\n    if (lassoManifestOptions) {\n        return new LassoManifest(lassoManifestOptions);\n    } else {\n        return null;\n    }\n}\n\nasync function doLassoPage (theLasso, options, lassoContext) {\n    const logInfoEnabled = logger.isInfoEnabled();\n    const perfLogInfoEnabled = perfLogger.isInfoEnabled();\n\n    const startTime = Date.now();\n\n    // if we create a new context then make sure we put it\n    // back into the options object for reference later\n    const pageName = lassoContext.pageName = options.pageName || options.name;\n\n    lassoContext.pageName = pageName;\n\n    const config = theLasso.config;\n\n    const lassoManifest = await getLassoManifestFromOptions(options, theLasso.dependencies);\n\n    if (!lassoManifest) {\n        throw new Error('Invalid options. \"dependencies\", \"packagePath\" or \"lassoManifest\" expected. Options: ' + require('util').inspect(options));\n    }\n\n    logger.debug('getLassoManifestFromOptions()');\n\n    options.lassoManifest = lassoManifest;\n\n    const pluginContext = {\n        context: lassoContext,\n        config,\n        options,\n        lasso: theLasso\n    };\n\n    // TODO: Deprecate this\n    theLasso.emit('beforeOptimizePage', pluginContext);\n    theLasso.emit('beforeLassoPage', pluginContext);\n    theLasso.emit('beforeBuildPage', pluginContext);\n\n    const lassoPageResult = new LassoPageResult();\n    const slotTracker = new SlotTracker();\n\n    lassoContext.lassoPageResult = lassoPageResult;\n\n    const writer = lassoContext.writer;\n\n    // Inline code fingerprinting is useful for building a Single Page App\n    // that is using a Content Security Policy (CSP) that prevents\n    // untrusted script blocks. By keeping track of inline code\n    // fingerprints, a build tool could provide these as part of the CSP\n    // so that inline code blocks created at build time will be trusted.\n    const fingerprintInlineCode = config.fingerprintInlineCode;\n    let inlineCodeFingerprints;\n\n    if (fingerprintInlineCode) {\n        inlineCodeFingerprints = [];\n    }\n\n    function onBundleWritten (bundle) {\n        if (logInfoEnabled) {\n            logger.info('Bundle ' + bundle + ' written.');\n        }\n        lassoPageResult.registerBundle(bundle, false, lassoContext);\n    }\n\n    function onAsyncBundleWritten (bundle) {\n        if (logInfoEnabled) {\n            logger.info('Bundle ' + bundle + ' (async) written.');\n        }\n        lassoPageResult.registerBundle(bundle, true, lassoContext);\n    }\n\n    function buildHtmlSlots (pageBundles) {\n        pageBundles.forEachBundle(function (bundle) {\n            let attrs,\n                url;\n\n            const bundleAttrs = bundle.getHtmlAttributes();\n\n            if (bundle.isInline()) {\n                if (fingerprintInlineCode) {\n                    const fingerprint = config.fingerprintInlineCode(bundle.getCode());\n                    if (fingerprint) {\n                        inlineCodeFingerprints.push(fingerprint);\n                    }\n                }\n\n                slotTracker.addInlineCode(\n                    bundle.getSlot(),\n                    bundle.getContentType(),\n                    bundle.getCode(),\n                    bundle.getInlinePos(),\n                    bundle.isMergeInline());\n            } else {\n                url = bundle.getUrl(lassoContext);\n\n                if (bundle.isJavaScript()) {\n                    attrs = Object.assign({ src: url }, bundleAttrs);\n                } else if (bundle.isStyleSheet()) {\n                    attrs = Object.assign({ href: url }, bundleAttrs);\n                } else if (!bundle.hasContent()) {\n                    // ignore this bundle because contentType is \"none\"\n                    return;\n                } else {\n                    throw new Error('Invalid bundle content type: ' + bundle.getContentType());\n                }\n                slotTracker.addContent(bundle.getSlot(), bundle.getContentType(), attrs);\n            }\n        });\n\n        lassoPageResult.setSlotsByName(slotTracker.getSlotsByName());\n        lassoPageResult.setInlineCodeFingerprints(inlineCodeFingerprints);\n    }\n\n    let pageBundles;\n\n    let prevStartTime = startTime;\n\n    async function buildPageBundles () {\n        logger.debug('buildPageBundles BEGIN');\n        pageBundles = await theLasso.buildPageBundles(options, lassoContext);\n    }\n\n    async function writeAsyncBundles () {\n        if (perfLogInfoEnabled) {\n            perfLogger.info('Page bundles built in ' + (Date.now() - prevStartTime) + 'ms');\n        }\n\n        prevStartTime = Date.now();\n\n        lassoContext.setPhase('write-async-page-bundles');\n\n        // First write out all of the async bundles\n        await writer.writeBundles(\n            pageBundles.forEachAsyncBundleIter(),\n            onAsyncBundleWritten,\n            lassoContext);\n    }\n\n    async function writeSyncBundles () {\n        if (perfLogInfoEnabled) {\n            perfLogger.info('Async page bundles written in ' + (Date.now() - prevStartTime) + 'ms');\n        }\n\n        prevStartTime = Date.now();\n\n        lassoContext.setPhase('write-page-bundles');\n\n        // Now write out all of the non-async bundles\n        await writer.writeBundles(\n            pageBundles.forEachBundleIter(),\n            onBundleWritten,\n            lassoContext);\n    }\n\n    await buildPageBundles();\n    await writeAsyncBundles();\n    await writeSyncBundles();\n\n    if (perfLogInfoEnabled) {\n        perfLogger.info('Page bundles written in ' + (Date.now() - prevStartTime) + 'ms');\n    }\n\n    // All of the bundles have now been persisted, now we can\n    // generate all of the HTML for the page\n    buildHtmlSlots(pageBundles);\n\n    perfLogger.info('Built page \"' + pageName + '\" in ' + (Date.now() - startTime) + 'ms');\n\n    if (lassoContext.cache) {\n        try {\n            await lassoContext.cache.flushAll();\n        } catch (err) {\n            // The directory may have been manually purged. Do not throw an error\n            // if one is missing.\n            if (err.code !== 'ENOENT') throw err;\n        }\n    }\n\n    return lassoPageResult;\n}\n\nfunction resolvePath(path, from) {\n    const firstChar = path.charAt(0);\n    if (firstChar === '.') {\n        // path is relative to dependency directory\n        return nodePath.resolve(from, path);\n    } else if (isAbsolute(path)) {\n        // path is absolute\n        return path;\n    } else {\n        // path should be resolved using require.resolve() convention first\n        // and attempt relative path resolution if that fails\n        try {\n            return resolveFrom(from, path);\n        } catch (e) {\n            // Not bothering to check error code since serverResolveRequire\n            // should only throw error for one reason which is \"module not found\".\n            // if (e.code === 'MODULE_NOT_FOUND') {\n            //\n            // }\n            const resolvedPath = nodePath.resolve(from, path);\n\n            // Since the path looked like it was for a module we should check\n            // to see if the fallback technique actually found a file. If file\n            // does not exist for fallback path, then we'll report an error\n            // that the module does not exist by re-throwing the original error.\n            if (cachingFs.existsSync(resolvedPath)) {\n                // Fallback technique found the path.\n                // We might want to log something here to suggest that relative\n                // paths be prefixed with \".\" to avoid the extra work of trying to\n                // resolve path using NodeJS module search path.\n            } else {\n                // Path is not a module or resolved path.\n                // Since the path did not start with a \".\" let's\n                // throw the error that we caught when trying to\n                // resolve as module\n                throw new Error('Failed to resolve path \"' + path + '\". Target file does not exist. Started search from directory \"' + from + '\".');\n            }\n\n            // We were able to r\n            return resolvedPath;\n        }\n    }\n}\n\nasync function doLassoResourceString (theLasso, path, cacheKey, options, lassoContext) {\n    const inputPath = path;\n\n    function done (err, result) {\n        if (err) {\n            throw createError('Error while resolving resource URL for path \"' + path + '\". Error: ' + err, err);\n        }\n\n        const url = result.url;\n\n        if (logger.isDebugEnabled()) {\n            logger.debug('Resolved URL: ', inputPath, ' --> ', url);\n        }\n\n        return result;\n    }\n\n    if (isExternalUrl(path)) {\n        return done(null, { url: path });\n    } else {\n        const writer = theLasso.writer;\n\n        const hashStart = path.indexOf('#');\n\n        if (hashStart !== -1) {\n            path = path.substring(0, hashStart);\n        }\n\n        let queryString = '';\n        const queryStart = path.indexOf('?');\n\n        if (queryStart !== -1) {\n            queryString = path.substring(queryStart);\n            path = path.substring(0, queryStart);\n        }\n\n        if (!isAbsolute(path)) {\n            let dir = lassoContext.dir;\n\n            if (!dir) {\n                if (lassoContext.dependency) {\n                    dir = lassoContext.dependency.getDir(lassoContext);\n                }\n\n                if (!dir) {\n                    dir = lassoContext.getProjectRoot();\n                }\n            }\n\n            path = resolvePath(path, dir);\n        }\n\n        if (!cachingFs.existsSync(path)) {\n            throw new Error('File with path \"' + path + '\" does not exist');\n        }\n\n        let dataURIEncoding;\n        let base64Requested = false;\n\n        if (queryString === '?base64') {\n            base64Requested = true;\n\n            if (writer.base64EncodeSupported !== true) {\n                dataURIEncoding = 'base64';\n            }\n        } else if (queryString === '?utf8') {\n            dataURIEncoding = 'utf8';\n        }\n\n        if (dataURIEncoding) {\n            try {\n                const fileData = await fs.promises.readFile(path);\n                const dataUrl = 'data:' + mime.getType(path) + ';' + dataURIEncoding + ',' + fileData.toString(dataURIEncoding);\n\n                return done(null, {\n                    url: dataUrl\n                });\n            } catch (err) {\n                return done(err);\n            }\n        } else {\n            // Record that base 64 encoding was requested for this resource (this might be helpful to the writer)\n            if (base64Requested) {\n                lassoContext = Object.create(lassoContext);\n                lassoContext.base64EncodeUrl = true;\n            }\n\n            const writeResult = await writer.writeResource(path, lassoContext);\n            return done(null, writeResult);\n        }\n    }\n}\n\nasync function doLassoResourceBuffer (theLasso, buff, cacheKey, options, lassoContext) {\n    const writer = theLasso.writer;\n\n    try {\n        const result = writer.writeResourceBuffer(buff, cacheKey, lassoContext);\n        const url = result.url;\n\n        if (logger.isDebugEnabled()) {\n            logger.debug('Resolved URL for buffered resource: ', url);\n        }\n\n        return result;\n    } catch (err) {\n        throw createError('Error while resolving buffered resource URL', err);\n    }\n}\n\nfunction _buildResourceCacheKey (cacheKey, theLasso, lassoContext) {\n    const writer = theLasso.writer;\n    const buildResourceCacheKey = writer.buildResourceCacheKey;\n\n    if (buildResourceCacheKey) {\n        cacheKey = buildResourceCacheKey.call(writer, cacheKey, lassoContext);\n    }\n\n    return cacheKey;\n}\n\nfunction Lasso(config) {\n    ok(config, 'config is required');\n\n    Lasso.$super.call(this);\n\n    this.config = config;\n\n    // LassoCache instances cache information associated with a specific\n    this.lassoCacheLookup = {};\n\n    this.dependencies = dependencies.createRegistry();\n\n    this.initPlugins();\n\n    let writer = this.writer;\n    if (!writer) {\n        if (!config.writer) {\n            throw new Error('Writer not configured for page lasso config');\n        }\n\n        writer = createWriter(config.writer);\n\n        writer.lasso = this;\n        writer.config = this.config;\n    }\n\n    this.writer = writer;\n\n    this.emit('lassoConfigured', {\n        config: this.config,\n        lasso: this\n    });\n}\n\nLasso.prototype = {\n\n    initPlugins: function() {\n        const plugins = this.config.getPlugins();\n        for (let i = 0; i < plugins.length; i++) {\n            const plugin = plugins[i];\n            plugin.func(this, plugin.config || {});\n        }\n    },\n\n    async createAppBundleMappings (bundleSetConfig, lassoContext) {\n        ok(bundleSetConfig, '\"bundleSetConfig\" is required');\n\n        const dependencyRegistry = this.dependencies;\n        ok(dependencyRegistry, '\"this.dependencies\" is required');\n\n        logger.debug('createAppBundleMappings() begin');\n\n        const bundleMappings = new BundleMappings(this.config);\n\n        for (const bundleConfig of bundleSetConfig.bundleConfigs) {\n            const bundleName = bundleConfig.name;\n\n            ok(bundleName, 'Illegal state. Bundle name is required');\n\n            await bundleBuilder.buildBundle(\n                bundleMappings,\n                dependencyRegistry,\n                bundleConfig,\n                lassoContext);\n        }\n\n        logger.debug('createAppBundleMappings() *DONE*');\n        return bundleMappings;\n    },\n\n    async buildPageBundles (options, lassoContext) {\n        const pageName = options.pageName;\n        const config = this.getConfig();\n        const bundleSetConfig = config.getPageBundleSetConfig(pageName);\n        const startTime = Date.now();\n\n        logger.debug('buildPageBundles() BEGIN');\n\n        async function buildPageBundleMappings(appBundleMappings) {\n            logger.debug('buildPageBundles() - buildPageBundleMappings() BEGIN');\n\n            const bundleMappings = new BundleMappings(config, lassoContext.pageName);\n\n            if (appBundleMappings) {\n                bundleMappings.setParentBundleMappings(appBundleMappings);\n            }\n\n            if (perfLogger.isInfoEnabled()) {\n                perfLogger.info('Bundle mappings built in ' + (Date.now() - startTime) + 'ms');\n            }\n\n            return pageBundlesBuilder.build(options, config, bundleMappings, lassoContext);\n        }\n\n        if (config.isBundlingEnabled()) {\n            logger.debug('buildPageBundles() - getAppBundleMappingsCached()');\n            const cachedAppBundleMappings = await this.getAppBundleMappingsCached(bundleSetConfig, lassoContext);\n            return buildPageBundleMappings(cachedAppBundleMappings);\n        } else {\n            return buildPageBundleMappings();\n        }\n    },\n\n    async getAppBundleMappingsCached (bundleSetConfig, lassoContext) {\n        const lassoCache = this.getLassoCache(lassoContext);\n        const cacheKey = bundleSetConfig._id;\n\n        logger.debug('getAppBundleMappingsCached()');\n\n        const builder = () => {\n            logger.debug('getAppBundleMappingsCached - BUILDER');\n            return this.createAppBundleMappings(bundleSetConfig, lassoContext);\n        };\n\n        return lassoCache.getBundleMappings(cacheKey, builder);\n    },\n\n    buildLassoCacheKey: function(lassoContext) {\n        let hash = 5381;\n        const keyParts = [];\n\n        function cacheKeyAdd (str) {\n            keyParts.push(str);\n\n            let i = str.length;\n            while (i) {\n                hash = (hash * 33) ^ str.charCodeAt(--i);\n            }\n        }\n\n        this.emit('buildCacheKey', {\n            context: lassoContext,\n            config: this.config,\n            lasso: this,\n            cacheKey: {\n                add: cacheKeyAdd\n            }\n        });\n\n        const flags = lassoContext.flags;\n        if (flags && !flags.isEmpty()) {\n            cacheKeyAdd('flags:' + flags.getKey());\n        }\n\n        cacheKeyAdd('config:' + (lassoContext.config.cacheKey || lassoContext.config.getConfigFingerprint()));\n\n        if (hash < 0) {\n            hash = 0 - hash;\n        }\n\n        return {\n            value: hash.toString(16),\n            parts: keyParts\n        };\n    },\n\n    /**\n     * This method is used by the lasso page tag to\n     * @param {Object} options is an object with the following properties:\n     *    - page: the render context\n     *    - flags: an array of enabled flags\n     * @return {LassoCache} the lasso cache associated with this page lasso\n     */\n    getLassoCache: function(lassoContext) {\n        let cache = lassoContext.cache;\n        if (!cache) {\n            const config = this.getConfig();\n\n            const keyInfo = this.buildLassoCacheKey(lassoContext);\n            const key = keyInfo.value;\n            cache = this.lassoCacheLookup[key];\n            if (!cache) {\n                cache = this.lassoCacheLookup[key] = new LassoCache(key, {\n                    dir: config.getCacheDir(),\n                    keyParts: keyInfo.parts,\n                    profile: config.getCacheProfile(),\n                    profiles: config.getCacheProfiles()\n                });\n\n                const pluginContext = {\n                    context: lassoContext,\n                    config,\n                    options: lassoContext.options,\n                    lasso: this,\n                    cacheKey: key,\n                    lassoCache: cache\n                };\n\n                this.emit('lassoCacheCreated', pluginContext);\n            }\n\n            lassoContext.cache = cache;\n        }\n        return cache;\n    },\n\n    getConfig: function() {\n        return this.config;\n    },\n\n    _resolveflags: function(options) {\n        const flagSet = flags.createFlagSet();\n\n        if (options) {\n            let additionalFlags = options.flags || options.extensions || options.enabledExtensions;\n            if (additionalFlags) {\n                if (typeof additionalFlags === 'string') {\n                    additionalFlags = additionalFlags.split(commaSeparatedRegExp);\n                }\n                flagSet.addAll(additionalFlags);\n            }\n        }\n\n        flagSet.addAll(this.config.getFlags());\n\n        return flagSet;\n    },\n\n    /**\n     * A LassoContext is created for each call to Lasso::lassoPage\n     * The LassoContext contains the following:\n     * - flags: Complete list of enabled flags\n     * - writer: A reference to the write configured by the Lasso\n     * - lasso: A reference to the Lasso\n     * - cache: Lasso.jsC\n     */\n    createLassoContext: function(options) {\n        const writer = this.writer;\n        const lassoContext = new LassoContext();\n\n        options = options || {};\n\n        if (options.basePath) {\n            lassoContext.basePath = options.basePath;\n        }\n\n        if (options.data) {\n            raptorUtil.extend(lassoContext.data, options.data);\n            delete options.data;\n        }\n\n        lassoContext.dependencyRegistry = this.dependencies;\n        lassoContext.flags = this._resolveflags(options);\n        lassoContext.config = this.config;\n        lassoContext.writer = writer;\n        lassoContext.lasso = this;\n        lassoContext.options = options;\n        // cache must come last so that all of the data above will\n        // be available on the lassoContext that will be part of the subsequent\n        // payload of the event that will be emitted after the cache is fetched.\n        lassoContext.cache = this.getLassoCache(lassoContext);\n\n        return lassoContext;\n    },\n\n    async lassoPage (options) {\n        const lassoContext = options.lassoContext || this.createLassoContext(options);\n\n        if (options.cache === false) {\n            return doLassoPage(this, options, lassoContext);\n        }\n\n        const lassoCache = this.getLassoCache(lassoContext);\n        const cacheKey = options.cacheKey || options.pageName || options.name;\n\n        const lassoPageResult = await lassoCache.getLassoPageResult(cacheKey, {\n            builder: async () => {\n                // Reuse the same lasso context\n                options = extend({ lassoContext }, options);\n                return doLassoPage(this, options, lassoContext);\n            }\n        });\n\n        this.emit('afterLassoPage', {\n            context: lassoContext,\n            lasso: this,\n            result: lassoPageResult\n        });\n\n        return lassoPageResult;\n    },\n\n    async prebuildPage (pageConfig, { writeToDisk = true } = {}) {\n        ok(pageConfig, '\"pageConfig\" is required by \"lasso.prebuildPage(...)\"');\n\n        let pageConfigs;\n        if (Array.isArray(pageConfig)) {\n            pageConfigs = pageConfig;\n        } else if (typeof pageConfig === 'object') {\n            pageConfigs = [pageConfig];\n        } else {\n            throw new Error('\"pageConfig\" should either be an array or object passed to \"lasso.prebuildPage(...)\"');\n        }\n\n        const lassoPrebuildResult = new LassoPrebuildResult();\n\n        for (let i = 0; i < pageConfigs.length; i++) {\n            const pageConfig = pageConfigs[i];\n            ok(typeof pageConfig === 'object', 'All pages passed to \"lasso.prebuildPage(...)\" should be an object');\n\n            const cwd = process.cwd();\n            const lassoPageResult = await this.lassoPage(pageConfig);\n            const name = buildPrebuildName(pageConfig.pageName);\n\n            const lassoPrebuild = lassoPageResult.toLassoPrebuild(name || cwd, pageConfig.flags);\n\n            const pageDir = pageConfig.pageDir || cwd;\n            const fileName = buildPrebuildFileName(name);\n            const buildPath = nodePath.resolve(pageDir, fileName);\n\n            lassoPrebuildResult.addBuild(buildPath, lassoPrebuild);\n        }\n\n        if (writeToDisk) await lassoPrebuildResult.write();\n        return lassoPrebuildResult;\n    },\n\n    async loadPrebuild (options = {}) {\n        const { path, flags } = options;\n        // TODO: If the prebuild does not exist, we should just use the lassoPage flow\n\n        // If we've already found the prebuild at this path, we can just return it\n        let lassoPageResult;\n        if ((lassoPageResult = prebuildToPath[path])) {\n            return lassoPageResult;\n        }\n\n        let prebuildFile;\n        try {\n            prebuildFile = require(path);\n        } catch (err) {\n            throw new Error(`Error loading prebuild. No prebuild with path \"${path}\" exists. Error: ${err.toString()}`);\n        }\n\n        // TODO: Consider changing this to just the dash separated cache key for flags\n        let build;\n        if (flags) {\n            for (const prebuild of prebuildFile) {\n                try {\n                    assert.deepEqual(prebuild.flags, flags);\n                    build = prebuild;\n                    break;\n                } catch (err) {}\n            }\n        } else {\n            // Try to find a prebuild that does not require flags\n            for (const prebuild of prebuildFile) {\n                if (!prebuild.flags || !prebuild.flags.length) {\n                    build = prebuild;\n                    break;\n                }\n            }\n        }\n\n        if (!build) {\n            const flagsStr = (flags && flags.join(',')) || flags;\n            throw new Error(`No build could be found using flags: \"${flagsStr}\" for file at path \"${path}\"`);\n        }\n\n        lassoPageResult = new LassoPageResult();\n        lassoPageResult.setSlotsByName(build.slots);\n        lassoPageResult.resources = build.resources;\n\n        prebuildToPath[path] = lassoPageResult;\n\n        return lassoPageResult;\n    },\n\n    /**\n     * @param  {String} path The file path of the resource to bundle\n     * @param  {Object} options (see below for supported options)\n     */\n    async lassoResource (data, options) {\n        let lassoContext;\n        options = options || {};\n\n        if (options.LassoContext === true) {\n            lassoContext = options;\n            options = {};\n        }\n\n        if (!lassoContext) {\n            lassoContext = options.lassoContext || this.createLassoContext(options);\n        }\n\n        const lassoPageResult = lassoContext.lassoPageResult;\n\n        function done (result) {\n            if (lassoPageResult && result) {\n                lassoPageResult.registerResource(result);\n            }\n\n            return result;\n        }\n\n        let lassoResourceResult;\n\n        const dataType = typeof data;\n        const resourceHandlers = resourceHandlersByType[dataType];\n\n        if (!resourceHandlers) {\n            throw new Error(`Unsupported data type \"${dataType}\" passed to \"lassoResource\"`);\n        }\n\n        const useCache = options.cache !== false;\n\n        // If the resource type has the `hashPath` property set, we have to\n        // calculate the cache key to use it for the file path even if the\n        // the `cache` option is not set.\n        let cacheKey = null;\n        if (resourceHandlers.hashPath || useCache) {\n            cacheKey = resourceHandlers.calculateKey(data, this, lassoContext, options);\n        }\n\n        if (useCache) {\n            const cache = this.getLassoCache(lassoContext);\n\n            lassoResourceResult = await cache.getLassoedResource(cacheKey, async () => {\n                return resourceHandlers.resource(this, data, cacheKey, options, lassoContext);\n            });\n        } else {\n            lassoResourceResult = await resourceHandlers.resource(this, data, cacheKey, options, lassoContext);\n        }\n\n        return done(lassoResourceResult);\n    },\n\n    addTransform: function(transform) {\n        this.config.addTransform(transform);\n    },\n\n    getDependencyRegistry() {\n        return this.dependencies;\n    }\n};\n\nraptorUtil.inherit(Lasso, EventEmitter);\n\nmodule.exports = Lasso;\n"
  },
  {
    "path": "src/LassoCache.js",
    "content": "const raptorCache = require('raptor-cache');\nconst nodePath = require('path');\nconst LassoPageResult = require('./LassoPageResult');\nconst DEFAULT_BASE_CACHE_DIR = nodePath.join(require('app-root-dir').get(), '.cache/lasso');\nconst deserializeLassoPageResult = LassoPageResult.deserialize;\nconst serializeLassoPageResult = LassoPageResult.serialize;\nconst fs = require('fs');\nconst mkdirp = require('mkdirp');\n\nfunction safeFilename(name) {\n    return name.replace(/[^A-Za-z0-9_\\-\\.\\/]/g, '-');\n}\n\nfunction waitImmediate() {\n    return new Promise(resolve => setImmediate(resolve));\n}\n\nconst CACHE_DEFAULTS = {\n    '*': { // Any profile\n        '*': { // Any cache\n            store: 'memory' // Default to a memory store for all caches for all profiles\n        },\n        lassoPageResults: {\n            store: 'memory',\n            serialize: serializeLassoPageResult,\n            deserialize: deserializeLassoPageResult\n        },\n        bundleMappings: {\n            store: 'memory'\n        },\n        lassoedResources: {\n            store: 'memory',\n            valueType: 'json'\n        },\n        dependencyFingerprints: {\n            store: 'disk',\n            valueType: 'string'\n        },\n        read: {\n            store: 'disk',\n            singleFile: false,\n            encoding: 'utf8'\n        }\n    },\n    production: { // Read and write to disk cache in production\n        lassoPageResults: {\n            store: 'disk'\n        },\n        bundleMappings: {\n            store: 'memory'\n        },\n        lassoedResources: {\n            store: 'disk'\n        },\n        dependencyFingerprints: {\n            store: 'disk'\n        }\n    }\n};\n\nclass SyncCache {\n    constructor() {\n        this._store = {};\n    }\n\n    getSync(key) {\n        return this._store[key];\n    }\n\n    putSync(key, value) {\n        this._store[key] = value;\n    }\n}\n\nfunction LassoCache(key, options) {\n    const cacheProfileName = options.profile;\n    const keyParts = options.keyParts;\n\n    let cacheManager;\n\n    if (typeof options.cacheManagerFactory === 'function') {\n        cacheManager = options.cacheManagerFactory({\n            profile: cacheProfileName,\n            profiles: options.profiles\n        });\n    }\n\n    this.cacheManager = cacheManager || options.cacheManager || raptorCache.createCacheManager({\n        profile: cacheProfileName,\n        profiles: options.profiles\n    });\n\n    this.key = key;\n\n    const _this = this;\n\n    this.cacheManager.on('cacheConfigured', function(eventArgs) {\n        const cacheName = eventArgs.name;\n        const cacheConfig = eventArgs.config;\n\n        if (!cacheConfig.dir) {\n            // Just in case this this cache uses a disk store we will configure a safe directory to use\n            cacheConfig.dir = nodePath.join(_this.baseCacheDir, safeFilename(cacheName));\n        }\n    });\n\n    this.baseCacheName = safeFilename(cacheProfileName || 'default') + (key ? '/' + safeFilename(key) : '');\n    this.baseCacheDir = options.dir || DEFAULT_BASE_CACHE_DIR;\n\n    if (keyParts) {\n        const keyDir = nodePath.join(this.baseCacheDir, this.baseCacheName);\n        mkdirp.sync(keyDir);\n        const keyFile = nodePath.join(keyDir, 'key');\n\n        try {\n            fs.writeFileSync(keyFile, JSON.stringify(keyParts), { encoding: 'utf8' });\n        } catch (e) {\n            // We only write the key for debugging purposes. On machines with\n            // read only disks this will fail but that is okay\n        }\n    }\n\n    // Merge in the lasso defaults (the user profiles, if any, have already been merged)\n    this.configureCacheDefaults(CACHE_DEFAULTS);\n\n    this.lassoPageResultCache = this.getCache('lassoPageResults');\n    this.bundleMappingsCache = this.getCache('bundleMappings');\n    this.lassoedResourcesCache = this.getCache('lassoedResources');\n    this.dependencyFingerprintsCache = this.getCache('dependencyFingerprints');\n    this.readCache = this.getCache('read');\n\n    this.syncCaches = {};\n}\n\nLassoCache.prototype = {\n    configureCacheDefaults: function(profileName, cacheConfigName, defaults) {\n        this.cacheManager.configureCacheDefaults.apply(this.cacheManager, arguments);\n    },\n\n    getCache: function(name, cacheConfigName) {\n        if (!cacheConfigName) {\n            cacheConfigName = name;\n        }\n\n        name = this.baseCacheName + '/' + name;\n        return this.cacheManager.getCache(name, cacheConfigName);\n    },\n\n    getSyncCache: function(name) {\n        return this.syncCaches[name] || (this.syncCaches[name] = new SyncCache());\n    },\n\n    flushAll () {\n        return raptorCache.flushAll();\n    },\n\n    async getLassoPageResult(cacheKey, options) {\n        return this.lassoPageResultCache.get(cacheKey, options);\n    },\n\n    async getBundleMappings (id, builder) {\n        await waitImmediate();\n\n        while (process.domain) {\n            process.domain.exit();\n        }\n\n        return this.bundleMappingsCache.get(id.toString(), { builder });\n    },\n\n    async getLassoedResource (path, builder) {\n        await waitImmediate();\n\n        while (process.domain) {\n            process.domain.exit();\n        }\n\n        return this.lassoedResourcesCache.get(path, { builder });\n    },\n\n    async getDependencyFingerprint (cacheKey, lastModified, builder) {\n        await waitImmediate();\n\n        while (process.domain) {\n            process.domain.exit();\n        }\n\n        return this.dependencyFingerprintsCache.get(cacheKey, {\n            lastModified,\n            builder\n        });\n    }\n};\n\nmodule.exports = LassoCache;\n"
  },
  {
    "path": "src/LassoContext.js",
    "content": "const EventEmitter = require('events').EventEmitter;\nconst lastModified = require('./last-modified');\nconst cachingFs = require('./caching-fs');\nconst DeferredReadable = require('./util/DeferredReadable');\nconst manifestLoader = require('./manifest-loader');\nconst LassoManifest = require('./LassoManifest');\nconst util = require('./util');\nconst getClientPath = require('lasso-modules-client/transport').getClientPath;\nconst resolve = require('./resolve');\n\nclass LassoContext extends EventEmitter {\n    constructor() {\n        super();\n\n        this.data = {};\n        this.phaseData = {};\n        this._phase = null;\n        this.cachingFs = cachingFs;\n\n        let nextId = 0;\n\n        this.uniqueId = function() {\n            return nextId++;\n        };\n    }\n\n    deferredStream(startFn, options) {\n        return new DeferredReadable(startFn, options);\n    }\n\n    /**\n     * Converts a \"reader\" function to a function that *always* returns a stream.\n     * The actual reader function may return a promise, a String, a stream or it may use a callback.\n     */\n    createReadStream(func) {\n        return util.readStream(func);\n    }\n\n    clearData() {\n        this.data = {};\n    }\n\n    getData(name) {\n        return this.data[name];\n    }\n\n    setData(name, value) {\n        this.data[name] = value;\n    }\n\n    async getFileLastModified (filePath) {\n        const lastModifiedResult = await lastModified.forFile(filePath);\n        return lastModifiedResult || -1;\n    }\n\n    setPhase(phaseName) {\n        this._phase = phaseName;\n        this.phaseData = {}; // Clear out the phase data\n    }\n\n    isPageBundlingPhase() {\n        return this._phase === 'page-bundle-mappings';\n    }\n\n    isAppBundlingPhase() {\n        return this._phase === 'app-bundle-mappings';\n    }\n\n    isAsyncBundlingPhase() {\n        return this._phase === 'async-page-bundle-mappings';\n    }\n\n    readPackageFile(path) {\n        const rawManifest = manifestLoader.load(path);\n        return new LassoManifest({\n            manifest: rawManifest,\n            dependencyRegistry: this.dependencyRegistry\n        });\n    }\n\n    createFingerprintStream() {\n        return util.createFingerprintStream();\n    }\n\n    getClientPath(file) {\n        return getClientPath(file);\n    }\n\n    getResolver() {\n        if (this.resolver === undefined) {\n            this.resolver = resolve.createResolver(this, getClientPath);\n        }\n        return this.resolver;\n    }\n\n    resolve(targetModule, fromDir, options) {\n        return this.getResolver().resolve(targetModule, fromDir, options);\n    }\n\n    resolveCached(targetModule, fromDir, options) {\n        return this.getResolver().resolveCached(targetModule, fromDir, options);\n    }\n\n    getProjectRoot() {\n        return this.config.getProjectRoot();\n    }\n}\n\nLassoContext.prototype.LassoContext = true;\n\nmodule.exports = LassoContext;\n"
  },
  {
    "path": "src/LassoManifest.js",
    "content": "const extend = require('raptor-util').extend;\nconst DependencyList = require('./DependencyList');\nconst ok = require('assert').ok;\n\nconst nodePath = require('path');\nconst FlagSet = require('./FlagSet');\nlet nextId = 0;\n\nconst condition = require('./condition');\n\nconst lassoResolveFrom = require('lasso-resolve-from');\n\nconst logger = require('raptor-logging').logger(module);\n\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction resolveBrowserPath(dir, path) {\n    let resolved;\n\n    if (path.charAt(0) === '.') {\n        resolved = lassoResolveFrom(dir, path);\n    } else {\n        resolved = lassoResolveFrom(dir, './' + path);\n        if (!resolved) {\n            resolved = lassoResolveFrom(dir, path);\n        }\n    }\n\n    return resolved ? resolved.path : undefined;\n}\n\nfunction LassoManifest(options) {\n    const dependencyRegistry = options.dependencyRegistry;\n\n    let async;\n\n    if (options.manifest) {\n        // save off the async property value\n        async = options.manifest.async;\n\n        extend(this, options.manifest);\n    }\n\n    ok(dependencyRegistry, '\"dependencyRegistry\" is required');\n\n    this._uniqueId = nextId++;\n\n    if (options.dirname) {\n        this.dirname = options.dirname;\n    }\n\n    if (options.filename) {\n        this.filename = options.filename;\n    }\n\n    const dirname = this.dirname;\n    const filename = this.filename;\n\n    ok(dirname, '\"dirname\" is required');\n    ok(typeof dirname === 'string', '\"dirname\" must be a string');\n\n    this.dependencies = new DependencyList(\n        this.dependencies || [],\n        dependencyRegistry,\n        dirname,\n        filename);\n\n    this.async = null;\n\n    if (async) {\n        if (typeof async !== 'object') {\n            throw new Error('async should be an object. (dirname=' + dirname + ', filename=' + filename + ')');\n        }\n\n        this.async = {};\n\n        for (const asyncPackageName in async) {\n            if (hasOwn.call(async, asyncPackageName)) {\n                const asyncDependencies = async[asyncPackageName];\n                this.async[asyncPackageName] = new DependencyList(\n                    asyncDependencies,\n                    dependencyRegistry,\n                    dirname,\n                    filename);\n            }\n        }\n    }\n\n    const requireRemap = this.requireRemap;\n    if (requireRemap && Array.isArray(requireRemap)) {\n        this.requireRemap = requireRemap.map((requireRemap) => {\n            const from = resolveBrowserPath(dirname, requireRemap.from);\n            const to = resolveBrowserPath(dirname, requireRemap.to);\n\n            return {\n                from,\n                to,\n                condition: condition.fromObject(requireRemap)\n            };\n        });\n    }\n}\n\nLassoManifest.prototype = {\n    __LassoManifest: true,\n\n    getUniqueId: function() {\n        return this._uniqueId;\n    },\n\n    resolve: function(relPath) {\n        return nodePath.resolve(this.dirname, relPath);\n    },\n\n    /**\n     *\n     * @param options\n     * @returns\n     */\n    async getDependencies (options) {\n        logger.debug('getDependencies()');\n\n        let flags = options && options.flags;\n        if (!flags || !flags.__FlagSet) {\n            flags = new FlagSet(flags);\n        }\n\n        logger.debug('getDependencies() Normalizing dependencies BEGIN: ', this.dependencies);\n\n        const dependencies = await this.dependencies.normalize();\n        logger.debug('getDependencies() Normalizing dependencies DONE: ', this.dependencies);\n        return dependencies;\n    },\n\n    getRequireRemap: function(lassoContext) {\n        if (this.requireRemap && Array.isArray(this.requireRemap)) {\n            const filteredRemaps = {};\n            const flags = lassoContext.flags;\n\n            this.requireRemap.forEach(function(remap) {\n                if (remap.condition && !remap.condition(flags)) {\n                    return;\n                }\n\n                filteredRemaps[remap.from] = remap.to;\n            });\n\n            return filteredRemaps;\n        } else {\n            return {};\n        }\n    }\n};\n\nLassoManifest.isLassoManifest = function(o) {\n    return o && o.__LassoManifest;\n};\n\nmodule.exports = LassoManifest;\n"
  },
  {
    "path": "src/LassoPageResult.js",
    "content": "const Slot = require('./Slot');\nconst EMPTY_OBJECT = {};\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction LassoPageResult () {\n    this.urlsBySlot = {};\n    this.urlsByContentType = {};\n    this.files = [];\n    this.infoByBundleName = {};\n    this.infoByAsyncBundleName = {};\n    this.resources = [];\n    this._slotsByName = {};\n\n    /**\n     * If Lasso is configured to fingerprint inline code for\n     * the purpose of Content Security Policy then this property\n     * will store the array of fingerprints.\n     */\n    this._inlineCodeFingerprints = undefined;\n}\n\nLassoPageResult.deserialize = function (reader) {\n    let json = '';\n\n    return new Promise((resolve, reject) => {\n        reader()\n            .on('data', function (data) {\n                json += data;\n            })\n            .on('end', function () {\n                resolve(Object.assign(new LassoPageResult(), JSON.parse(json)));\n            })\n            .on('error', function (err) {\n                reject(err);\n            });\n    });\n};\n\nLassoPageResult.serialize = function(lassoPageResult) {\n    return JSON.stringify(lassoPageResult);\n};\n\nLassoPageResult.prototype = {\n    /**\n     * Returns the HTML for all slots on the page.\n     *\n     * An object is returned in which property name\n     * is the name of the slot and the value is the corresponding\n     * HTML for the slot.\n     *\n     * <p>\n     * Example output:\n     * <js>\n     * {\n     *   'body': '<script src=\"/static/test-page-body-f01892af.js\"></script>',\n     *   'head': '<link rel=\"stylesheet\" href=\"/static/test-page-head-bf4cf798.css\">'\n     * }\n     * </js>\n     *\n     * @return {Object} An object with slot names as property names and slot HTML as property values.\n     */\n    get htmlBySlot() {\n        const htmlBySlot = {};\n        for (const slotName in this._slotsByName) {\n            if (hasOwn.call(this._slotsByName, slotName)) {\n                const slotHtml = this.getHtmlForSlot(slotName);\n                htmlBySlot[slotName] = slotHtml;\n            }\n        }\n\n        return htmlBySlot;\n    },\n\n    getHtmlBySlot: function() {\n        return this.htmlBySlot;\n    },\n\n    /**\n     * Returns the HTML for a single slot.\n     * <p>\n     * Example out:\n     * <js>\n     * \"<script src=\"/static/test-page-body-f01892af.js\"></script>\"\n     * </js>\n     *\n     * @param  {String} slotName The name of the slot (e.g. \"head\" or \"body\")\n     * @param  {Object} data Input data to the slot that is used to render the actual slot HTML\n     * @return {String} The HTML for the slot or an empty string if there is no HTML defined for the slot.\n     */\n    getHtmlForSlot: function(slotName, data) {\n        const slots = this._slotsByName[slotName];\n\n        if (slots) {\n            const slotData = data || EMPTY_OBJECT;\n            let html = '';\n            let sep = '';\n            for (const slot of slots) {\n                html += sep + Slot.render(slot, slotData);\n                sep = '\\n';\n            }\n\n            return html;\n        }\n\n        return '';\n    },\n\n    getHeadHtml: function(data) {\n        return this.getHtmlForSlot('head', data);\n    },\n\n    getBodyHtml: function(data) {\n        return this.getHtmlForSlot('body', data);\n    },\n\n    /**\n     * Synonym for {@Link raptor/lasso/LassoPageResult#getHtmlForSlot}\n     */\n    getSlotHtml: function(slotName, data) {\n        return this.getHtmlForSlot(slotName, data);\n    },\n\n    setSlotsByName: function(slotsByName) {\n        this._slotsByName = slotsByName;\n    },\n\n    registerBundle: function(bundle, async, lassoContext) {\n        const bundleInfoMap = async\n            ? this.infoByAsyncBundleName\n            : this.infoByBundleName;\n\n        const info = bundleInfoMap[bundle.name] || (bundleInfoMap[bundle.name] = {});\n        const url = bundle.getUrl(lassoContext);\n        const slot = async ? undefined : bundle.slot;\n\n        if (url) {\n            this.addUrl(url, bundle.getSlot(), bundle.getContentType(), async, slot);\n            info.url = url;\n        }\n\n        if (!bundle.isExternalResource && bundle.outputFile) {\n            this.addFile(bundle.outputFile, bundle.getContentType(), async, slot);\n            info.file = bundle.outputFile;\n        }\n    },\n\n    registerResource: function(resource) {\n        this.resources.push(resource);\n    },\n\n    addUrl: function(url, slot, contentType, isAsync) {\n        if (!isAsync) {\n            const urlsForSlot = this.urlsBySlot[slot] || (this.urlsBySlot[slot] = []);\n            urlsForSlot.push(url);\n        }\n\n        const urlsForContentType = this.urlsByContentType[contentType] || (this.urlsByContentType[contentType] = []);\n        urlsForContentType.push(url);\n    },\n\n    getOutputFilesWithInfo() {\n        return this.files;\n    },\n\n    addFile: function(filePath, contentType, isAsync, slot) {\n        this.files.push({\n            path: filePath,\n            contentType,\n            async: isAsync,\n            slot\n        });\n    },\n\n    /**\n     * Returns the URLs of all the JavaScript resources for the page\n     * @return {Array<String>} An array of URLs\n     */\n    getJavaScriptUrls: function() {\n        return this.urlsByContentType.js || [];\n    },\n\n    /**\n     * Returns the URLs of all the CSS resources for the page\n     * @return {Array<String>} An array of URLs\n     */\n    getCSSUrls: function() {\n        return this.urlsByContentType.css || [];\n    },\n\n    /**\n     * Returns the URLs of all the JavaScript resources for the page\n     * @return {Array<String>} An array of URLs\n     */\n    getUrlsForSlot: function(slot) {\n        return this.urlsBySlot[slot] || [];\n    },\n\n    /**\n     * Returns the {@Link raptor/files/File} objects for all the JavaScript resources for the page\n     * @return {Array<raptor/files/File>} An array of File objects\n     */\n    getJavaScriptFiles: function() {\n        return this.getFilePathsByContentType('js');\n    },\n\n    getFilePathsByContentType(contentType) {\n        const paths = [];\n        this.files.forEach((file) => {\n            if (file.contentType === contentType) {\n                paths.push(file.path);\n            }\n        });\n        return paths;\n    },\n\n    /**\n     * Returns the {@Link raptor/files/File} objects for all the CSS resources for the page\n     * @return {Array<raptor/files/File>} An array of File objects\n     */\n    getCSSFiles: function() {\n        return this.getFilePathsByContentType('css');\n    },\n\n    getOutputFiles: function() {\n        return this.getJavaScriptFiles().concat(this.getCSSFiles());\n    },\n\n    getFileByBundleName: function(bundleName) {\n        const info = this.infoByBundleName[bundleName];\n        return info && info.file;\n    },\n\n    getFileByAsyncBundleName: function(bundleName) {\n        const info = this.infoByAsyncBundleName[bundleName];\n        return info && info.file;\n    },\n\n    getUrlByBundleName: function(bundleName) {\n        const info = this.infoByBundleName[bundleName];\n        return info && info.url;\n    },\n\n    getUrlByAsyncBundleName: function(bundleName) {\n        const info = this.infoByAsyncBundleName[bundleName];\n        return info && info.url;\n    },\n\n    getInlineCodeFingerprints: function() {\n        return this._inlineCodeFingerprints;\n    },\n\n    setInlineCodeFingerprints: function(inlineCodeFingerprints) {\n        this._inlineCodeFingerprints = inlineCodeFingerprints;\n    },\n\n    toLassoPrebuild (name, flags) {\n        return {\n            slots: this._slotsByName,\n            assets: this.resources,\n            name,\n            flags\n        };\n    }\n};\n\nmodule.exports = LassoPageResult;\n"
  },
  {
    "path": "src/LassoPrebuildResult.js",
    "content": "const fs = require('fs');\n\n/**\n* We may want to store the prebuild in the same directory as the page\n* file instead of the current working directory. There will often be\n* an npm script that is running at the base of the project. In the\n* AWS Lambda case, we want the prebuild file to live alongside of the\n* page itself. We need to preprocess all of the builds and then write\n* them individually after because there may be multiple pages that live\n* in the same directory as well as multiple builds for the same page\n* with different flags.\n*/\nclass LassoPrebuildResult {\n    constructor () {\n        this._buildsByPath = {};\n    }\n\n    addBuild (path, build) {\n        if (this._buildsByPath[path]) {\n            this._buildsByPath[path].push(build);\n        } else {\n            this._buildsByPath[path] = [build];\n        }\n    }\n\n    async write () {\n        for (const buildPath in this._buildsByPath) {\n            await fs.promises.writeFile(\n                buildPath,\n                this.serializeBuild(buildPath),\n                'utf8');\n        }\n    }\n\n    serializeBuild (path) {\n        const build = this._buildsByPath[path];\n        return JSON.stringify(build, null, 2);\n    }\n\n    getBuildByPath (path) {\n        return this._buildsByPath[path];\n    }\n\n    getBuildsByPath () {\n        return this._buildsByPath;\n    }\n}\n\nmodule.exports = LassoPrebuildResult;\n"
  },
  {
    "path": "src/LoaderMetadata.js",
    "content": "const AsyncPackage = require('./AsyncPackage');\nfunction LoaderMetadata() {\n    this._packageNames = Object.create(null);\n    this._asyncPackagesByName = {};\n}\n\nLoaderMetadata.prototype = {\n\n    addAsyncPackageName: function(asyncName) {\n        this._packageNames[asyncName] = true;\n    },\n\n    addBundle: function(asyncName, bundle) {\n        const asyncPackage = this._asyncPackagesByName[asyncName] || (this._asyncPackagesByName[asyncName] = new AsyncPackage(asyncName));\n        asyncPackage.addBundle(bundle);\n    },\n\n    /**\n     * This method is used by lasso-modules-client/transport/src/code-loader-metadata.js\n     * to create simple object that can be stringified to generate code for\n     * lasso metadata.\n     */\n    toObject: function(context) {\n        if (!context) {\n            throw new Error('\"context\" is required');\n        }\n\n        // EXAMPLE RESULT:\n        /*\n        {\n            \"foo\": {\n                js: ['a.js'],\n                css: ['b.js']\n            }\n        }\n        */\n        const result = {};\n\n        for (const name in this._packageNames) {\n            const asyncPackage = this._asyncPackagesByName[name];\n            if (asyncPackage) {\n                result[name] = asyncPackage.getMeta(context);\n            } else {\n                result[name] = {};\n            }\n        }\n\n        return result;\n    }\n};\n\nmodule.exports = LoaderMetadata;\n"
  },
  {
    "path": "src/PageBundles.js",
    "content": "const forEachEntry = require('raptor-util').forEachEntry;\n\n/**\n *\n */\nconst PageBundles = function() {\n    this.bundles = [];\n    this.bundleLookup = {};\n    this.asyncBundleLookup = {};\n};\n\nPageBundles.prototype = {\n    addSyncBundle: function(bundle) {\n        /*\n         * Add the bundle to a page slot if it has not already been added\n         */\n        const bundleLookupKey = bundle.getKey();\n\n        if (!this.bundleLookup[bundleLookupKey]) {\n            this.bundleLookup[bundleLookupKey] = bundle;\n            this.bundles.push(bundle);\n        }\n    },\n\n    addAsyncBundle: function(bundle) {\n        this.asyncBundleLookup[bundle.getKey()] = bundle;\n    },\n\n    lookupSyncBundle: function(bundle) {\n        return this.bundleLookup[bundle.getKey()];\n    },\n\n    forEachBundle: function(callback, thisObj) {\n        this.bundles.forEach(callback, thisObj);\n    },\n\n    forEachAsyncBundle: function(callback, thisObj) {\n        forEachEntry(this.asyncBundleLookup, function(bundleKey, bundle) {\n            callback.call(thisObj, bundle);\n        }, this);\n    },\n\n    forEachBundleIter: function() {\n        return this.forEachBundle.bind(this);\n    },\n\n    forEachAsyncBundleIter: function() {\n        return this.forEachAsyncBundle.bind(this);\n    }\n};\n\nmodule.exports = PageBundles;\n"
  },
  {
    "path": "src/PageConfig.js",
    "content": "function PageConfig() {\n    this.name = null;\n    this.bundleSetConfig = null;\n    this.packageManifest = null;\n}\n\nPageConfig.prototype = {\n\n    getBundleSetConfig: function() {\n        return this.bundleSetConfig;\n    },\n\n    addBundleSetConfig: function(bundleSetConfig) {\n        if (this.bundleSetConfig) {\n            throw new Error('Page \"' + this.name + '\" already has bundles defined\"');\n        }\n\n        this.bundleSetConfig = bundleSetConfig;\n    },\n\n    setPackageManifest: function(packageManifest) {\n        this.packageManifest = packageManifest;\n    },\n\n    getPackageManifest: function() {\n        return this.packageManifest;\n    },\n\n    getName: function() {\n        return this.name;\n    },\n\n    toString: function() {\n        return '[PageConfig name=' + this.name + ']';\n    }\n};\n\nmodule.exports = PageConfig;\n"
  },
  {
    "path": "src/Slot.js",
    "content": "const ok = require('assert').ok;\nconst stringifyAttrs = require('./util/stringify-attrs');\n\nfunction Slot(contentType) {\n    ok(contentType, 'contentType is required');\n    this.contentType = contentType;\n    this.content = [];\n}\n\nSlot.prototype = {\n    addInlineCode: function(code, merge) {\n        if (merge) {\n            const prev = this.content.length ? this.content[this.content.length - 1] : null;\n            if (prev && prev.inline && prev.merge && typeof prev.code === 'string') {\n                prev.code += '\\n' + code;\n                return;\n            }\n        }\n\n        this.content.push({\n            inline: true,\n            code,\n            merge: merge !== false\n        });\n    },\n\n    addContent: function(content) {\n        this.content.push({\n            inline: false,\n            code: content\n        });\n    }\n};\n\nSlot.render = function(slot, data) {\n    let html = '';\n    let sep = '';\n\n    for (const content of slot.content) {\n        html += sep;\n        sep = '\\n';\n\n        switch (slot.contentType) {\n        case 'js':\n            html += (content.inline ? inlineScript : externalScript)(content.code, data);\n            break;\n        case 'css':\n            html += (content.inline ? inlineStyle : externalStyle)(content.code, data);\n            break;\n        default:\n            throw new Error('Invalid content type: ' + slot.contentType);\n        }\n    }\n\n    return html;\n};\n\nfunction inlineScript(content, data) {\n    const scriptAttrs = data.externalScriptAttrs;\n    let result = `<script${stringifyAttrs(data.inlineScriptAttrs)}>`;\n\n    if (scriptAttrs) {\n        if (scriptAttrs.async) {\n            result += wrapInDocumentLoaded(content, true);\n        } else if (scriptAttrs.defer) {\n            result += wrapInDocumentLoaded(content);\n        } else {\n            result += content;\n        }\n    } else {\n        result += content;\n    }\n\n    return `${result}</script>`;\n}\n\nfunction inlineStyle(content, data) {\n    return `<style${stringifyAttrs(data.inlineStyleAttrs)}>${content}</style>`;\n}\n\nfunction externalScript(attrs, data) {\n    return `<script${stringifyAttrs(Object.assign({}, attrs, data.externalScriptAttrs))}></script>`;\n}\n\nfunction externalStyle(attrs, data) {\n    return `<link${stringifyAttrs(Object.assign({ rel: 'stylesheet' }, attrs, data.externalStyleAttrs))}>`;\n}\n\nfunction wrapInDocumentLoaded(code, isAsync) {\n    return (\n        '(function() { var run = function() { ' +\n        code +\n        ' }; if (document.readyState ' +\n        (isAsync ? '!== \"complete\"' : '=== \"loading\"') +\n        ') { ' +\n        (isAsync\n            ? 'window.addEventListener(\"load\"'\n            : 'document.addEventListener(\"DOMContentLoaded\"') +\n        ', run); } else { run(); } })();'\n    );\n}\n\nmodule.exports = Slot;\n"
  },
  {
    "path": "src/SlotTracker.js",
    "content": "const Slot = require('./Slot');\nconst InlinePos = require('./InlinePos');\n\nfunction SlotTracker() {\n    this.slots = {};\n    this.slotNames = new Set();\n}\n\nSlotTracker.prototype = {\n    addInlineCode: function(slotName, contentType, code, inlinePos, mergeInline) {\n        this.slotNames.add(slotName);\n\n        let slotKey = contentType + ':' + slotName;\n        if (inlinePos === InlinePos.BEGINNING) {\n            slotKey += ':before';\n        } else if (inlinePos === InlinePos.END) {\n            slotKey += ':after';\n        }\n\n        const slot = this.slots[slotKey] || (this.slots[slotKey] = new Slot(contentType));\n        slot.addInlineCode(code, mergeInline);\n    },\n\n    addContent: function(slotName, contentType, content) {\n        this.slotNames.add(slotName);\n\n        const slotKey = contentType + ':' + slotName;\n        const slot = this.slots[slotKey] || (this.slots[slotKey] = new Slot(contentType));\n        slot.addContent(content);\n    },\n\n    getSlotsByName: function() {\n        const slotsByName = {};\n        const slots = this.slots;\n\n        function addCode(slotList, key) {\n            const slot = slots[key];\n            if (slot) slotList.push(slot);\n        }\n\n        for (const slotName of this.slotNames) {\n            const slotList = slotsByName[slotName] = [];\n            addCode(slotList, 'css:' + slotName + ':before');\n            addCode(slotList, 'css:' + slotName);\n            addCode(slotList, 'css:' + slotName + ':after');\n\n            addCode(slotList, 'js:' + slotName + ':before');\n            addCode(slotList, 'js:' + slotName);\n            addCode(slotList, 'js:' + slotName + ':after');\n        }\n\n        return slotsByName;\n    }\n};\n\nmodule.exports = SlotTracker;\n"
  },
  {
    "path": "src/browser-refresh/index.js",
    "content": "const browserRefreshClient = require('browser-refresh-client');\nconst nodePath = require('path');\n\nconst styleExtensions = {\n    css: true,\n    less: true,\n    styl: true,\n    stylus: true,\n    scss: true,\n    sass: true,\n    webp: true\n};\n\nconst imageExtensions = {\n    png: true,\n    jpeg: true,\n    jpg: true,\n    gif: true,\n    svg: true\n};\n\nlet enabled = false;\n\nexports.enable = function(patterns) {\n    if (!browserRefreshClient.isBrowserRefreshEnabled() || enabled) {\n        return;\n    }\n\n    enabled = true;\n\n    const lasso = require('../');\n\n    lasso.setDevelopmentMode();\n\n    if (!patterns) {\n        // Reasonable default with client-side only files...\n        patterns = '*.marko *.css *.less *.styl *.scss *.sass *.png *.jpeg *.jpg *.gif *.webp *.svg *.eot *.ttf *.woff *.woff2';\n    }\n\n    browserRefreshClient\n        .enableSpecialReload(patterns, { autoRefresh: false })\n        .onFileModified(function(path) {\n            lasso.handleWatchedFileChanged(path);\n\n            let extname = nodePath.extname(path);\n            if (extname) {\n                extname = extname.substring(1);\n            }\n\n            if (imageExtensions[extname]) {\n                console.log('[lasso/browser-refresh] Image modified: ' + path);\n                browserRefreshClient.refreshImages();\n            } else if (styleExtensions[extname]) {\n                console.log('[lasso/browser-refresh] StyleSheet modified: ' + path);\n                browserRefreshClient.refreshStyles();\n            } else {\n                console.log('[lasso/browser-refresh] File modified: ' + path);\n                browserRefreshClient.refreshPage();\n            }\n        });\n};\n"
  },
  {
    "path": "src/bundle-builder.js",
    "content": "const dependencyWalker = require('./dependency-walker');\nconst DependencyTree = require('./DependencyTree');\nconst logger = require('raptor-logging').logger(module);\nconst lassoPackageRoot = require('lasso-package-root');\nconst nodePath = require('path');\n\nconst recurseHandlers = {\n    none: function(rootDependency, lassoContext) {\n        return {\n            shouldIncludeDependency: function(dependency) {\n                return false;\n            },\n\n            shouldRecurseIntoPackageDependency: function(dependency) {\n                return false;\n            }\n        };\n    },\n\n    all: function(rootDependency, lassoContext) {\n        return {\n            shouldIncludeDependency: function(dependency) {\n                return true;\n            },\n\n            shouldRecurseIntoPackageDependency: function(dependency) {\n                return true;\n            }\n        };\n    },\n\n    dir: function(rootDependency, lassoContext) {\n        const baseDir = rootDependency.getDir(lassoContext) || '';\n\n        return {\n            shouldIncludeDependency: function(dependency) {\n                const dir = dependency.getDir(lassoContext);\n                return dir === baseDir;\n            },\n\n            shouldRecurseIntoPackageDependency: function(dependency) {\n                if (dependency.getDir(lassoContext) === baseDir) {\n                    return true;\n                }\n\n                return false;\n            }\n        };\n    },\n\n    dirtree: function(rootDependency, lassoContext) {\n        const baseDir = rootDependency.getDir(lassoContext);\n\n        function checkDir(dependency) {\n            if (!baseDir) {\n                return false;\n            }\n\n            const dir = dependency.getDir(lassoContext);\n            if (!dir) {\n                return false;\n            }\n\n            return dir.startsWith(baseDir);\n        }\n\n        return {\n            shouldIncludeDependency: function(dependency) {\n                return checkDir(dependency);\n            },\n\n            shouldRecurseIntoPackageDependency: function(dependency) {\n                return checkDir(dependency);\n            }\n        };\n    },\n\n    module: function(rootDependency, lassoContext) {\n        let baseDir = rootDependency.getDir(lassoContext);\n        let nodeModulesDir;\n\n        if (baseDir) {\n            baseDir = lassoPackageRoot.getRootDir(baseDir);\n\n            nodeModulesDir = nodePath.join(baseDir, 'node_modules');\n        }\n\n        function checkDir(dependency) {\n            if (!baseDir) {\n                return false;\n            }\n\n            const dir = dependency.getDir(lassoContext);\n            if (!dir) {\n                return false;\n            }\n\n            return dir.startsWith(baseDir) && !dir.startsWith(nodeModulesDir);\n        }\n\n        return {\n            shouldIncludeDependency: function(dependency) {\n                return checkDir(dependency);\n            },\n\n            shouldRecurseIntoPackageDependency: function(dependency) {\n                return checkDir(dependency);\n            }\n        };\n    }\n};\n\nfunction shouldIncludeDependency (lassoContext, rootDependency, recurseHandler, dependency) {\n    if (dependency === rootDependency ||\n            (lassoContext.parentDependency && lassoContext.parentDependency === rootDependency)) {\n        // Always include the root dependency or any child dependencies if the top-level\n        // dependency was a package\n        return true;\n    }\n\n    return recurseHandler.shouldIncludeDependency(dependency);\n}\n\nfunction shouldRecurseIntoPackageDependency (rootDependency, recurseHandler, dependency) {\n    if (dependency === rootDependency) {\n        // Always recurse into top-level package dependencies\n        return true;\n    }\n\n    return recurseHandler.shouldRecurseIntoPackageDependency(dependency);\n}\n\nasync function buildBundle(bundleMappings, dependencyRegistry, bundleConfig, lassoContext) {\n    const tree = logger.isDebugEnabled() ? new DependencyTree() : null;\n    const flags = lassoContext.flags;\n\n    const bundleDependencies = bundleConfig.getDependencies(dependencyRegistry);\n    const targetBundleName = bundleConfig.name;\n\n    // Each bundle should have its own phase data. Phase data is just a bucket of data that can\n    // be used by dependency handlers to keep track of what has been done for the current \"phase\"\n    // of optimization.\n    lassoContext.setPhase('app-bundle-mappings');\n\n    const dependencies = await bundleDependencies.normalize();\n\n    for (const rootDependency of dependencies) {\n        await rootDependency.init(lassoContext);\n\n        logger.debug('Root init');\n\n        let recurseInto = rootDependency._recurseInto || bundleConfig.getRecurseInto();\n\n        if (!recurseInto) {\n            if (rootDependency.getDir()) {\n                recurseInto = 'dirtree';\n            } else {\n                recurseInto = 'all';\n            }\n        }\n\n        if (!recurseHandlers[recurseInto]) {\n            throw new Error('Invalid recursion option: ' + recurseInto);\n        }\n\n        const recurseHandler = recurseHandlers[recurseInto](rootDependency, lassoContext);\n\n        await dependencyWalker.walk({\n            lassoContext,\n            dependency: rootDependency,\n            flags,\n            shouldSkipDependency (dependency) {\n                if (dependency.isPageBundleOnlyDependency()) {\n                    return true;\n                }\n\n                if (bundleMappings.getBundleForDependency(dependency)) {\n                    // The dependency has already been added to another bundle\n                    return true;\n                }\n\n                if (dependency.isPackageDependency()) {\n                    return !shouldRecurseIntoPackageDependency(rootDependency, recurseHandler, dependency);\n                } else if (!dependency.read) {\n                    // ignore non-readable dependencies during bundling phase\n                    return true;\n                }\n\n                return false;\n            },\n            on: {\n                dependency (dependency, context) {\n                    logger.debug(module.id, 'on dependency: ' + dependency.type);\n\n                    if (dependency.isPackageDependency()) {\n                        if (tree) {\n                            tree.add(dependency, context.parentDependency);\n                        }\n\n                        // We are only interested in non-package dependencies\n                        return;\n                    }\n\n                    if (shouldIncludeDependency(lassoContext, rootDependency, recurseHandler, dependency)) {\n                        bundleMappings.addDependencyToBundle(\n                            dependency,\n                            targetBundleName,\n                            context.slot,\n                            bundleConfig,\n                            lassoContext);\n\n                        if (tree) {\n                            tree.add(dependency, context.parentDependency);\n                        }\n                    }\n                }\n            }\n        });\n    }\n\n    if (tree) {\n        logger.debug('Bundle \"' + targetBundleName + '\":\\n' + tree.toString());\n    }\n}\n\nexports.buildBundle = buildBundle;\n"
  },
  {
    "path": "src/bundling-strategies.js",
    "content": "const logger = require('raptor-logging').logger(module);\n\nmodule.exports = {\n    default: function(options, config, bundleMappings, pageBundles) {\n        const pageName = options.name || options.pageName;\n        const pageBundleName = pageName;\n        const asyncPageBundleName = pageBundleName + '-async';\n\n        return {\n            getBundleForSyncDependency: function(dependency, walkContext, debugTree) {\n                const lassoContext = walkContext.lassoContext;\n\n                const infoEnabled = logger.isInfoEnabled();\n                let bundleMapping = bundleMappings.getBundleMappingForDependency(dependency);\n\n                if (bundleMapping && bundleMapping.bundle.isAsyncOnly()) {\n                    if (infoEnabled) {\n                        logger.info('Removing dependency ' + dependency + ' from bundle ' + bundleMapping.bundle);\n                    }\n\n                    // surgically remove the bundle from its existing mapping so that it can be\n                    // rebundled into a page bundle\n                    bundleMappings.removeBundleMapping(bundleMapping);\n                    bundleMapping = null;\n                }\n\n                let bundle;\n\n                // Has this dependency been mapped into a bundle and is the bundle willing to accept\n                // non-asynchronous dependencies?\n                if (bundleMapping) {\n                    if (infoEnabled) {\n                        logger.info('Dependency ' + dependency + ' already mapped to bundle ' + bundleMapping.bundle);\n                    }\n\n                    // pull the bundle out of the bundle mapping\n                    bundle = bundleMapping.bundle;\n                } else {\n                    if (infoEnabled) {\n                        logger.info('Dependency ' + dependency + ' is not mapped to a bundle');\n                    }\n\n                    // either the dependency was not configured to fall into a bundle\n                    // or the bundle that it could have gone into is only for asynchronous\n                    // dependencies. Either way, we need to go ahead and add a new page\n                    // bundle for this dependency.\n                    bundle = bundleMappings.addDependencyToPageBundle(\n                        dependency,\n                        pageBundleName,\n                        walkContext.slot,\n                        null,\n                        lassoContext);\n                }\n\n                if (debugTree) {\n                    debugTree.addToBundle(bundle, dependency, walkContext.parentDependency);\n                }\n\n                return bundle;\n            },\n\n            getBundleForAsyncDependency: function(dependency, walkContext, debugTree) {\n                const lassoContext = walkContext.lassoContext;\n\n                let bundle = bundleMappings.getBundleForDependency(dependency);\n                if (bundle) {\n                    if (pageBundles.lookupSyncBundle(bundle)) {\n                        // This dependency has already been bundled with the page synchronously\n                        // so don't return a new async bundle.\n                        // Return null to indicate that this dependency does not belong\n                        // to an async bundle.\n                        return null;\n                    }\n                } else {\n                    // Create a new bundle for the dependency if one does not exist\n                    bundle = bundleMappings.addDependencyToPageBundle(\n                        dependency,\n                        asyncPageBundleName,\n                        walkContext.slot,\n                        null,\n                        lassoContext);\n                }\n\n                if (debugTree) {\n                    debugTree.addToBundle(bundle, dependency, walkContext.parentDependency);\n                }\n\n                return bundle;\n            }\n        };\n    },\n\n    lean: function(options, config, bundleMappings, pageBundles) {\n        const BundleMappings = require('./BundleMappings');\n        const pageName = options.name || options.pageName;\n        const pageBundleName = pageName;\n        const asyncPageBundleName = pageBundleName + '-async';\n        const pageBundleMappings = new BundleMappings(config, pageName);\n\n        return {\n            getBundleForSyncDependency: function(dependency, walkContext, debugTree) {\n                const lassoContext = walkContext.lassoContext;\n\n                // find the bundle that was configured for dependency\n                const bundleMapping = bundleMappings.getBundleMappingForDependency(dependency);\n\n                let bundle;\n\n                if (bundleMapping && !bundleMapping.bundle.isAsyncOnly()) {\n                    bundle = pageBundleMappings.addDependencyToPageBundle(\n                        dependency,\n                        bundleMapping.bundle.getName(),\n                        walkContext.slot,\n                        bundleMapping.bundle.getConfig(),\n                        lassoContext);\n                } else {\n                    bundle = pageBundleMappings.addDependencyToPageBundle(\n                        dependency,\n                        pageBundleName,\n                        walkContext.slot,\n                        null,\n                        lassoContext);\n                }\n\n                if (debugTree) {\n                    debugTree.addToBundle(bundle, dependency, walkContext.parentDependency);\n                }\n\n                return bundle;\n            },\n\n            getBundleForAsyncDependency: function(dependency, walkContext, debugTree) {\n                const lassoContext = walkContext.lassoContext;\n                let bundle = pageBundleMappings.getBundleForDependency(dependency);\n                if (bundle) {\n                    if (pageBundles.lookupSyncBundle(bundle)) {\n                        // This dependency has already been bundled with the page synchronously\n                        // so don't add it to an async bundle.\n                        // Return null to indicate that this dependency does not belong\n                        // to an async bundle.\n                        return null;\n                    }\n                } else {\n                    // this dependency has not been bundled yet\n                    const bundleMapping = bundleMappings.getBundleMappingForDependency(dependency);\n                    if (bundleMapping) {\n                        // this dependency has been mapped into a bundle\n                        const bundleName = bundleMapping.bundle.isAsyncOnly() ? bundleMapping.bundle.getName() : bundleMapping.bundle.getName() + '-async';\n                        bundle = pageBundleMappings.addDependencyToPageBundle(\n                            dependency,\n                            bundleName,\n                            walkContext.slot,\n                            bundleMapping.bundle.getConfig(),\n                            lassoContext);\n                    } else {\n                        bundle = pageBundleMappings.addDependencyToPageBundle(\n                            dependency,\n                            asyncPageBundleName,\n                            walkContext.slot,\n                            null,\n                            lassoContext);\n                    }\n\n                    if (debugTree) {\n                        debugTree.addToBundle(bundle, dependency, walkContext.parentDependency);\n                    }\n                }\n\n                return bundle;\n            }\n        };\n    }\n};\n"
  },
  {
    "path": "src/caching-fs.js",
    "content": "module.exports = require('lasso-caching-fs');\n"
  },
  {
    "path": "src/condition.js",
    "content": "exports.ifCondition = function(condition) {\n    // This is a hack because we moved from \"flags\" to \"extensions\"\n    // We create a function that introduces two scoped variables: flags, extensions\n    const conditionFunc = eval('(function(flags, extensions) { return ' + condition + ';})');\n\n    return function(flags) {\n        return conditionFunc(flags, flags);\n    };\n};\n\nexports.ifFlag = function(flag) {\n    return function(flags) {\n        return flags.contains(flag);\n    };\n};\n\nexports.ifNotFlag = function(flag) {\n    return function(flags) {\n        return !flags.contains(flag);\n    };\n};\n\nexports.fromObject = function(o) {\n    let condition;\n\n    if ((condition = o.if)) {\n        return exports.ifCondition(condition);\n    } else if ((condition = o['if-flag'] || o['if-extension'])) {\n        return exports.ifFlag(condition);\n    } else if ((condition = o['if-not-flag'] || o['if-not-extension'])) {\n        return exports.ifNotFlag(condition);\n    }\n\n    return null;\n};\n"
  },
  {
    "path": "src/config-loader.js",
    "content": "const Config = require('./Config');\nconst BundleSetConfig = require('./BundleSetConfig');\nconst BundleConfig = require('./BundleConfig');\nconst nodePath = require('path');\nconst fileWriterFactory = require('./writers/file-writer');\nconst fs = require('fs');\nconst ok = require('assert').ok;\nconst propertyHandlers = require('property-handlers');\nconst minifyJSPlugin = require('./plugins/lasso-minify-js');\nconst minifyCSSPlugin = require('./plugins/lasso-minify-css');\nconst resolveCssUrlsPlugin = require('./plugins/lasso-resolve-css-urls');\nconst extend = require('raptor-util/extend');\nconst resolveFrom = require('resolve-from');\nconst complain = require('complain');\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction findRootDir(dirname) {\n    if (dirname === '' || dirname === '/') {\n        return null;\n    }\n\n    const packagePath = nodePath.join(dirname, 'package.json');\n\n    if (dirname.indexOf('node_modules') === -1 && fs.existsSync(packagePath)) {\n        return dirname;\n    }\n\n    const parentDirname = nodePath.dirname(dirname);\n\n    if (parentDirname !== dirname) {\n        return findRootDir(parentDirname);\n    } else {\n        return null;\n    }\n}\n\nfunction load(options, baseDir, filename, configDefaults) {\n    /* jshint loopfunc:true */\n\n    ok(baseDir, '\"baseDir\" argument is required');\n\n    function getProjectRootDir(dirname) {\n        let rootDir = findRootDir(dirname);\n        if (!rootDir) {\n            rootDir = baseDir;\n        }\n\n        return rootDir;\n    }\n\n    if (!options || typeof options !== 'object') {\n        throw new Error('Invalid options. Object expected');\n    }\n\n    if (options.fileWriter) {\n        // Move fileWriter properties to the root\n        extend(options, options.fileWriter);\n        delete options.fileWriter;\n    }\n\n    if (configDefaults) {\n        for (const key in configDefaults) {\n            // copy defaults to options only if options doesn't already\n            // have that property\n            if (hasOwn.call(configDefaults, key) && !hasOwn.call(options, key)) {\n                options[key] = configDefaults[key];\n            }\n        }\n    }\n\n    const config = new Config();\n\n    config.rawConfig = options;\n\n    const fileWriterConfig = {};\n\n    function addBundles(bundleSetName, bundles) {\n        const bundleSetConfig = new BundleSetConfig(bundleSetName);\n        bundles.forEach(function(bundle) {\n            const bundleConfig = new BundleConfig(baseDir, filename);\n            bundleConfig.name = bundle.name;\n            bundleConfig.asyncOnly = bundle.asyncOnly;\n\n            if (bundle.recursive !== undefined) {\n                bundleConfig.recurseInto = (bundle.recursive === true) ? 'all' : 'none';\n            }\n\n            if (bundle.dependencies) {\n                bundle.dependencies.forEach(function(d) {\n                    // \"recursive\" is not an allowed dependency\n                    // property but we need this property to determine\n                    // how to build the bundle. Prefixing with an\n                    // underscore allows the property to go through\n                    if (d.recursive === true) {\n                        d.recurseInto = 'all';\n                    } else if (d.recursive === false) {\n                        d.recurseInto = 'none';\n                    }\n\n                    d._recurseInto = d.recurseInto;\n                    delete d.recursive;\n                    delete d.recurseInto;\n                });\n            }\n            bundleConfig.addDependencies(bundle.dependencies);\n            bundleSetConfig.addBundleConfig(bundleConfig);\n        });\n        config.addBundleSetConfig(bundleSetConfig);\n    }\n\n    const handlers = {\n\n        require: function(value) {\n            if (value) {\n                extend(config._requirePluginConfig, value);\n            }\n        },\n\n        minify: function(value) {\n            if (value) {\n                config.addPlugin(minifyJSPlugin, config._minifyJSPluginConfig);\n                config.addPlugin(minifyCSSPlugin, config._minifyCSSPluginConfig);\n            }\n        },\n\n        minifyJS: function(value) {\n            if (value) {\n                config.addPlugin(minifyJSPlugin, config._minifyJSPluginConfig);\n            }\n        },\n\n        minifyCSS: function(value) {\n            if (value) {\n                config.addPlugin(minifyCSSPlugin, config._minifyCSSPluginConfig);\n            }\n        },\n\n        minifyInlineOnly: function(value) {\n            if (value) {\n                config.addPlugin(minifyJSPlugin, config._minifyJSPluginConfig);\n                config.addPlugin(minifyCSSPlugin, config._minifyCSSPluginConfig);\n\n                config._minifyJSPluginConfig.inlineOnly = true;\n                config._minifyCSSPluginConfig.inlineOnly = true;\n            }\n        },\n\n        minifyInlineJSOnly: function(value) {\n            if (value) {\n                config.addPlugin(minifyJSPlugin, config._minifyJSPluginConfig);\n                config._minifyJSPluginConfig.inlineOnly = true;\n            }\n        },\n\n        minifyInlineCSSOnly: function(value) {\n            if (value) {\n                config.addPlugin(minifyCSSPlugin, config._minifyCSSPluginConfig);\n                config._minifyCSSPluginConfig.inlineOnly = true;\n            }\n        },\n\n        resolveCssUrls: function(value) {\n            if (value) {\n                // the value can be a plugin config or a truthy value\n                if (value === true) {\n                    // value is a boolean so no config was provided so use an empty object\n                    value = {};\n                }\n                config.addPlugin(resolveCssUrlsPlugin, value);\n            }\n        },\n\n        relativeUrlsEnabled: function(value) {\n            fileWriterConfig.relativeUrlsEnabled = value === true;\n        },\n\n        bundlingEnabled: function(value) {\n            config.setBundlingEnabled(value === true);\n        },\n\n        bundlingStrategy: function(value) {\n            config.setBundlingStrategy(value);\n        },\n\n        fingerprintsEnabled: function(value) {\n            fileWriterConfig.fingerprintsEnabled = value === true;\n        },\n\n        outputDir: function(value) {\n            value = nodePath.resolve(baseDir, value);\n            fileWriterConfig.outputDir = value;\n        },\n\n        urlPrefix: function(value) {\n            fileWriterConfig.urlPrefix = value;\n        },\n\n        includeSlotNames: function(value) {\n            fileWriterConfig.includeSlotNames = value === true;\n        },\n\n        fingerprintLength: function(value) {\n            fileWriterConfig.fingerprintLength = value;\n        },\n\n        flags: function(flags) {\n            config.setFlags(flags);\n        },\n\n        /**\n         * @deprecated\n         */\n        extensions (flags) {\n            complain('\"configLoader.extensions(...)\" is deprecated. Please use \"configLoader.flags(...)\" instead.');\n            config.setFlags(flags);\n        },\n\n        /**\n         * @deprecated\n         */\n        enabledExtensions (flags) {\n            complain('\"configLoader.enabledExtensions(...)\" is deprecated. Please use \"configLoader.flags(...)\" instead.');\n            config.setFlags(flags);\n        },\n\n        bundles: function(bundles) {\n            if (bundles) {\n                addBundles('default', bundles);\n            }\n        },\n\n        inPlaceDeploymentEnabled: function(value) {\n            config.setInPlaceDeploymentEnabled(value === true);\n        },\n\n        inPlaceDeployment: function(inPlaceDeploymentOptions) {\n            if (typeof inPlaceDeploymentOptions === 'boolean') {\n                config.setInPlaceDeploymentEnabled(inPlaceDeploymentOptions === true);\n            } else {\n                propertyHandlers(inPlaceDeploymentOptions, {\n                    enabled: function(value) {\n                        config.setInPlaceDeploymentEnabled(value === true);\n                    },\n\n                    urlPrefix: function(value) {\n                        config.setInPlaceUrlPrefix(value);\n                    }\n                }, 'config.inPlaceDeployment');\n            }\n        },\n\n        plugins: function(value) {\n            if (value != null) {\n                if (!Array.isArray(value)) {\n                    value = Object.keys(value).map(function(moduleName) {\n                        const pluginConfig = value[moduleName];\n                        return {\n                            plugin: moduleName,\n                            config: pluginConfig\n                        };\n                    });\n                }\n\n                for (let i = 0; i < value.length; i++) {\n                    let pluginInfo = value[i];\n\n                    if (typeof pluginInfo === 'string' || typeof pluginInfo === 'function') {\n                        pluginInfo = {\n                            plugin: pluginInfo,\n                            config: {}\n                        };\n                    }\n\n                    if (pluginInfo.plugin === 'lasso-minify-js') {\n                        extend(config._minifyJSPluginConfig, pluginInfo.config);\n                        continue;\n                    } else if (pluginInfo.plugin === 'lasso-minify-css') {\n                        extend(config._minifyCSSPluginConfig, pluginInfo.config);\n                        continue;\n                    }\n\n                    let pluginFunc = null;\n                    let pluginConfig = null;\n                    let enabled = true;\n\n                    propertyHandlers(pluginInfo, {\n                        plugin: function(plugin) {\n                            if (typeof plugin === 'string') {\n                                let resolvedPath = null;\n                                try {\n                                    resolvedPath = resolveFrom(baseDir, plugin);\n                                } catch (e2) {\n                                    throw new Error('Plugin module not found for \"' + plugin + '\". Searched from \"' + baseDir + '\"');\n                                }\n                                pluginFunc = require(resolvedPath);\n                            } else {\n                                pluginFunc = plugin;\n                            }\n                        },\n                        config: function(value) {\n                            pluginConfig = value;\n                        },\n                        enabled: function(value) {\n                            enabled = value;\n                        }\n                    }, 'config.plugins');\n\n                    pluginConfig = pluginConfig || {};\n\n                    if (enabled === false || pluginConfig.enabled === false) {\n                        continue;\n                    }\n\n                    config.addPlugin(pluginFunc, pluginConfig);\n                }\n            }\n        },\n\n        projectRoot: function(value) {\n            config.setProjectRoot(nodePath.resolve(baseDir, value));\n        },\n\n        cacheProfile: function(value) {\n            config.setCacheProfile(value);\n        },\n\n        cacheDir: function(value) {\n            config.setCacheDir(value);\n        },\n\n        cacheProfiles: function(value) {\n            config.setCacheProfiles(value);\n        },\n\n        bundleReadTimeout: function(value) {\n            config.setBundleReadTimeout(value);\n        },\n\n        /**\n        * Whether Lasso should load from a prebuild configuration or not\n        */\n        loadPrebuild (value) {\n            config.setLoadPrebuild(value);\n        },\n\n        resolver (value) {\n            config.setResolver(value);\n        },\n\n        noConflict: function(value) {\n            if (value) {\n                if (value.constructor !== String) {\n                    throw new Error('Value for \"noConflict\" should be a string that uniquely identifies your project');\n                }\n\n                // Build the variable name for the modules global\n                // (the lasso-require plugin will sanitize it by\n                // removing/replacing any illegal characters)\n                config.modulesRuntimeGlobal = config._requirePluginConfig.modulesRuntimeGlobal = '$_mod_' + value;\n\n                // The \"unbundledTargetPrefix\" is used to create sub-directory\n                // in the output folder for some of the lasso-require\n                // dependencies.\n                config._requirePluginConfig.unbundledTargetPrefix = value;\n            }\n        },\n\n        cspNonceProvider: function(value) {\n            if (typeof value !== 'function') {\n                throw new Error('\"cspNonceProvider\" should be a function');\n            }\n\n            config.setCSPNonceProvider(value);\n        },\n\n        fingerprintInlineCode: function(value) {\n            if (typeof value !== 'function') {\n                throw new Error('\"fingerprintInlineCode\" should be a function');\n            }\n\n            config.setFingerprintInlineCode(value);\n        },\n\n        cacheKey (value) {\n            config.setCacheKey(value);\n        }\n    };\n\n    propertyHandlers(options, handlers, 'config');\n\n    config.fileWriterConfig = fileWriterConfig;\n    config.writer = fileWriterFactory(fileWriterConfig, config);\n\n    if (!config.getProjectRoot()) {\n        config.setProjectRoot(getProjectRootDir(baseDir));\n    }\n\n    return config;\n}\n\nexports.load = load;\n"
  },
  {
    "path": "src/content-types.js",
    "content": "exports.CSS = 'css';\nexports.JS = 'js';\nexports.NONE = 'none';\n"
  },
  {
    "path": "src/dependencies/Dependency.js",
    "content": "const nodePath = require('path');\nconst condition = require('../condition');\n\nconst CONTENT_TYPE_CSS = require('../content-types').CSS;\nconst CONTENT_TYPE_JS = require('../content-types').JS;\nconst CONTENT_TYPE_NONE = require('../content-types').NONE;\nconst util = require('../util');\nconst ok = require('assert').ok;\nconst equal = require('assert').equal;\nconst Readable = require('stream').Readable;\nconst manifestLoader = require('../manifest-loader');\nconst logger = require('raptor-logging').logger(module);\nconst lastModified = require('../last-modified');\nconst AsyncValue = require('raptor-async/AsyncValue');\nconst EventEmitter = require('events').EventEmitter;\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nconst NON_KEY_PROPERTIES = {\n    inline: true,\n    slot: true,\n    'js-slot': true,\n    'css-slot': true,\n    getDefaultBundleName: true\n};\n\nfunction getPackagePath(d) {\n    return d.__filename ? d.__filename : '(unknown)';\n}\n\nfunction doCalculateFingerprint (dependency, lassoContext) {\n    return new Promise((resolve, reject) => {\n        const input = dependency.read(lassoContext);\n        const cachingReadStream = util.createCachingStream();\n\n        const fingerprintStream = util.createFingerprintStream()\n            .on('error', reject)\n            .on('fingerprint', function(fingerprint) {\n                dependency._cachingReadStream = cachingReadStream;\n                if (logger.isDebugEnabled()) {\n                    logger.debug('Dependency ' + dependency.toString() + ' fingerprint key: ' + fingerprint);\n                }\n                resolve(fingerprint);\n            });\n\n        // Don't buffer the data so that the stream can be drained\n        fingerprintStream.resume();\n\n        input\n            .on('error', function(e) {\n                let message = 'Unable to read dependency \"' + dependency + '\" referenced in \"' + dependency.getParentManifestPath() + '\". ';\n                if (e.code === 'ENOENT' && e.path) {\n                    message += 'File does not exist: ' + e.path;\n                } else {\n                    message += 'Error: ' + (e.stack || e);\n                }\n                e = new Error(message);\n                e.dependency = dependency;\n                reject(e);\n            })\n            .pipe(cachingReadStream)\n            .pipe(fingerprintStream);\n    });\n};\n\n// This is a simple stream implementation that either has code available\n// immediately or it is waiting for code to be made available upon\n// callback completion\nfunction DependencyReadable() {\n\n}\n\nrequire('util').inherits(DependencyReadable, Readable);\n\nDependencyReadable.prototype._read = function() {\n    // don't need to actually implement _read because\n};\n\nfunction Dependency(dependencyConfig, dirname, filename) {\n    ok(dependencyConfig != null, '\"dependencyConfig\" is a required argument');\n    equal(typeof dependencyConfig, 'object', '\"dependencyConfig\" should be an object');\n\n    ok(dirname, '\"dirname\" is a required argument');\n    equal(typeof dirname, 'string', '\"dirname\" should be a string');\n\n    this._resolvedInit = undefined;\n    this._keyAsyncValue = undefined;\n    this._lastModifiedAsyncValue = undefined;\n    this._cachingReadStream = undefined;\n\n    // The directory associated with this dependency.\n    // If the dependency was defined in an browser.json\n    // file then the directory is the directory in which\n    // browser.json is found.\n    this.__dirname = dirname;\n    this.__filename = filename;\n\n    this.type = dependencyConfig.type;\n\n    this._condition = condition.fromObject(dependencyConfig);\n    this._events = undefined;\n\n    this.set(dependencyConfig);\n}\n\nDependency.prototype = {\n    __Dependency: true,\n\n    properties: {\n        type: 'string',\n        attributes: 'object',\n        inline: 'string',\n        slot: 'string',\n        'css-slot': 'string',\n        'js-slot': 'string',\n        // TODO: Change: Should these be removed?\n        if: 'string',\n        'if-extension': 'string', /* DEPRECRATED */\n        'if-not-extension': 'string', /* DEPRECRATED */\n        'if-flag': 'string',\n        'if-not-flag': 'string',\n        getDefaultBundleName: 'function'\n    },\n\n    async init (lassoContext) {\n        this._context = lassoContext;\n\n        if (this._resolvedInit) {\n            return;\n        }\n\n        await this.doInit(lassoContext);\n        this._resolvedInit = true;\n    },\n\n    async doInit (lassoContext) {},\n\n    createReadStream: function(lassoContext) {\n        if (this._cachingReadStream) {\n            return this._cachingReadStream.createReplayStream();\n        }\n\n        return this.doRead(lassoContext);\n    },\n\n    /**\n     *\n     * @deprecated use createReadStream instead\n     */\n    read: function(lassoContext) {\n        return this.createReadStream(lassoContext);\n    },\n\n    set: function(props) {\n        const propertyTypes = this.properties;\n\n        for (const k in props) {\n            if (hasOwn.call(props, k)) {\n                let v = props[k];\n\n                if (propertyTypes) {\n                    const type = propertyTypes[k];\n                    if (!type && !k.startsWith('_')) {\n                        throw new Error('Dependency of type \"' + this.type + '\" does not support property \"' + k + '\". Package: ' + getPackagePath(this));\n                    }\n\n                    if (type && typeof v === 'string') {\n                        if (type === 'boolean') {\n                            v = (v === 'true');\n                        } else if (type === 'int' || type === 'integer') {\n                            v = parseInt(v, 10);\n                        } else if (type === 'float' || type === 'number') {\n                            v = parseFloat(v);\n                        } else if (type === 'path') {\n                            v = this.resolvePath(v);\n                        }\n                    }\n                }\n\n                this[k] = v;\n            }\n        }\n    },\n\n    /*\n     * This resolve method will use the module search path to resolve\n     * the given path if the path does not begin with \".\" or \"/\".\n     *\n     * For example, dependency.resolvePath('some-module/a.js')\n     * will use the NodeJS module search path starting from this dependencies directory.\n     * If resolution fails using the NodeJS module search path, then an attempt\n     * will be made to resolve the path as a relative path.\n     *\n     * dependency.resolvePath('./a.js') we be resolved relative to the\n     * directory of this dependency.\n     *\n     * dependency.resolvePath('/a.js') is assumed to be absolute\n     * (possibly because it was already resolved).\n     */\n    resolvePath: function(path, from) {\n        const result = this._context.resolve(path, from || this.__dirname, {\n            moduleFallbackToRelative: true\n        });\n        return result && result.path;\n    },\n\n    getParentManifestDir: function() {\n        return this.__dirname;\n    },\n\n    getParentManifestPath: function() {\n        return this.__filename;\n    },\n\n    isPackageDependency: function() {\n        return this._packageDependency === true;\n    },\n\n    /**\n     * This method is called to determine if a depednency can be added to a shared\n     * application bundle or if it can only be added to a page bundle.\n     * This method can be overridden, but the default behavior is to return\n     * false to indicate that it can be added to either a shared application\n     * bundle or a page-specific bundle.\n     * @return {boolean} Returns true if this is a page-bundle only dependency. False, otherwise.s\n     */\n    isPageBundleOnlyDependency: function() {\n        return false;\n    },\n\n    onAddToPageBundle: function(bundle, lassoContext) {\n        // subclasses can override\n    },\n\n    onAddToAsyncPageBundle: function(bundle, lassoContext) {\n        // subclasses can override\n    },\n\n    async getPackageManifest (lassoContext) {\n        if (!this.isPackageDependency()) {\n            throw new Error('getPackageManifest() failed. Dependency is not a package: ' + this.toString());\n        }\n\n        let manifest;\n\n        if (typeof this.loadPackageManifest === 'function') {\n            const packageManifestResult = await this.loadPackageManifest(lassoContext);\n\n            if (!packageManifestResult) {\n                return null;\n            }\n\n            const dependencyRegistry = this.__dependencyRegistry;\n            const LassoManifest = require('../LassoManifest');\n\n            if (typeof packageManifestResult === 'string') {\n                const manifestPath = packageManifestResult;\n                const from = this.getParentManifestDir();\n\n                try {\n                    manifest = this.createPackageManifest(manifestLoader.load(manifestPath, from));\n                } catch (e) {\n                    let err;\n                    if (e.fileNotFound) {\n                        err = new Error('Lasso manifest not found for path \"' +\n                            manifestPath + '\" (searching from \"' + from + '\"). Dependency: ' +\n                            this.toString());\n                    } else {\n                        err = new Error('Unable to load lasso manifest for path \"' +\n                            manifestPath + '\". Dependency: ' + this.toString() + '. Exception: ' +\n                            (e.stack || e));\n                    }\n\n                    throw err;\n                }\n            } else if (!LassoManifest.isLassoManifest(packageManifestResult)) {\n                manifest = new LassoManifest({\n                    manifest: packageManifestResult,\n                    dependencyRegistry,\n                    dirname: this.getParentManifestDir(),\n                    filename: this.getParentManifestPath()\n                });\n            } else {\n                manifest = packageManifestResult;\n            }\n\n            return manifest;\n        } else if (typeof this.getDependencies === 'function') {\n            const dependencies = await this.getDependencies(lassoContext);\n            if (dependencies) {\n                manifest = this.createPackageManifest(dependencies);\n            }\n\n            return manifest;\n        } else {\n            throw new Error('getPackageManifest() failed. \"getDependencies\" or \"loadPackageManifest\" expected: ' + this.toString());\n        }\n    },\n\n    _getKeyPropertyNames: function() {\n        return Object.keys(this)\n            .filter(function(k) {\n                return !k.startsWith('_') && k !== 'type' && !hasOwn.call(NON_KEY_PROPERTIES, k);\n            }, this)\n            .sort();\n    },\n\n    getKey: function() {\n        if (!this._keyAsyncValue || !this._keyAsyncValue.isResolved()) {\n            return null;\n            // throw new Error('getKey() was called before key was calculated');\n        }\n        return this._keyAsyncValue.data;\n    },\n\n    /**\n     * getReadCacheKey() must be a unique key across all lasso context since\n     * it is flattened to single level and shared by multiple lasso instances.\n     */\n    getReadCacheKey: function() {\n        return this.getPropsKey();\n    },\n\n    getPropsKey: function() {\n        return this._propsKey || (this._propsKey = this.calculateKeyFromProps());\n    },\n\n    /**\n     * calculateKey() is used to calculate a unique key for this dependency\n     * that is unique within the given lasso context.\n     *\n     * getReadCacheKey() must be a unique key across all lasso context since\n     * it is flattened to single level and shared by multiple lasso instances.\n     */\n    calculateKey (lassoContext) {\n        // TODO: Change to fully use async/await\n        return new Promise((resolve, reject) => {\n            function callback (err, res) {\n                return err ? reject(err) : resolve(res);\n            }\n\n            if (this._key !== undefined) {\n                return callback(null, this._key);\n            }\n\n            if (this._keyAsyncValue) {\n                // Attach a listener to the current in-progres check\n                return this._keyAsyncValue.done(callback);\n            }\n\n            // no data holder so let's create one\n            let keyAsyncValue;\n            this._keyAsyncValue = keyAsyncValue = new AsyncValue();\n            this._keyAsyncValue.done(callback);\n\n            const handleKey = (key) => {\n                if (key === null) {\n                    key = this.type + '|' + lassoContext.uniqueId();\n                } else if (typeof key !== 'string') {\n                    keyAsyncValue.reject(new Error('Invalid key: ' + key));\n                    return;\n                }\n\n                if (logger.isDebugEnabled()) {\n                    logger.debug('Calculated key for ' + this.toString() + ': ' + key);\n                }\n\n                // Store resolve key in \"_key\" for quick lookup\n                this._key = key;\n                keyAsyncValue.resolve(key);\n            };\n\n            const keyResult = this.doCalculateKey(lassoContext);\n\n            if ((typeof keyResult === 'string') && !keyAsyncValue.isSettled()) {\n                handleKey(keyResult);\n            } else if (keyResult && typeof keyResult === 'object' && keyResult.then) {\n                keyResult\n                    .then((key) => {\n                        handleKey(key);\n                    })\n                    .catch((err) => {\n                        keyAsyncValue.reject(err);\n                    });\n            } else {\n                return handleKey(keyResult);\n            }\n        });\n    },\n\n    doCalculateKey (lassoContext) {\n        if (this.isPackageDependency()) {\n            return this.calculateKeyFromProps();\n        } else if (this.isExternalResource()) {\n            const url = this.getUrl ? this.getUrl(lassoContext) : this.url;\n            return url;\n        } else {\n            if (lassoContext.cache) {\n                return this.getLastModified(lassoContext)\n                    .then((lastModified) => {\n                        if (!lastModified) {\n                            return doCalculateFingerprint(this, lassoContext);\n                        }\n\n                        return lassoContext.cache.getDependencyFingerprint(\n                            // cache key\n                            this.getPropsKey(),\n                            // last modified timestamp (if cache entry is older than this then builder will be called)\n                            lastModified,\n                            // builder\n                            doCalculateFingerprint.bind(null, this, lassoContext));\n                    });\n            } else {\n                return doCalculateFingerprint(this, lassoContext);\n            }\n        }\n    },\n\n    calculateKeyFromProps: function() {\n        const key = this._getKeyPropertyNames()\n            .map(function(k) {\n                return k + '=' + this[k];\n            }, this)\n            .join('|');\n\n        return this.type + '|' + key;\n    },\n\n    hasContent: function() {\n        return this.contentType !== CONTENT_TYPE_NONE;\n    },\n\n    isJavaScript: function() {\n        return this.contentType === CONTENT_TYPE_JS;\n    },\n\n    isStyleSheet: function() {\n        return this.contentType === CONTENT_TYPE_CSS;\n    },\n\n    getSlot: function() {\n        if (this.slot) {\n            return this.slot;\n        }\n\n        if (this.isStyleSheet()) {\n            return this.getStyleSheetSlot();\n        } else {\n            return this.getJavaScriptSlot();\n        }\n    },\n\n    hasModifiedFingerprint: function() {\n        return false;\n    },\n\n    getContentType: function() {\n        return this.contentType;\n    },\n\n    isCompiled: function() {\n        return false;\n    },\n\n    isInPlaceDeploymentAllowed: function() {\n        return this.type === 'js' || this.type === 'css';\n    },\n\n    isExternalResource: function() {\n        return false;\n    },\n\n    getJavaScriptSlot: function() {\n        return this['js-slot'] || this.slot;\n    },\n\n    getStyleSheetSlot: function() {\n        return this['css-slot'] || this.slot;\n    },\n\n    async getLastModified (lassoContext) {\n        if (this._lastModifiedValue) {\n            return this._lastModifiedValue;\n        }\n\n        const getLastModified = (lastModified) =>\n            lastModified == null || lastModified < 0 ? 0 : lastModified;\n\n        const lastModified = this._lastModifiedValue =\n            getLastModified(await this.doGetLastModified(lassoContext));\n\n        return lastModified;\n    },\n\n    async doGetLastModified (lassoContext, callback) {\n        const sourceFile = this.getSourceFile();\n        if (sourceFile) {\n            return this.getFileLastModified(sourceFile);\n        } else {\n            return 0;\n        }\n    },\n\n    async getFileLastModified (path) {\n        return lastModified.forFile(path);\n    },\n\n    createPackageManifest: function(manifest, dirname, filename) {\n        const LassoManifest = require('../LassoManifest');\n\n        if (Array.isArray(manifest) || !manifest) {\n            manifest = {\n                dependencies: manifest || []\n            };\n        } else {\n            dirname = manifest.dirname;\n            filename = manifest.filename;\n        }\n\n        return new LassoManifest({\n            manifest,\n            dependencyRegistry: this.__dependencyRegistry,\n            dirname: dirname || this.getParentManifestDir(),\n            filename: filename || this.getParentManifestPath()\n        });\n    },\n\n    getDir: function() {\n        const sourceFile = this.getSourceFile();\n        // if (!sourceFile) {\n        //     throw new Error('Unable to determine directory that dependency is associated with because getSourceFile() returned null and getDir() is not implemented. Dependency: ' + this.toString());\n        // }\n        return (sourceFile) ? nodePath.dirname(sourceFile) : null;\n    },\n\n    getSourceFile: function() {\n        return null;\n    },\n\n    toString() {\n        const entries = [];\n        const type = this.type;\n\n        for (const k in this) {\n            if (hasOwn.call(this, k) && !k.startsWith('_') && k !== 'type') {\n                const v = this[k];\n                entries.push(k + '=' + JSON.stringify(v));\n            }\n        }\n\n        // var packagePath = this.getParentManifestPath();\n        // if (packagePath) {\n        //     entries.push('packageFile=\"' + packagePath + '\"');\n        // }\n\n        return '[' + type + (entries.length ? (': ' + entries.join(', ')) : '') + ']';\n    },\n\n    shouldCache: function(lassoContext) {\n        let cacheable = true;\n        let isStatic = false;\n\n        const cacheConfig = this.cacheConfig;\n        if (cacheConfig) {\n            cacheable = cacheConfig.cacheable !== false;\n            isStatic = cacheConfig.static === true;\n        } else {\n            cacheable = this.cache !== false;\n        }\n\n        if (isStatic) {\n            const transformer = lassoContext.transformer;\n            if (!transformer || transformer.hasTransforms() === false) {\n                // Don't bother caching a dependency if it is static and there are no transforms\n                return false;\n            }\n        }\n\n        return cacheable;\n    },\n\n    emit: function() {\n        if (!this._events) {\n            // No listeners\n            return;\n        }\n\n        return this._events.emit.apply(this._events, arguments);\n    },\n\n    on: function(event, listener) {\n        if (!this._events) {\n            this._events = new EventEmitter();\n        }\n\n        return this._events.on(event, listener);\n    },\n\n    once: function(event, listener) {\n        if (!this._events) {\n            this._events = new EventEmitter();\n        }\n\n        return this._events.once(event, listener);\n    },\n\n    removeListener: function(event, listener) {\n        if (!this._events) {\n            // Nothing to remove\n            return;\n        }\n\n        return this._events.removeListener.apply(this._events, arguments);\n    },\n\n    removeAllListeners: function(event) {\n        if (!this._events) {\n            // Nothing to remove\n            return;\n        }\n\n        return this._events.removeAllListeners.apply(this._events, arguments);\n    },\n\n    getDefaultBundleName: function(pageBundleName, lassoContext) {\n        return this.defaultBundleName;\n    },\n\n    inspect: function() {\n        const inspected = {\n            type: this.type\n        };\n\n        this._getKeyPropertyNames()\n            .forEach((k) => {\n                inspected[k] = this[k];\n            });\n\n        return inspected;\n    }\n};\n\nDependency.prototype.addListener = Dependency.prototype.on;\n\nmodule.exports = Dependency;\n"
  },
  {
    "path": "src/dependencies/DependencyRegistry.js",
    "content": "const nodePath = require('path');\nconst extend = require('raptor-util').extend;\nconst inherit = require('raptor-util').inherit;\nconst Dependency = require('./Dependency');\nconst CONTENT_TYPE_CSS = require('../content-types').CSS;\nconst CONTENT_TYPE_JS = require('../content-types').JS;\nconst ok = require('assert').ok;\nconst typePathRegExp = /^([A-Za-z0-9_\\-]{2,})\\s*:\\s*(.+)$/; // Hack: {2,} is used because Windows file system paths start with \"c:\\\"\nconst readStream = require('../util').readStream;\nconst RequireHandler = require('./RequireHandler');\nconst equal = require('assert').equal;\nconst globNormalizer = require('./glob').normalizer;\nconst dependencyResource = require('./dependency-resource');\nconst logger = require('raptor-logging').logger(module);\nconst slice = Array.prototype.slice;\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction createDefaultNormalizer(registry) {\n    function parsePath(path) {\n        const typePathMatches = typePathRegExp.exec(path);\n        if (typePathMatches) {\n            return {\n                type: typePathMatches[1],\n                path: typePathMatches[2]\n            };\n        } else {\n            let type = registry.typeForPath(path);\n\n            if (!type) {\n                type = 'package';\n            }\n\n            return {\n                type,\n                path\n            };\n        }\n    }\n\n    return function(dependency) {\n        if (typeof dependency === 'string') {\n            dependency = parsePath(dependency);\n        } else if (!Array.isArray(dependency)) {\n            dependency = Object.assign({}, dependency);\n\n            // the dependency doesn't have a type so try to infer it from the path\n            if (!dependency.type) {\n                if (dependency.package) {\n                    dependency.type = 'package';\n                    dependency.path = dependency.package;\n                    delete dependency.package;\n                } else if (dependency.path) {\n                    const parsed = parsePath(dependency.path);\n                    dependency.type = parsed.type;\n                    dependency.path = parsed.path;\n                } else if (dependency.intersection) {\n                    dependency.type = 'intersection';\n                    dependency.dependencies = dependency.intersection;\n                    delete dependency.intersection;\n                } else if (dependency.dependencies) {\n                    dependency.type = 'dependencies';\n                }\n            }\n        }\n        return dependency;\n    };\n}\n\nfunction DependencyRegistry() {\n    this.registeredTypes = {};\n    this.extensions = {};\n    this.requireExtensions = {};\n    this._normalizers = [];\n    this._finalNormalizers = [];\n\n    this.addNormalizer(createDefaultNormalizer(this));\n\n    this.registerDefaults();\n    this.requireExtensions = {};\n\n    this.requireExtensionNames = undefined;\n}\n\nDependencyRegistry.prototype = {\n    __DependencyRegistry: true,\n\n    registerDefaults: function() {\n        this.registerStyleSheetType('css', require('./dependency-resource'));\n        this.registerJavaScriptType('js', require('./dependency-resource'));\n        this.registerJavaScriptType('comment', require('./dependency-comment'));\n        this.registerPackageType('package', require('./dependency-package'));\n        this.registerPackageType('intersection', require('./dependency-intersection'));\n        this.registerPackageType('dependencies', require('./dependency-dependencies'));\n        this.registerExtension('browser.json', 'package');\n        this.registerExtension('optimizer.json', 'package');\n    },\n\n    typeForPath: function(path) {\n        // Find the type from the longest matching file extension.\n        // For example if we are trying to infer the type of \"jquery-1.8.3.js\" then we will try:\n        // a) \"8.3.js\"\n        // b) \"3.js\"\n        // c) \"js\"\n        path = nodePath.basename(path);\n\n        let type = this.extensions[path];\n\n        if (type) {\n            // This is to handle the case where the extension\n            // is the actual filename. For example: \"browser.json\"\n            return type;\n        }\n\n        let dotPos = path.indexOf('.');\n        if (dotPos === -1) {\n            return null;\n        }\n\n        do {\n            type = path.substring(dotPos + 1);\n            if (hasOwn.call(this.extensions, type)) {\n                return this.extensions[type];\n            }\n            // move to the next dot position\n            dotPos = path.indexOf('.', dotPos + 1);\n        }\n        while (dotPos !== -1);\n\n        const lastDot = path.lastIndexOf('.');\n        return path.substring(lastDot + 1);\n    },\n\n    addNormalizer: function(normalizerFunc) {\n        ok(typeof normalizerFunc === 'function', 'function expected');\n        this._normalizers.unshift(normalizerFunc);\n\n        // Always run the glob normalizer first\n        this._finalNormalizers = [globNormalizer].concat(this._normalizers);\n    },\n    registerType: function(type, mixins) {\n        equal(typeof type, 'string', '\"type\" should be a string');\n        equal(typeof mixins, 'object', '\"mixins\" should be a object');\n\n        const isPackageDependency = mixins._packageDependency === true;\n\n        const hasReadFunc = mixins.read;\n\n        if (isPackageDependency && hasReadFunc) {\n            throw new Error('Manifest dependency of type \"' + type + '\" is not expected to have a read() method.');\n        }\n\n        if (mixins.init) {\n            mixins.doInit = mixins.init;\n            delete mixins.init;\n        }\n\n        mixins = extend({}, mixins);\n\n        const properties = mixins.properties || {};\n        const childProperties = Object.create(Dependency.prototype.properties);\n        extend(childProperties, properties);\n        mixins.properties = childProperties;\n\n        const calculateKey = mixins.calculateKey;\n        if (calculateKey) {\n            mixins.doCalculateKey = calculateKey;\n            delete mixins.calculateKey;\n        }\n\n        const getLastModified = mixins.getLastModified || mixins.lastModified;\n        if (getLastModified) {\n            mixins.doGetLastModified = getLastModified;\n            delete mixins.getLastModified;\n            delete mixins.lastModified;\n        }\n\n        if (!isPackageDependency && mixins.read) {\n            // Wrap the read method to ensure that it always returns a stream\n            // instead of possibly using a callback\n            const oldRead = mixins.read;\n            delete mixins.read;\n\n            mixins.doRead = function(lassoContext) {\n                return readStream(() => {\n                    return oldRead.call(this, lassoContext);\n                });\n            };\n        }\n\n        const _this = this;\n\n        function Ctor(dependencyConfig, dirname, filename) {\n            this.__dependencyRegistry = _this;\n            Dependency.call(this, dependencyConfig, dirname, filename);\n        }\n\n        inherit(Ctor, Dependency);\n\n        extend(Ctor.prototype, mixins);\n\n        this.registeredTypes[type] = Ctor;\n    },\n\n    registerRequireExtension: function(ext, options) {\n        this.requireExtensionNames = undefined;\n\n        equal(typeof ext, 'string', '\"ext\" should be a string');\n\n        if (ext.charAt(0) === '.') {\n            ext = ext.substring(1);\n        }\n\n        if (typeof options === 'function') {\n            options = {\n                read: options\n            };\n        }\n\n        ok(options.read || options.createReadStream, '\"read\" or \"createReadStream\" is required');\n\n        this.requireExtensions[ext] = options;\n    },\n\n    /**\n     * In addition to registering a require extension using the \"registerRequireExtension\",\n     * this method also registers a new dependency type with possibly additional properties.\n     *\n     * For example, if you just use \"registerRequireExtension('foo', ...)\", then only the following is supported:\n     * - var foo = require('./hello.foo');\n     * - \"require: ./hello.foo\"\n     *\n     * However, if you use registerRequireType with custom proeprties then all of the following are supported:\n     * - var foo = require('./hello.foo');\n     * - \"require: ./hello.foo\"\n     * - \"hello.foo\",\n     * - { \"type\": \"foo\", \"path\": \"hello.foo\", \"hello\": \"world\" }\n     *\n     * For an example, please see:\n     * https://github.com/lasso-js/lasso-marko/blob/master/lasso-marko-plugin.js     *\n     *\n     * dependency that can be required. Howev\n     * @param {String} type   The extension/type to register\n     * @param {Object} mixins [description]\n     */\n    registerRequireType: function(type, options) {\n        equal(typeof type, 'string', '\"type\" should be a string');\n        equal(typeof options, 'object', '\"options\" should be a object');\n\n        const userRead = options.read;\n        const userCreateReadStream = options.createReadStream;\n        const userGetLastModified = options.getLastModified;\n\n        const extensionOptions = extend({}, options);\n\n        if (userRead) {\n            extensionOptions.read = function(path, lassoContext, callback) {\n                // Chop off the first path argument\n                return userRead.apply(this, slice.call(arguments, 1));\n            };\n        }\n\n        if (userCreateReadStream) {\n            extensionOptions.userCreateReadStream = function(path, lassoContext) {\n                // Chop off the first path argument\n                return userCreateReadStream.apply(this, slice.call(arguments, 1));\n            };\n        }\n\n        if (userGetLastModified) {\n            extensionOptions.getLastModified = async function (path, lassoContext) {\n                // Chop off the first path argument\n                return userGetLastModified.apply(this, slice.call(arguments, 1));\n            };\n        }\n\n        this.registerRequireExtension(type, extensionOptions);\n        this.registerPackageType(type, {\n            properties: {\n                path: 'string'\n            },\n            async init(lassoContext) {\n                this.path = this.resolvePath(this.path);\n            },\n            getSourceFile() {\n                return this.path;\n            },\n            async getDependencies (lassoContext) {\n                const path = this.path;\n                return [\n                    {\n                        type: 'require',\n                        path\n                    }\n                ];\n            }\n        });\n    },\n\n    getRequireExtensionNames() {\n        if (this.requireExtensionNames === undefined) {\n            const extensionsLookup = {};\n            // eslint-disable-next-line n/no-deprecated-api\n            const nodeRequireExtensions = require.extensions;\n            for (const ext in nodeRequireExtensions) {\n                if (ext !== '.node') {\n                    extensionsLookup[ext] = true;\n                }\n            }\n\n            for (let ext in this.requireExtensions) {\n                if (ext.charAt(0) !== '.') {\n                    ext = '.' + ext;\n                }\n                extensionsLookup[ext] = true;\n            }\n\n            this.requireExtensionNames = Object.keys(extensionsLookup);\n        }\n        return this.requireExtensionNames;\n    },\n\n    createRequireHandler(path, lassoContext, userOptions) {\n        ok(path, '\"path\" is required');\n        ok(lassoContext, '\"lassoContext\" is required');\n        ok(userOptions, '\"userOptions\" is required');\n\n        ok(typeof path === 'string', '\"path\" should be a string');\n        ok(typeof lassoContext === 'object', '\"lassoContext\" should be an object');\n\n        return new RequireHandler(userOptions, lassoContext, path);\n    },\n\n    getRequireHandler: function(path, lassoContext) {\n        ok(path, '\"path\" is required');\n        ok(lassoContext, '\"lassoContext\" is required');\n        ok(typeof path === 'string', '\"path\" should be a string');\n        ok(typeof lassoContext === 'object', '\"lassoContext\" should be an object');\n\n        const basename = nodePath.basename(path);\n        const lastDot = basename.lastIndexOf('.');\n        if (lastDot === -1) {\n            return null;\n        }\n\n        const ext = basename.substring(lastDot + 1);\n\n        const userOptions = this.requireExtensions[ext];\n        if (!userOptions) {\n            return null;\n        }\n\n        return new RequireHandler(userOptions, lassoContext, path);\n    },\n\n    registerJavaScriptType: function(type, mixins) {\n        equal(typeof type, 'string', '\"type\" should be a string');\n        equal(typeof mixins, 'object', '\"mixins\" should be a object');\n        mixins.contentType = CONTENT_TYPE_JS;\n        this.registerType(type, mixins);\n    },\n\n    registerStyleSheetType: function(type, mixins) {\n        equal(typeof type, 'string', '\"type\" should be a string');\n        equal(typeof mixins, 'object', '\"mixins\" should be a object');\n        mixins.contentType = CONTENT_TYPE_CSS;\n        this.registerType(type, mixins);\n    },\n\n    registerPackageType: function(type, mixins) {\n        equal(typeof type, 'string', '\"type\" should be a string');\n        equal(typeof mixins, 'object', '\"mixins\" should be a object');\n        mixins._packageDependency = true;\n        this.registerType(type, mixins);\n    },\n\n    registerExtension: function(extension, type) {\n        equal(typeof extension, 'string', '\"extension\" should be a string');\n        equal(typeof type, 'string', '\"type\" should be a string');\n        this.extensions[extension] = type;\n    },\n\n    getType: function(type) {\n        return this.registeredTypes[type];\n    },\n\n    createDependency: function(config, dirname, filename) {\n        ok(config, '\"config\" is required');\n        ok(dirname, '\"dirname\" is required');\n        equal(typeof config, 'object', 'Invalid dependency: ' + require('util').inspect(config));\n\n        const type = config.type;\n        const Ctor = this.registeredTypes[type];\n        if (!Ctor) {\n            throw new Error('Dependency of type \"' + type + '\" is not supported. (dependency=' + require('util').inspect(config) + ', package=\"' + filename + '\"). Registered types:\\n' + Object.keys(this.registeredTypes).join(', '));\n        }\n\n        return new Ctor(config, dirname, filename);\n    },\n\n    async normalizeDependencies (dependencies, dirname, filename) {\n        logger.debug('normalizeDependencies()  BEGIN: ', dependencies, 'count:', dependencies.length);\n\n        if (dependencies.length === 0) {\n            return dependencies;\n        }\n\n        let i = 0;\n        let j = 0;\n\n        dependencies = dependencies.concat([]);\n\n        const normalizers = this._finalNormalizers;\n        const normalizerCount = normalizers.length;\n\n        const context = {\n            dirname,\n            filename\n        };\n\n        function handleNormalizedDependency (dependencies, i, normalizedDependency) {\n            if (normalizedDependency) {\n                if (Array.isArray(normalizedDependency)) {\n                    // Remove one\n                    dependencies.splice.apply(dependencies, [i, 1].concat(normalizedDependency));\n                    j = 0;\n                    // Continue at the same dependency index, but restart normalizing at the beginning\n                    return null;\n                } else {\n                    dependencies[i] = normalizedDependency;\n                }\n            }\n\n            j++;\n            return normalizedDependency;\n        };\n\n        const handleDependencyNormalization = async () => {\n            while (i < dependencies.length) {\n                let dependency = dependencies[i];\n\n                if (!dependency.__Dependency) {\n                    if (j < normalizerCount) {\n                        const normalizeFunc = normalizers[j];\n                        const normalizedDependency = await normalizeFunc(dependency, context);\n                        const handledNormalizedDep = handleNormalizedDependency(dependencies, i, normalizedDependency);\n\n                        dependency = handledNormalizedDep || dependency;\n\n                        // Stop looping and we will pick up where we left off when\n                        // the async normalizer finishes\n                        return handleDependencyNormalization();\n                    }\n\n                    // Restart with the first normalizer for the next dependency\n                    j = 0;\n                    // Convert the dependency object to an actual Dependency instance\n                    dependency = this.createDependency(dependency, dirname, filename);\n                }\n\n                dependencies[i] = dependency;\n                i++;\n            }\n\n            logger.debug('normalizeDependencies()  DONE!');\n            return dependencies;\n        };\n\n        return handleDependencyNormalization();\n    },\n\n    /**\n     * This method is used to create a new JavaScript or CSS\n     * type that allows the code to be transformed using a custom\n     * transform function. This was introduced because we wanted to\n     * be able to easily use the babel transpiler on individual\n     * JS dependencies without registering a global transform.\n     */\n    createResourceTransformType (transformFunc) {\n        const transformType = extend({}, dependencyResource);\n        extend(transformType, {\n            isExternalResource: function() {\n                return false;\n            },\n\n            async read (context) {\n                const readResult = await dependencyResource.read.call(this, {});\n\n                return new Promise((resolve, reject) => {\n                    function callback (err, res) {\n                        return err ? reject(err) : resolve(res);\n                    }\n\n                    if (typeof readResult === 'string') {\n                        return transformFunc(readResult, callback);\n                    } else if (readResult) {\n                        let code = '';\n                        readResult\n                            .on('data', function(data) {\n                                code += data;\n                            })\n                            .on('end', function() {\n                                transformFunc(code, callback);\n                            });\n                    }\n                });\n            }\n        });\n\n        return transformType;\n    }\n\n};\n\nmodule.exports = DependencyRegistry;\n"
  },
  {
    "path": "src/dependencies/RequireHandler.js",
    "content": "const nodePath = require('path');\nconst ok = require('assert').ok;\n\nconst EMPTY_ARRAY_PROMISE = Promise.resolve([]);\n\nclass RequireHandler {\n    constructor(userOptions, lassoContext, path) {\n        ok(userOptions, '\"userOptions\" is required');\n        ok(lassoContext, '\"lassoContext\" is required');\n        ok(path, '\"path\" is required');\n\n        this.lassoContext = lassoContext;\n        this.userOptions = userOptions;\n        this.path = path;\n        this.includePathArg = true;\n\n        this.userThisObject = {\n            path,\n            resolvePath: function(pathToResolve) {\n                const dir = nodePath.dirname(path);\n                const resolved = lassoContext.resolve(pathToResolve, dir);\n                return resolved && resolved.path;\n            }\n        };\n        this.lastModified = null;\n        this.object = userOptions.object === true;\n    }\n\n    init() {\n        const lassoContext = this.lassoContext;\n        const userInit = this.userOptions.init;\n\n        return new Promise((resolve, reject) => {\n            if (userInit) {\n                const promise = userInit.call(this.userThisObject, lassoContext, (err) => {\n                    if (err) {\n                        reject(err);\n                    } else {\n                        resolve();\n                    }\n                });\n\n                if (promise !== undefined) {\n                    resolve(promise);\n                }\n            } else {\n                resolve();\n            }\n        });\n    }\n\n    createReadStream() {\n        const lassoContext = this.lassoContext;\n        const path = this.path;\n        const createReadStream = this.userOptions.createReadStream;\n        if (createReadStream) {\n            return this.includePathArg\n                ? createReadStream.call(this.userThisObject, path, lassoContext)\n                : createReadStream.call(this.userThisObject, lassoContext);\n        }\n\n        const userRead = this.userOptions.read;\n        if (userRead) {\n            return lassoContext.createReadStream((callback) => {\n                return this.includePathArg\n                    ? userRead.call(this.userThisObject, path, lassoContext, callback)\n                    : userRead.call(this.userThisObject, lassoContext, callback);\n            });\n        } else {\n            return lassoContext.createReadStream((callback) => {\n                callback(null, '');\n            });\n        }\n    }\n\n    getLastModified() {\n        const lassoContext = this.lassoContext;\n        const path = this.path;\n        const lastModifiedPromise = this.lastModified;\n\n        if (lastModifiedPromise) {\n            return lastModifiedPromise;\n        }\n\n        const userLastModified = this.userOptions.getLastModified;\n\n        if (userLastModified) {\n            this.lastModifiedPromise = new Promise((resolve, reject) => {\n                const callback = (err, lastModified) => {\n                    if (err) {\n                        reject(err);\n                    } else {\n                        resolve(lastModified || -1);\n                    }\n                };\n\n                const userPromise = this.includePathArg\n                    ? userLastModified.call(this.userThisObject, path, lassoContext, callback)\n                    : userLastModified.call(this.userThisObject, lassoContext, callback);\n\n                if (userPromise !== undefined) {\n                    resolve(userPromise || -1);\n                }\n            });\n        } else {\n            this.lastModifiedPromise = this.lassoContext.getFileLastModified(path);\n        }\n\n        return this.lastModifiedPromise;\n    }\n\n    async getDependencies() {\n        const lassoContext = this.lassoContext;\n        const userGetDependencies = this.userOptions.getDependencies;\n        if (!userGetDependencies) {\n            return EMPTY_ARRAY_PROMISE;\n        }\n\n        return userGetDependencies.call(this.userThisObject, lassoContext);\n    }\n\n    getDefaultBundleName(pageBundleName, lassoContext) {\n        const userGetDefaultBundleName = this.userOptions.getDefaultBundleName;\n        if (userGetDefaultBundleName) {\n            return userGetDefaultBundleName.call(this.userThisObject, pageBundleName, lassoContext);\n        }\n    }\n}\n\nmodule.exports = RequireHandler;\n"
  },
  {
    "path": "src/dependencies/dependency-comment.js",
    "content": "module.exports = {\n\n    properties: {\n        path: 'string'\n    },\n\n    // we don't actually produce JavaScript or CSS\n    contentType: 'none',\n\n    read: function(lassoContext) {\n        return null;\n    },\n\n    calculateKey () {\n        return 'comment';\n    }\n};\n"
  },
  {
    "path": "src/dependencies/dependency-dependencies.js",
    "content": "module.exports = {\n    properties: {\n        dependencies: 'array'\n    },\n\n    async init (lassoContext) {},\n\n    async getDependencies (lassoContext) {\n        return this.dependencies || [];\n    },\n\n    calculateKey () {\n        return null; // A just use a unique ID for this dependency\n    }\n};\n"
  },
  {
    "path": "src/dependencies/dependency-intersection.js",
    "content": "const dependencyWalker = require('../dependency-walker');\nconst DependencyList = require('../DependencyList');\n\nconst thresholdRegex = /^(\\d+)([%]*)$/;\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction onDependency (tracking, strictIntersection, firstSet, i) {\n    return function (dependency, context) {\n        if (dependency.isPackageDependency()) {\n            return;\n        }\n\n        const key = dependency.getKey();\n\n        const info = tracking[key];\n        if (info === undefined) {\n            tracking[key] = {\n                dependency,\n                count: 1\n            };\n        } else {\n            info.count++;\n        }\n\n        if ((i === 0) && strictIntersection) {\n            // strict intersection so only need to keep track\n            // dependencies from first set (which is a little\n            // arbitrary but will work)\n            firstSet.push(dependency);\n        }\n    };\n}\n\nmodule.exports = {\n    properties: {\n        dependencies: 'array',\n        threshold: 'object'\n    },\n\n    async init (lassoContext) {\n        if (!this.dependencies) {\n            throw new Error('\"dependencies\" property is required');\n        }\n\n        if (!Array.isArray(this.dependencies)) {\n            throw new Error('\"dependencies\" property is required');\n        }\n\n        this.dependencies = new DependencyList(\n            this.dependencies,\n            lassoContext.dependencyRegistry,\n            this.getParentManifestDir(),\n            this.getParentManifestPath());\n\n        if (this.threshold) {\n            if (typeof this.threshold === 'string') {\n                const match = thresholdRegex.exec(this.threshold);\n                let units;\n\n                if (!match || ((units = match[2]) && (units !== '%'))) {\n                    throw new Error('Invalid threshold: ' + this.threshold);\n                }\n\n                this.threshold = {\n                    value: parseInt(match[1], 10),\n                    units\n                };\n            } else {\n                this.threshold = {\n                    value: this.threshold\n                };\n            }\n        }\n    },\n\n    getDir: function() {\n        return null;\n    },\n\n    async getDependencies (lassoContext) {\n        const tracking = {};\n        const flags = lassoContext.flags;\n        const firstSet = [];\n\n        const dependencies = await this.dependencies.normalize();\n\n        const numDependencies = dependencies.length;\n        let thresholdValue;\n        if (this.threshold) {\n            thresholdValue = this.threshold.value;\n            if (this.threshold.units === '%') {\n                // A dependency will become part of the intersection if it is in at X percent of the enumerated list of dependencies\n                thresholdValue = thresholdValue / 100 * numDependencies;\n            } else {\n                // A dependency will become part of the intersection if it is in at least X of the enumerated list of dependencies\n                thresholdValue = this.threshold.value;\n            }\n        } else {\n            // strict intersection -- only include the dependencies that are in the enumerated list of dependencies\n            thresholdValue = numDependencies;\n        }\n\n        const strictIntersection = (thresholdValue >= numDependencies);\n\n        for (const [i, dependency] of dependencies.entries()) {\n            // HACK: The built-in `dep-require` dependency type\n            // uses its `Deduper` instance to ignore dependencies\n            // within the same \"phase\" of a lasso operation.\n            //\n            // However, for the purposes of calculating intersection\n            // we should not de-duplicate across each \"walk\" of\n            // starting dependency.\n            //\n            // The `Deduper` stores a cache of \"visited\" dependencies in\n            // `lassoContext.phaseData['dependency-require']`.\n            //\n            // We reset the `phaseData` property to remove this\n            // cache before we walk each starting dependency.\n            const oldPhaseData = lassoContext.phaseData;\n            lassoContext.phaseData = {};\n\n            await dependencyWalker.walk({\n                lassoContext,\n                dependency,\n                flags,\n                on: {\n                    dependency: onDependency(tracking, strictIntersection, firstSet, i)\n                }\n            });\n\n            lassoContext.phaseData = oldPhaseData;\n        }\n\n        const intersection = [];\n\n        function checkDependency(info) {\n            if (info.count >= thresholdValue) {\n                intersection.push(info.dependency);\n            }\n        }\n\n        if (strictIntersection) {\n            // strict intersection\n            for (let i = 0, len = firstSet.length; i < len; i++) {\n                const dependency = firstSet[i];\n                checkDependency(tracking[dependency.getKey()]);\n            }\n        } else {\n            // not a strict intersection so we need to check counts for all dependencies\n            for (const key in tracking) {\n                if (hasOwn.call(tracking, key)) {\n                    checkDependency(tracking[key]);\n                }\n            }\n        }\n\n        return intersection;\n    },\n\n    calculateKey () {\n        return null; // A just use a unique ID for this dependency\n    }\n};\n"
  },
  {
    "path": "src/dependencies/dependency-package.js",
    "content": "const ok = require('assert').ok;\nconst manifestLoader = require('../manifest-loader');\nconst nodePath = require('path');\n\nmodule.exports = {\n    properties: {\n        path: 'string',\n        from: 'string'\n    },\n\n    async init (lassoContext) {\n        this._alias = this.path; // Store a reference to the unresolved path\n\n        const from = this.from || this.getParentManifestDir();\n        delete this.from;\n\n        try {\n            this._packageManifest = this.createPackageManifest(\n                manifestLoader.load(\n                    this.path,\n                    from));\n        } catch (e) {\n            if (e.fileNotFound) {\n                const inFile = this.getParentManifestPath();\n                throw new Error('Lasso manifest not found for path \"' + this.path + '\" referenced in \"' + (inFile || this.getParentManifestDir()) + '\"');\n            } else {\n                throw new Error('Unable to load lasso manifest for path \"' + this.path + '\". Dependency: ' + this.toString() + '. Exception: ' + (e.stack || e));\n            }\n        }\n\n        this.path = this._packageManifest.filename; // Store the resolved path and use that as the key\n        ok(this.path, 'this.path should not be null');\n\n        this._dir = nodePath.dirname(this.path);\n    },\n\n    getDir: function() {\n        return this._dir;\n    },\n\n    async loadPackageManifest (lassoContext) {\n        return this._packageManifest;\n    },\n\n    calculateKey () {\n        return 'package|' + this.path;\n    }\n};\n"
  },
  {
    "path": "src/dependencies/dependency-resource.js",
    "content": "const nodePath = require('path');\n\nconst urlReader = require('../util/url-reader');\nconst urlRegExp = /^(http:|https:)?\\/\\//;\n\nconst fs = require('fs');\n\nfunction maskDefine(code) {\n    return '(function(define) { /* mask define */ ' + code + '\\n}()); // END: mask define wrapper';\n}\n\nmodule.exports = {\n    properties: {\n        path: 'string',\n        dir: 'string',\n        virtualPath: 'string',\n        url: 'string',\n        code: 'string',\n        external: 'boolean',\n        'mask-define': 'boolean'\n    },\n\n    async init (lassoContext) {\n        let path = this.path;\n\n        if (!this.path && !this.url && !this.code && !this.virtualPath) {\n            throw new Error('\"path\", \"virtualPath\", \"url\" or \"code\" is required for a resource dependency');\n        }\n\n        if (urlRegExp.test(path)) {\n            this.url = path;\n            path = null;\n            delete this.path;\n        }\n\n        if (path) {\n            this.path = this.resolvePath(path);\n            this._dir = nodePath.dirname(this.path);\n        }\n    },\n\n    cacheConfig: {\n        cacheable: true,\n        static: true\n    },\n\n    getDir: function() {\n        return this._dir || this.dir;\n    },\n\n    async read (context) {\n        if (this.code) {\n            return this.code;\n        }\n\n        // if mask-define, use callback to wrap the resource\n        if (this['mask-define'] === true) {\n            const code = await fs.promises.readFile(this.path, 'utf8');\n            return maskDefine(code);\n        // otherwise return a stream\n        } else {\n            if (this.url) {\n                return urlReader.createUrlReadStream(this.url);\n            } else {\n                return fs.createReadStream(this.path, { encoding: 'utf8' });\n            }\n        }\n    },\n\n    isExternalResource: function() {\n        return this.url != null && this.external !== false;\n    },\n\n    getUrl: function() {\n        if (this.external !== false) {\n            return this.url;\n        }\n    },\n\n    getSourceFile: function() {\n        return this.path || this.virtualPath;\n    },\n\n    async getLastModified (lassoContext) {\n        if (!this.path) {\n            return -1;\n        }\n\n        return this.getFileLastModified(this.path);\n    }\n};\n"
  },
  {
    "path": "src/dependencies/glob.js",
    "content": "const nodePath = require('path');\nconst glob = require('util').promisify(require('glob'));\n\nconst globRegExp = /[*?+{}]/;\n\nasync function globNormalizer (dependency, context) {\n    if (typeof dependency === 'string' && globRegExp.test(dependency)) {\n        const typeSeparator = dependency.indexOf(':');\n        const basedir = context.dirname;\n\n        let pattern = dependency;\n        let type = null;\n        let matches = [];\n\n        if (typeSeparator) {\n            type = dependency.substring(0, typeSeparator).trim();\n            pattern = dependency.substring(typeSeparator + 1);\n        }\n\n        pattern = pattern.trim();\n\n        const patterns = pattern.split(/\\s+/);\n\n        for (const pattern of patterns) {\n            const files = await glob(pattern, { cwd: basedir });\n            matches = matches.concat(files);\n        }\n\n        matches = matches.map((match) => {\n            match = nodePath.join(basedir, match);\n            return type ? type + ':' + match : match;\n        });\n\n        return matches;\n    }\n}\n\nexports.normalizer = globNormalizer;\n"
  },
  {
    "path": "src/dependencies/index.js",
    "content": "const Dependency = require('./Dependency');\nconst DependencyRegistry = require('./DependencyRegistry');\n\nexports.Dependency = Dependency;\nexports.DependencyRegistry = DependencyRegistry;\n\nexports.createRegistry = function() {\n    return new DependencyRegistry();\n};\n\nexports.isRegistry = function(o) {\n    return o && o.__DependencyRegistry === true;\n};\n\nexports.isDependency = function(d) {\n    return d && d.__Dependency === true;\n};\n\nexports.toString = function () {\n    return '[lasso@' + __filename + ']';\n};\n"
  },
  {
    "path": "src/dependency-walker.js",
    "content": "const EventEmitter = require('events').EventEmitter;\nconst forEachEntry = require('raptor-util/forEachEntry');\nconst perfLogger = require('raptor-logging').logger('lasso/perf');\nconst logger = require('raptor-logging').logger(module);\nconst createError = require('raptor-util/createError');\n\n/**\n * Helper method to walk all dependencies recursively\n *\n * @param options\n */\nasync function walk(options) {\n    const startTime = Date.now();\n    const emitter = new EventEmitter();\n    const lassoContext = options.lassoContext || {};\n    const flags = lassoContext.flags;\n    const shouldSkipDependencyFunc = options.shouldSkipDependency;\n\n    const walkContext = {\n        lassoContext\n    };\n\n    const on = options.on;\n    if (!on) {\n        throw new Error('\"on\" property is required');\n    }\n\n    forEachEntry(on, function(event, listener) {\n        emitter.on(event, listener);\n    });\n\n    const foundDependencies = {};\n\n    async function walkDependencies (dependencies, parentDependency, jsSlot, cssSlot, dependencyChain) {\n        logger.debug('walkDependencies', dependencies);\n\n        for (const dependency of dependencies) {\n            await walkDependency(dependency,\n                parentDependency,\n                jsSlot,\n                cssSlot,\n                dependencyChain);\n        }\n    }\n\n    async function walkManifest(manifest, parentDependency, jsSlot, cssSlot, dependencyChain) {\n        delete walkContext.dependency;\n        walkContext.package = manifest;\n        walkContext.dependencyChain = dependencyChain;\n        emitter.emit('manifest', manifest, walkContext, parentDependency);\n\n        logger.debug('walkManifest', manifest);\n\n        const dependencies = await manifest.getDependencies({\n            flags,\n            lassoContext: options.lassoContext\n        });\n\n        logger.debug('walkManifest - dependencies', dependencies);\n        await walkDependencies(dependencies, parentDependency, jsSlot, cssSlot, dependencyChain);\n    }\n\n    async function walkDependency(dependency, parentDependency, jsSlot, cssSlot, dependencyChain) {\n        dependencyChain = dependencyChain.concat(dependency);\n\n        await dependency.init(lassoContext);\n\n        logger.debug('dependency init', dependency);\n\n        if (dependency._condition && !dependency._condition(flags)) {\n            return;\n        }\n\n        const key = await dependency.calculateKey(lassoContext);\n\n        if (foundDependencies[key]) {\n            return;\n        }\n\n        foundDependencies[key] = true;\n\n        let slot;\n\n        if (!dependency.isPackageDependency()) {\n            slot = dependency.getSlot();\n            if (!slot) {\n                if (dependency.isJavaScript()) {\n                    slot = jsSlot || 'body';\n                } else {\n                    slot = cssSlot || 'head';\n                }\n            }\n        }\n\n        walkContext.slot = slot;\n        delete walkContext.package;\n        walkContext.dependency = dependency;\n        walkContext.parentDependency = parentDependency;\n        walkContext.dependencyChain = dependencyChain;\n\n        if (shouldSkipDependencyFunc && shouldSkipDependencyFunc(dependency, walkContext)) {\n            return;\n        }\n\n        emitter.emit('dependency', dependency, walkContext);\n\n        if (dependency.isPackageDependency()) {\n            try {\n                const dependencyManifest = await dependency.getPackageManifest(lassoContext);\n\n                if (!dependencyManifest) {\n                    return;\n                }\n\n                await walkManifest(\n                    dependencyManifest,\n                    dependency,\n                    dependency.getJavaScriptSlot() || jsSlot,\n                    dependency.getStyleSheetSlot() || cssSlot,\n                    dependencyChain);\n            } catch (err) {\n                const message = 'Failed to walk dependency ' + dependency + '. Dependency chain: ' + dependencyChain.join(' → ') + '. Cause: ' + err;\n                throw createError(message, err);\n            }\n        }\n    }\n\n    function done () {\n        perfLogger.debug('Completed walk in ' + (Date.now() - startTime) + 'ms');\n        emitter.emit('end');\n    }\n\n    const dependencyChain = [];\n\n    if (options.lassoManifest) {\n        await walkManifest(\n            options.lassoManifest,\n            null, // parent package\n            null, // jsSlot\n            null,\n            dependencyChain);\n        done();\n    } else if (options.dependency) {\n        await walkDependency(\n            options.dependency,\n            null, // parent package\n            null, // jsSlot\n            null,\n            dependencyChain);\n        done();\n    } else if (options.dependencies) {\n        const dependencies = await options.dependencies.normalize();\n        await walkDependencies(\n            dependencies,\n            null,\n            null,\n            null,\n            dependencyChain);\n        done();\n    } else {\n        throw new Error('\"lassoManifest\", \"dependency\", \"dependencies\" is required');\n    }\n}\n\nexports.walk = walk;\n"
  },
  {
    "path": "src/flags.js",
    "content": "const FlagSet = require('./FlagSet');\n\nfunction isFlagSet(o) {\n    return o && o.__FlagSet;\n}\n\nfunction createFlagSet(flags) {\n    return new FlagSet(flags);\n}\n\nexports.isFlagSet = isFlagSet;\nexports.createFlagSet = createFlagSet;\n"
  },
  {
    "path": "src/index.js",
    "content": "require('raptor-logging');\n\nconst nodePath = require('path');\nconst configLoader = require('./config-loader');\nconst flags = require('./flags');\nconst transforms = require('./transforms');\nconst ok = require('assert').ok;\nconst fs = require('fs');\nconst raptorCache = require('raptor-cache');\nconst extend = require('raptor-util/extend');\nconst getClientPath = require('lasso-modules-client/transport').getClientPath;\nconst stripJsonComments = require('strip-json-comments');\n\nif (!getClientPath) {\n    throw new Error('getClientPath is not defined');\n}\n\nconst configDefaults = {\n    outputDir: 'static',\n    urlPrefix: '/static',\n    includeSlotNames: false,\n    fingerprintsEnabled: true,\n    resolveCssUrls: true,\n    bundlingEnabled: true,\n    minify: false\n};\n\nexports.defaultConfig = {};\nexports.defaultConfigBaseDir = process.cwd();\nexports.defaultConfigFilename = null;\n\nfunction create(config, baseDir, filename) {\n    if (!config) {\n        config = exports.defaultConfig;\n    } else if (typeof config === 'string') {\n        filename = config;\n        filename = nodePath.resolve(process.cwd(), filename);\n\n        baseDir = nodePath.dirname(filename);\n        const json = fs.readFileSync(filename, { encoding: 'utf8' });\n        config = JSON.parse(stripJsonComments(json));\n    }\n\n    if (!baseDir) {\n        baseDir = config.baseDir || process.cwd();\n    }\n\n    if (!config.__Config) {\n        config = configLoader.load(config, baseDir, filename, configDefaults);\n    }\n\n    const Lasso = require('./Lasso');\n    const theLasso = new Lasso(config);\n    return theLasso;\n}\n\nlet defaultLasso = null;\nlet isConfigured = false;\n\nfunction getDefaultLasso() {\n    if (!defaultLasso) {\n        // Fixes #82 - Make lasso a singleton. When resolving the default\n        //             lasso use the global lasso unless this lasso\n        //             was explicitly configured.\n        if (!isConfigured && global.GLOBAL_LASSO) {\n            defaultLasso = global.GLOBAL_LASSO.getDefaultLasso();\n            return defaultLasso;\n        }\n\n        defaultLasso = create(\n            exports.defaultConfig,\n            exports.defaultConfigBaseDir,\n            exports.defaultConfigFilename);\n    }\n\n    return defaultLasso;\n}\n\nfunction setDevelopmentMode() {\n    extend(configDefaults, {\n        fingerprintsEnabled: false,\n        bundlingEnabled: false,\n        minify: false\n    });\n}\n\nconst NODE_ENV = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase();\n\nif (NODE_ENV === 'development' || NODE_ENV === 'dev') {\n    setDevelopmentMode();\n}\n\nfunction configure(config, baseDir, filename) {\n    // Fixes #82 - Make lasso a singleton. The first lasso that is\n    //             explicitly configured will become the default\n    //             global instance.\n    isConfigured = true;\n\n    if (!global.GLOBAL_LASSO) {\n        global.GLOBAL_LASSO = exports;\n    }\n\n    // Clear out the default lasso instance since that it will\n    // be recreated with the new config.\n    defaultLasso = null;\n\n    exports.defaultConfig = config = config || {};\n    exports.defaultConfigBaseDir = baseDir;\n    exports.defaultConfigFilename = filename;\n}\n\nasync function lassoPage(pageConfig) {\n    ok(pageConfig, '\"pageConfig\" is required');\n    ok(typeof pageConfig === 'object', '\"pageConfig\" should be an object');\n\n    let dependencies = pageConfig.dependencies;\n    let packagePath = pageConfig.packagePath;\n\n    ok(dependencies || packagePath, '\"page.dependencies\" or \"page.packagePath\" is required');\n    if (dependencies) {\n        ok(typeof dependencies === 'string' || Array.isArray(dependencies), '\"dependencies\" should be an Array or a String');\n    }\n\n    if (typeof dependencies === 'string') {\n        packagePath = nodePath.resolve(process.cwd(), dependencies);\n        dependencies = null;\n    } else if (typeof packagePath === 'string') {\n        packagePath = nodePath.resolve(process.cwd(), packagePath);\n    }\n\n    return getDefaultLasso().lassoPage(pageConfig);\n}\n\nasync function lassoResource (path, context) {\n    return getDefaultLasso().lassoResource(path, context);\n}\n\nfunction clearCaches() {\n    raptorCache.freeAll();\n    require('./caching-fs').clearCaches();\n}\n\nexports.getDefaultLasso = getDefaultLasso;\nexports.lassoPage = lassoPage;\nexports.lassoResource = lassoResource;\nexports.create = create;\nexports.configure = configure;\nexports.setDevelopmentMode = setDevelopmentMode;\n\nexports.createFlagSet = flags.createFlagSet;\nexports.isFlagSet = flags.isFlagSet;\n\nexports.transforms = transforms;\nexports.writers = require('./writers');\n\nexports.flushAllCaches = raptorCache.flushAll;\n\nexports.handleWatchedFileChanged = function(path) {\n    console.log('[lasso] File modified: ' + path);\n    clearCaches();\n};\n\nexports.clearCaches = clearCaches;\nexports.getClientPath = getClientPath;\n\nObject.defineProperty(exports, 'defaultLasso', {\n    get: getDefaultLasso,\n    enumerable: true,\n    configurable: false\n});\n\nexports.toString = function () {\n    return '[lasso@' + __filename + ']';\n};\n\nrequire('../browser-refresh').enable();\n"
  },
  {
    "path": "src/last-modified.js",
    "content": "const cachingFs = require('./caching-fs');\n\n// TODO: Change in lasso-caching-fs\nexports.forFile = async function (filePath) {\n    return new Promise((resolve, reject) => {\n        cachingFs.lastModified(filePath, function (err, data) {\n            return err ? reject(err) : resolve(data);\n        });\n    });\n};\n"
  },
  {
    "path": "src/manifest-loader.js",
    "content": "const ok = require('assert').ok;\nconst nodePath = require('path');\nconst Module = require('module').Module;\nconst fs = require('fs');\nconst stripJsonComments = require('strip-json-comments');\nconst resolveFrom = require('resolve-from');\n\nconst resolveCache = {};\nconst manifestCache = {};\nconst isAbsolute = require('./path').isAbsolute;\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nconst allowedProps = {\n    dependencies: true,\n    async: true,\n    main: true,\n    requireRemap: true\n};\n\nfunction readManifest(path) {\n    let manifest = manifestCache[path];\n    if (manifest !== undefined) {\n        return manifest;\n    }\n\n    let json;\n\n    try {\n        json = fs.readFileSync(path, { encoding: 'utf8' });\n    } catch (e) {\n        manifest = null;\n    }\n\n    if (json) {\n        try {\n            manifest = JSON.parse(stripJsonComments(json));\n        } catch (e) {\n            throw new Error('Unable to parse JSON file at path \"' + path + '\". Exception: ' + e);\n        }\n\n        for (const k in manifest) {\n            if (hasOwn.call(manifest, k)) {\n                if (!allowedProps[k]) {\n                    throw new Error('Invalid property of \"' + k + '\" in lasso manifest at path \"' + path + '\"');\n                }\n            }\n        }\n\n        if (manifest.main && manifest.dependencies) {\n            throw new Error('\"dependencies\" not allowed when \"main specified. Lasso.js manifest file: ' + path);\n        }\n\n        manifest.dirname = nodePath.dirname(path);\n        manifest.filename = path;\n    }\n\n    manifestCache[path] = manifest;\n    return manifest;\n}\n\nfunction tryManifest(dirname, manifestPath) {\n    let manifest = readManifest(nodePath.resolve(dirname, manifestPath, 'browser.json'));\n    if (!manifest) {\n        manifest = readManifest(nodePath.resolve(dirname, manifestPath, 'optimizer.json'));\n    }\n    return manifest;\n}\n\nfunction tryExtensionManifest(dirname, manifestPath) {\n    let manifest = readManifest(nodePath.resolve(dirname, manifestPath + '.browser.json'));\n    if (!manifest) {\n        manifest = readManifest(nodePath.resolve(dirname, manifestPath + '.optimizer.json'));\n    }\n    return manifest;\n}\n\nfunction tryQualified(dirname, manifestPath) {\n    const path = nodePath.resolve(dirname, manifestPath);\n    return readManifest(path);\n}\n\nfunction tryAll(dirname, manifestPath) {\n    if (manifestPath.endsWith('browser.json') || manifestPath.endsWith('optimizer.json')) {\n        return tryQualified(dirname, manifestPath); // <dirname>/<manifestPath>/browser.json\n    } else {\n        return tryManifest(dirname, manifestPath) || // <dirname>/<manifestPath>/browser.json\n            tryExtensionManifest(dirname, manifestPath); // <dirname>/<manifestPath>.browser.json\n    }\n}\n\nfunction _resolve(path, from) {\n    if (isAbsolute(path)) {\n        return tryAll(from, path);\n    }\n\n    if (!from) {\n        throw new Error('\"from\" argument is required for non-absolute paths');\n    }\n\n    const resolveKey = path + '|' + from;\n    let manifest = resolveCache[resolveKey];\n\n    if (manifest !== undefined) {\n        return manifest;\n    }\n\n    if (process.platform === 'win32') {\n        path = path.replace(/\\\\/g, '/'); // Replace back slashes with forward slashes\n    }\n\n    if (path.startsWith('./') || path.startsWith('../')) {\n        // Don't go through the search paths for relative paths\n        manifest = tryAll(from, path);\n    } else {\n        const resolvedPath = (path.endsWith('optimizer.json') || path.endsWith('browser.json')) && resolveFrom(from, path);\n        if (resolvedPath) {\n            manifest = readManifest(resolvedPath);\n        } else {\n            const paths = Module._nodeModulePaths(from);\n\n            for (let i = 0, len = paths.length; i < len; i++) {\n                const dir = paths[i];\n\n                manifest = tryAll(dir, path);\n\n                if (manifest) {\n                    break;\n                }\n            }\n        }\n    }\n\n    resolveCache[resolveKey] = manifest;\n\n    return manifest;\n}\n\nfunction load(path, from) {\n    ok(path, '\"path\" is required');\n    ok(typeof path === 'string', '\"path\" must be a string');\n\n    // ok(from, '\"from\" is required');\n    // ok(typeof from === 'string', '\"from\" must be a string');\n\n    // Load the lasso manifest and automatically follow \"main\"\n    // to get the destination lasso package\n    function loadHelper(path, from) {\n        const manifest = _resolve(path, from);\n        if (!manifest) {\n            const e = new Error('Lasso manifest not found: ' + path + '(searching from: ' + from + ')');\n            e.fileNotFound = path + '@' + from;\n            throw e;\n        }\n\n        if (manifest.main) {\n            const mainPath = nodePath.resolve(manifest.dirname, manifest.main);\n            return loadHelper(mainPath, manifest.dirname);\n        } else {\n            return manifest;\n        }\n    }\n\n    return loadHelper(path, from);\n}\n\nexports.load = load;\n\nexports.toString = function () {\n    return '[lasso@' + __filename + ']';\n};\n"
  },
  {
    "path": "src/middleware/index.js",
    "content": "exports.serveStatic = require('./serveStatic');\n"
  },
  {
    "path": "src/middleware/koa/serveStatic.js",
    "content": "const lasso = require('../');\nconst send = require('send');\nconst extend = require('raptor-util/extend');\n\nfunction notFound() {\n    this.error(404);\n}\n\nmodule.exports = function(options) {\n    options = options || {};\n\n    const myLasso = options.lasso || lasso.getDefaultLasso();\n    const config = myLasso.config;\n\n    const outputDir = config.outputDir;\n    const urlPrefix = config.urlPrefix;\n    let routePrefix = urlPrefix;\n    if (!routePrefix.endsWith('/')) {\n        routePrefix += '/';\n    }\n\n    if (!outputDir || !urlPrefix) {\n        return function(req, res, next) {\n            return next();\n        };\n    }\n\n    const sendOptions = {\n        fallthrough: false,\n        redirect: false,\n        index: false\n    };\n\n    if (options.sendOptions) {\n        extend(sendOptions, options.sendOptions);\n    }\n\n    sendOptions.root = outputDir;\n\n    return function(ctx, next) {\n        const req = ctx.request;\n        const res = ctx.response;\n\n        const path = req.path;\n        if (!path.startsWith(routePrefix) || (req.method !== 'GET' && req.method !== 'HEAD')) {\n            return next();\n        }\n\n        const filePath = path.substring(routePrefix.length);\n\n        // create send stream\n        const stream = send(req, filePath, sendOptions);\n\n        // add directory handler\n        stream.on('directory', notFound);\n\n        // forward errors\n        stream.on('error', function error(err) {\n            res.statusCode = err.statusCode || 500;\n            res.end('Not found: ' + filePath);\n        });\n\n        // pipe\n        stream.pipe(res);\n    };\n};\n"
  },
  {
    "path": "src/middleware/serveStatic.js",
    "content": "const lasso = require('../');\nconst send = require('send');\nconst extend = require('raptor-util/extend');\n\nfunction notFound() {\n    this.error(404);\n}\n\nmodule.exports = function(options) {\n    options = options || {};\n\n    const myLasso = options.lasso || lasso.getDefaultLasso();\n    const config = myLasso.config;\n\n    const outputDir = config.outputDir;\n    const urlPrefix = config.urlPrefix;\n    let routePrefix = new URL(urlPrefix, 'file:').pathname;\n    if (!routePrefix.endsWith('/')) {\n        routePrefix += '/';\n    }\n\n    if (!outputDir || !urlPrefix) {\n        return function(req, res, next) {\n            return next();\n        };\n    }\n\n    const sendOptions = {\n        fallthrough: false,\n        redirect: false,\n        index: false\n    };\n\n    if (options.sendOptions) {\n        extend(sendOptions, options.sendOptions);\n    }\n\n    sendOptions.root = outputDir;\n\n    return function(req, res, next) {\n        const path = req.path;\n        if (!path.startsWith(routePrefix) || (req.method !== 'GET' && req.method !== 'HEAD')) {\n            return next();\n        }\n\n        const filePath = path.substring(routePrefix.length);\n\n        // create send stream\n        const stream = send(req, filePath, sendOptions);\n\n        // add directory handler\n        stream.on('directory', notFound);\n\n        // forward errors\n        stream.on('error', function error(err) {\n            res.statusCode = err.statusCode || 500;\n            res.end('Not found: ' + filePath);\n        });\n\n        // pipe\n        stream.pipe(res);\n    };\n};\n"
  },
  {
    "path": "src/node-require-no-op/index.js",
    "content": "function requireNoOp(module, filename) { /* no-op */ }\n\nfunction enableForExtension(extension) {\n    if (extension == null) {\n        return;\n    }\n\n    if (Array.isArray(extension)) {\n        extension.forEach(enableForExtension);\n        return;\n    }\n\n    if (typeof extension !== 'string') {\n        throw new Error('Expected extension to be a string. Actual: ' + extension);\n    }\n\n    if (extension.charAt(0) !== '.') {\n        extension = '.' + extension;\n    }\n\n    require.extensions[extension] = requireNoOp; // eslint-disable-line n/no-deprecated-api\n}\n\nexports.enable = function(extensions) {\n    for (let i = 0; i < arguments.length; i++) {\n        enableForExtension(arguments[i]);\n    }\n};\n"
  },
  {
    "path": "src/page-bundles-builder.js",
    "content": "const PageBundles = require('./PageBundles');\nconst dependencyWalker = require('./dependency-walker');\nconst assert = require('assert');\nconst LassoManifest = require('./LassoManifest');\nconst LoaderMetadata = require('./LoaderMetadata');\nconst DependencyTree = require('./DependencyTree');\nconst logger = require('raptor-logging').logger(module);\nconst bundlingStrategies = require('./bundling-strategies');\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nasync function build (options, config, bundleMappings, lassoContext) {\n    // TODO: Change to fully use async/await\n    assert.ok(options, '\"options\" is required');\n    assert.ok(config, '\"config\" is required');\n    assert.ok(bundleMappings, '\"bundleMappings\" is required');\n    assert.ok(lassoContext, '\"lassoContext\" is required');\n\n    const pageName = options.name || options.pageName;\n    const lassoManifest = options.lassoManifest;\n    const flags = lassoContext.flags;\n\n    assert.ok(pageName, 'page name is required');\n    assert.ok(typeof pageName === 'string', 'page name should be a string');\n    assert.ok(lassoManifest, '\"lassoManifest\" is required');\n    assert.ok(LassoManifest.isLassoManifest(lassoManifest), '\"lassoManifest\" is not a valid package');\n\n    // eslint-disable-next-line no-async-promise-executor\n    return new Promise(async (resolve, reject) => {\n        function callback (err, data) {\n            return err ? reject(err) : resolve(data);\n        }\n\n        // this will keep track of async loader metadata\n        const loaderMetadata = lassoContext.loaderMetadata = new LoaderMetadata();\n\n        const pageBundles = new PageBundles();\n\n        const bundlingStrategyFactory = bundlingStrategies[config.getBundlingStrategy() || 'default'];\n\n        if (!bundlingStrategyFactory) {\n            throw new Error('Invalid \"bundlingStrategy\": ' + config.getBundlingStrategy() + '. Expected: ' + Object.keys(bundlingStrategies).join(', '));\n        }\n\n        const bundlingStrategy = bundlingStrategyFactory(options, config, bundleMappings, pageBundles, lassoContext);\n\n        const infoEnabled = logger.isInfoEnabled();\n\n        const foundAsyncPackages = {};\n\n        // as we discover new manifests with \"async\" property, we add tasks to work queue\n        // that will be later used to build each async package\n        const buildAsyncPackagesWorkQueue = require('raptor-async/work-queue').create({\n            // task caused error\n            onTaskError: function(err) {\n                // on error, clear the queue of any tasks\n                buildAsyncPackagesWorkQueue.kill();\n                callback(err);\n            },\n\n            onTaskComplete: function() {\n                if (buildAsyncPackagesWorkQueue.idle()) {\n                    // no more work so done\n                    callback(null, pageBundles);\n                }\n            }\n        }, async function (task, callback) {\n            // this function is called when we need to run task\n\n            const asyncPackageName = task.asyncPackageName;\n            const debugTree = logger.isDebugEnabled() ? new DependencyTree() : null;\n\n            // register this async package name in loader metadata\n            loaderMetadata.addAsyncPackageName(asyncPackageName);\n\n            // Since we are building the async bundles in parallel we need to create a new\n            // lasso context object, each with its own phaseData\n            const nestedLassoContext = Object.create(lassoContext);\n            nestedLassoContext.phaseData = {};\n\n            if (infoEnabled) {\n                logger.info('Building async package \"' + asyncPackageName + '\"...');\n            }\n\n            try {\n                await dependencyWalker.walk({\n                    dependencies: task.dependencies,\n                    flags,\n                    lassoContext: nestedLassoContext,\n                    on: {\n                        // as we're building async packages, we need to watch for new async packages\n                        manifest: handleManifest,\n\n                        dependency: function(dependency, walkContext) {\n                            if (dependency.isPackageDependency()) {\n                                if (debugTree) {\n                                    debugTree.add(dependency, walkContext.parentDependency);\n                                }\n                                return;\n                            }\n\n                            if (!dependency.read) {\n                                logger.debug('Ignoring dependency because it is not readable', dependency);\n                                return;\n                            }\n\n                            // NOTE: walkContext will contain everything that is interesting including the following:\n                            // - dependency\n                            // - slot\n                            // - dependencyChain\n                            lassoContext.emit('beforeAddDependencyToAsyncPageBundle', walkContext);\n\n                            const bundle = bundlingStrategy.getBundleForAsyncDependency(dependency, walkContext, debugTree);\n                            if (bundle) {\n                                dependency.onAddToAsyncPageBundle(bundle, lassoContext);\n                                pageBundles.addAsyncBundle(bundle);\n                                loaderMetadata.addBundle(asyncPackageName, bundle);\n                            }\n                        }\n                    }\n                });\n\n                // we're done walking async dependencies for this async package\n                if (debugTree) {\n                    logger.debug('Async page bundles for \"' + asyncPackageName + '\":\\n' + debugTree.bundlesToString());\n                }\n            } catch (err) {\n                logger.error('Error building bundles for async package \"' + asyncPackageName + '\"', err);\n                return callback(err);\n            }\n\n            logger.info('Built async package \"' + asyncPackageName + '\".');\n            callback();\n        });\n\n        // When walking a manifest, we need to check if the manifest has an \"async\" property\n        // which declares asynchronous packages\n        function handleManifest(manifest, walkContext) {\n            const async = manifest.async;\n            if (async) {\n                // create jobs to build each async package\n                for (const asyncName in async) {\n                    if (hasOwn.call(async, asyncName)) {\n                        if (!hasOwn.call(foundAsyncPackages, asyncName)) {\n                            foundAsyncPackages[asyncName] = true;\n                            buildAsyncPackagesWorkQueue.push({\n                                asyncPackageName: asyncName,\n                                dependencies: async[asyncName]\n                            });\n                        }\n                    }\n                }\n            }\n        }\n\n        /**********************************************************************\n         * STEP 1: Put all of the dependencies into bundles and keep track of *\n         *         packages that are asynchronous.                            *\n         **********************************************************************/\n        async function buildSyncPageBundles () {\n            const debugTree = logger.isDebugEnabled() ? new DependencyTree() : null;\n            lassoContext.setPhase('page-bundle-mappings');\n\n            await dependencyWalker.walk({\n                lassoManifest,\n                flags,\n                lassoContext,\n                on: {\n                    manifest: handleManifest,\n                    dependency: function(dependency, walkContext) {\n                        if (dependency.isPackageDependency()) {\n                            if (debugTree) {\n                                debugTree.add(dependency, walkContext.parentDependency);\n                            }\n\n                            // We are only interested in the actual dependencies (not ones that resolve to more dependencies)\n                            return;\n                        }\n\n                        if (!dependency.read) {\n                            return;\n                        }\n\n                        // NOTE: walkContext will contain everything that is interesting including the following:\n                        // - dependency\n                        // - slot\n                        // - dependencyChain\n                        lassoContext.emit('beforeAddDependencyToSyncPageBundle', walkContext);\n\n                        const bundle = bundlingStrategy.getBundleForSyncDependency(dependency, walkContext, debugTree);\n                        if (bundle) {\n                            // We know that the dependency is now actually part of the page\n                            // (it wasn't just mapped into a bundle during configuration)\n                            dependency.onAddToPageBundle(bundle, lassoContext);\n\n                            // At this point we have added the dependency to a bundle and we know the bundle is not asynchronous\n                            pageBundles.addSyncBundle(bundle);\n                        }\n                    }\n                }\n            });\n\n            if (debugTree) {\n                logger.debug('Page bundles:\\n' + debugTree.bundlesToString());\n            }\n        }\n\n        try {\n            await buildSyncPageBundles();\n        } catch (err) {\n            return callback(err);\n        }\n\n        lassoContext.setPhase('async-page-bundle-mappings');\n        if (buildAsyncPackagesWorkQueue.idle()) {\n            callback(null, pageBundles);\n        } else {\n            // start the work to build bundles for async packages\n            buildAsyncPackagesWorkQueue.resume();\n        }\n    });\n}\n\nexports.build = build;\n"
  },
  {
    "path": "src/path.js",
    "content": "// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// The following code was adapted from: https://github.com/joyent/node/blob/master/lib/path.js\n// Older versions of Node.js do not export isAbsolute() so we added it here\nfunction absUnix (p) {\n    return p.charAt(0) === '/' || p === '';\n}\n\nfunction absWin (p) {\n    if (absUnix(p)) return true;\n    // pull off the device/UNC bit from a windows path.\n    // from node's lib/path.js\n    const splitDeviceRe = /^([a-zA-Z]:|[\\\\\\/]{2}[^\\\\\\/]+[\\\\\\/]+[^\\\\\\/]+)?([\\\\\\/])?([\\s\\S]*?)$/;\n    const result = splitDeviceRe.exec(p);\n    const device = result[1] || '';\n    const isUnc = device && device.charAt(1) !== ':';\n    const isAbsolute = !!result[2] || isUnc; // UNC paths are always absolute\n\n    return isAbsolute;\n}\n\nconst isAbsolute = process.platform === 'win32' ? absWin : absUnix;\n\nexports.isAbsolute = isAbsolute;\n"
  },
  {
    "path": "src/plugins/lasso-image/index.js",
    "content": "const imageSize = require('util').promisify(require('image-size'));\nconst nodePath = require('path');\n\nconst IMAGE_SIZE_WHITELIST = {\n    '.png': true,\n    '.jpeg': true,\n    '.jpg': true,\n    '.gif': true,\n    '.webp': true\n};\n\nfunction plugin(lasso, config) {\n    const handler = {\n        properties: {\n            path: 'string'\n        },\n\n        async init (lassoContext) {\n            if (!this.path) {\n                throw new Error('\"path\" is required for a Marko dependency');\n            }\n\n            this.path = this.resolvePath(this.path);\n        },\n\n        object: true, // We are exporting a simple JavaScript object\n\n        read (lassoContext) {\n            return new Promise((resolve, reject) => {\n                plugin.getImageInfo(this.path, { lasso, lassoContext }, (err, imageInfo) => {\n                    return err ? reject(err) : resolve(JSON.stringify(imageInfo));\n                });\n            });\n        },\n\n        async getLastModified(lassoContext) {\n            return lassoContext.getFileLastModified(this.path);\n        }\n    };\n\n    [\n        'png',\n        'jpeg',\n        'jpg',\n        'gif',\n        'svg',\n        'webp'\n    ].forEach(function(ext) {\n        lasso.dependencies.registerRequireType(ext, handler);\n    });\n};\n\nplugin.getImageInfo = function(path, options, callback) {\n    if (typeof options === 'function') {\n        callback = options;\n        options = null;\n    }\n\n    let theLasso;\n    let lassoContext;\n    let renderContext;\n\n    if (options) {\n        theLasso = options.lasso;\n        lassoContext = options.lassoContext;\n        renderContext = options.renderContext;\n    }\n\n    if (!theLasso) {\n        theLasso = (plugin.lasso || require('../../../')).defaultLasso;\n    }\n\n    if (!lassoContext) {\n        lassoContext = theLasso.createLassoContext(\n            renderContext ? { data: { renderContext } } : {});\n    }\n\n    // NOTE: lassoContext.getFileLastModified caches file timestamps\n    lassoContext.getFileLastModified(path)\n        .then((lastModified) => {\n            const cache = lassoContext.cache.getCache('lasso-image');\n            return cache.get(path, {\n                lastModified,\n                async builder () {\n                    const imageInfo = {};\n\n                    const resourceInfo = await theLasso.lassoResource(path, lassoContext);\n                    imageInfo.url = resourceInfo.url;\n\n                    const ext = nodePath.extname(path);\n                    if (IMAGE_SIZE_WHITELIST[ext]) {\n                        const dimensions = await imageSize(path);\n                        imageInfo.width = dimensions.width;\n                        imageInfo.height = dimensions.height;\n                    }\n\n                    return imageInfo;\n                }\n            });\n        }).then((imageInfo) => {\n            callback(null, imageInfo);\n        })\n        .catch((err) => {\n            callback(err);\n        });\n};\n\nmodule.exports = plugin;\n"
  },
  {
    "path": "src/plugins/lasso-image/lasso-image-browser.js",
    "content": "exports.getImageInfo = function(path, options, callback) {\n    if (typeof options === 'function') {\n        callback = options;\n        options = null;\n    }\n\n    callback(null, require(path));\n};\n"
  },
  {
    "path": "src/plugins/lasso-image/package.json",
    "content": "{\n  \"browser\": {\n    \"./index.js\": \"./lasso-image-browser.js\"\n  }\n}\n"
  },
  {
    "path": "src/plugins/lasso-minify-css/index.js",
    "content": "const CleanCSS = require('clean-css');\n\nfunction isInline(lassoContext) {\n    if (lassoContext.inline === true) {\n        return true;\n    }\n\n    if (lassoContext.dependency && lassoContext.dependency.inline === true) {\n        return true;\n    }\n\n    return false;\n}\n\nmodule.exports = function (lasso, pluginConfig) {\n    lasso.addTransform({\n        contentType: 'css',\n        name: module.id,\n        stream: false,\n\n        transform (code, lassoContext) {\n            if (pluginConfig.inlineOnly === true && !isInline(lassoContext)) {\n                // Skip minification when we are not minifying inline code\n                return code;\n            }\n\n            // Imports should not be loaded in. This was the same behavior as\n            // sqwish.\n            pluginConfig.processImport = false;\n            return new CleanCSS(pluginConfig).minify(code).styles;\n        }\n    });\n};\n"
  },
  {
    "path": "src/plugins/lasso-minify-js/index.js",
    "content": "const Terser = require('terser');\nconst codeFrame = require('@babel/code-frame');\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nfunction isInline(lassoContext) {\n    if (lassoContext.inline === true) {\n        return true;\n    }\n\n    if (lassoContext.dependency && lassoContext.dependency.inline === true) {\n        return true;\n    }\n\n    return false;\n}\n\nmodule.exports = function (lasso, pluginConfig) {\n    lasso.addTransform({\n        contentType: 'js',\n\n        name: module.id,\n\n        stream: false,\n\n        transform: async function(code, lassoContext) {\n            if (pluginConfig.inlineOnly === true && !isInline(lassoContext)) {\n                // Skip minification when we are not minifying inline code\n                return code;\n            }\n\n            const minifyOptions = {};\n            for (const key in pluginConfig) {\n                if (key !== 'inlineOnly' && hasOwn.call(pluginConfig, key)) {\n                    minifyOptions[key] = pluginConfig[key];\n                }\n            }\n\n            try {\n                const minified = (await Terser.minify(code, minifyOptions)).code;\n                if (minified && !minified.endsWith(';')) {\n                    return minified + ';';\n                }\n                return minified;\n            } catch (e) {\n                if (e.line) {\n                    const dependency = lassoContext.dependency;\n                    const frame = codeFrame(code, e.line, e.col, { highlightCode: true });\n                    console.error(e.message + ' in ' + dependency + ' at line ' + e.line + ' column ' + e.col + ':\\n' + frame);\n                    return code;\n                } else {\n                    throw e;\n                }\n            }\n        }\n    });\n};\n"
  },
  {
    "path": "src/plugins/lasso-resolve-css-urls/index.js",
    "content": "const cssParser = require('raptor-css-parser');\nconst nodePath = require('path');\nconst lassoResolveFrom = require('lasso-resolve-from');\n\nconst REQUIRE_PREFIX = 'require:';\n\nasync function defaultUrlResolver (url, lassoContext) {\n    if (url.indexOf('//') !== -1) {\n        return url;\n    }\n\n    const queryStart = url.indexOf('?');\n    let query;\n    let target = url;\n\n    if (queryStart !== -1) {\n        query = url.substring(queryStart + 1);\n        target = url.substring(0, queryStart);\n    }\n\n    if (target.charAt(0) === '/' && target.charAt(1) !== '/') {\n        target = nodePath.join(lassoContext.getProjectRoot(), target);\n    } else if (target.startsWith(REQUIRE_PREFIX)) {\n        target = target.substring(REQUIRE_PREFIX.length).trim();\n\n        let from;\n        if (lassoContext.dependency) {\n            from = lassoContext.dependency.getDir(lassoContext);\n        } else {\n            from = lassoContext.getProjectRoot();\n        }\n\n        const resolved = lassoResolveFrom(from, target);\n\n        if (resolved) {\n            target = resolved.path;\n        } else {\n            const err = new Error('Module not found: ' + target + ' (from: ' + from + ')');\n            err.target = target;\n            err.from = from;\n            err.code = 'MODULE_NOT_FOUND';\n            throw err;\n        }\n    }\n\n    if (query) {\n        // Add back the query string\n        target += '?' + query;\n    }\n\n    return target;\n}\n\nfunction replaceUrls (code, lassoContext, urlResolver) {\n    return new Promise((resolve, reject) => {\n        const lasso = lassoContext.lasso;\n\n        cssParser.replaceUrls(\n            code,\n\n            // the replacer function\n            async function (url, start, end, callback) {\n                try {\n                    // add exception for css properies with hash e.g. behavior: url(#default#VML);\n                    if (url.startsWith('#')) {\n                        return callback(null, url);\n                    }\n\n                    const resolvedUrl = await urlResolver(url, lassoContext);\n                    const bundledResource = await lasso.lassoResource(resolvedUrl, { lassoContext });\n                    callback(null, bundledResource && bundledResource.url);\n                } catch (err) {\n                    callback(err);\n                }\n            },\n\n            // when everything is done\n            function (err, code) {\n                return err ? reject(err) : resolve(code);\n            });\n    });\n}\n\nmodule.exports = function (lasso, pluginConfig) {\n    const urlResolver = pluginConfig.urlResolver || defaultUrlResolver;\n\n    lasso.addTransform({\n        contentType: 'css',\n\n        name: module.id,\n\n        // true: The transform function will RECEIVE and RETURN a stream that can be used to read the transformed out\n        // false: The transform function will RECEIVE full code and RETURN a value or promise\n        stream: false,\n\n        async transform (code, lassoContext) {\n            const dependency = lassoContext.dependency;\n            if (dependency && dependency.resolveCssUrlsEnabled === false) {\n                return code;\n            }\n\n            return replaceUrls(code, lassoContext, urlResolver);\n        }\n    });\n};\n"
  },
  {
    "path": "src/reader.js",
    "content": "const transforms = require('./transforms');\nconst through = require('through');\nconst logger = require('raptor-logging').logger(module);\nconst ok = require('assert').ok;\nconst fs = require('fs');\nconst CombinedStream = require('./util/CombinedStream');\nconst DeferredReadable = require('./util/DeferredReadable');\nconst nodePath = require('path');\nconst AsyncValue = require('raptor-async/AsyncValue');\n\nfunction createReadDependencyStream(dependency, lassoContext, transformerAsyncValue) {\n    const deferredReadable = new DeferredReadable();\n\n    transformerAsyncValue.done(function(err, transformer) {\n        if (err) {\n            deferredReadable.emit('error', err);\n            return;\n        }\n\n        const contentType = dependency.getContentType();\n\n        const readContext = Object.create(lassoContext || {});\n        readContext.contentType = contentType;\n        readContext.dependency = dependency;\n        readContext.transformer = transformer;\n        readContext.dir = dependency.getDir ? dependency.getDir(lassoContext) : null;\n\n        if (dependency.getSourceFile) {\n            readContext.path = dependency.getSourceFile();\n        }\n\n        function createReadStream() {\n            let err;\n            const readStream = dependency.read(readContext);\n            if (!readStream) {\n                err = new Error('Dependency did not return read stream: ' + dependency);\n            }\n\n            if (typeof readStream.pipe !== 'function') {\n                err = new Error('Dependency returned invalid stream: ' + dependency);\n            }\n\n            if (err) {\n                return new DeferredReadable(function() {\n                    this.emit('error', err);\n                    this.push(null);\n                });\n            }\n\n            return readStream;\n        }\n\n        function createTransformedStream(readStream) {\n            if (!transformer.hasTransforms()) {\n                // simply return the dependency read stream if there are no transforms\n                return readStream;\n            }\n\n            return transformer.transform(\n                readStream,\n                readContext);\n        }\n\n        const cache = lassoContext.cache;\n        const cacheKey = dependency.getReadCacheKey();\n\n        if (cache && dependency.shouldCache(lassoContext) && cacheKey) {\n            const readCache = cache.readCache;\n\n            dependency.getLastModified(lassoContext)\n                .then((lastModified) => {\n                    if (!lastModified || lastModified <= 0) {\n                        // This dependency does not support caching\n                        // so don't go through the caching layer\n                        deferredReadable.setWrappedStream(createTransformedStream(createReadStream()));\n                        return;\n                    }\n\n                    const cachedReadStream = readCache.createReadStream(\n                        cacheKey,\n                        {\n                            lastModified,\n                            builder: function () {\n                                // The read dependency has not been cached\n                                return Promise.resolve(createReadStream);\n                            }\n                        });\n\n                    deferredReadable.setWrappedStream(createTransformedStream(cachedReadStream));\n                });\n        } else {\n            deferredReadable.setWrappedStream(createTransformedStream(createReadStream()));\n        }\n    });\n\n    return deferredReadable;\n}\n\nfunction createReadBundleStream(bundle, lassoContext, transformerAsyncValue) {\n    const combinedStream = new CombinedStream({\n        separator: '\\n'\n    });\n\n    if (!bundle.hasContent()) {\n        return combinedStream;\n    }\n    let curIndex;\n    let timeoutId;\n    let timeout = lassoContext.config.getBundleReadTimeout();\n\n    if (timeout == null) {\n        timeout = exports.DEFAULT_READ_TIMEOUT;\n    }\n\n    logger.info('Bundle read timeout value: ' + timeout);\n\n    const dependencies = bundle.getDependencies();\n    const len = dependencies.length;\n\n    combinedStream.on('beginStream', function(event) {\n        curIndex = event.index;\n\n        const dependency = event.stream._dependency;\n        logger.debug('(' + (curIndex + 1) + ' of ' + len + ')', 'Begin reading dependency: ', dependency.toString());\n\n        if (timeout > 0) {\n            timeoutId = setTimeout(onTimeout, timeout);\n        }\n    });\n\n    combinedStream.on('error', function() {\n        if (timeoutId) {\n            clearTimeout(timeoutId);\n        }\n    });\n\n    combinedStream.on('endStream', function(event) {\n        if (timeoutId) {\n            clearTimeout(timeoutId);\n        }\n\n        const dependency = event.stream._dependency;\n        logger.debug('(' + (curIndex + 1) + ' of ' + len + ')', 'Completed reading dependency: ', dependency.toString());\n    });\n\n    logger.debug('Reading bundle: ' + bundle.getKey());\n\n    for (let i = 0; i < len; i++) {\n        const dependency = dependencies[i];\n\n        if (dependency && dependency.hasContent() && !dependency.isExternalResource(lassoContext)) {\n            // Each transform needs its own lassoContext since we update the lassoContext with the\n            // current dependency and each dependency is transformed in parallel\n            const readContext = Object.create(lassoContext || {});\n            readContext.dependency = dependency;\n            readContext.bundle = bundle;\n\n            const stream = createReadDependencyStream(dependency, readContext, transformerAsyncValue);\n\n            // tag the stream with the dependency\n            stream._dependency = dependency;\n\n            combinedStream.addStream(stream);\n        }\n    }\n\n    function onTimeout() {\n        const dependency = dependencies[curIndex];\n        const message = 'Reading dependency timed out after ' + timeout + 'ms: ' + dependency.toString() + '. The timeout value can be set via the bundleReadTimeout configuration option (defaults to ' + exports.DEFAULT_READ_TIMEOUT + ').';\n        combinedStream.emit('error', new Error(message));\n\n        combinedStream.forEachStream(function(stream) {\n            if (stream.end) {\n                stream.end();\n            }\n        });\n    }\n\n    return combinedStream;\n}\n\nfunction createBundleReader(bundle, lassoContext) {\n    ok(bundle, 'bundle is required');\n    ok(lassoContext, 'lassoContext is required');\n\n    const transformContext = Object.create(lassoContext || {});\n    transformContext.contentType = bundle.contentType;\n\n    // TODO: Change to fully use async/await\n    const transformerAsyncValue = new AsyncValue();\n    transforms.createTransformer(lassoContext.config.getTransforms(), transformContext)\n        .then((transformer) => {\n            transformerAsyncValue.resolve(transformer);\n        })\n        .catch((err) => {\n            transformerAsyncValue.reject(err);\n        });\n\n    return {\n        readBundle: function() {\n            return createReadBundleStream(bundle, lassoContext, transformerAsyncValue);\n        },\n\n        readDependency: function(dependency) {\n            ok(dependency, 'dependency is required');\n            ok(typeof dependency.read === 'function', 'Invalid dependency');\n            return createReadDependencyStream(dependency, lassoContext, transformerAsyncValue);\n        },\n\n        async readBundleFully () {\n            if (!bundle.hasContent()) return '';\n\n            return new Promise((resolve, reject) => {\n                let hasError = false;\n\n                function handleError(e) {\n                    if (hasError) {\n                        return;\n                    }\n\n                    hasError = true;\n                    reject(e);\n                }\n\n                const input = this.readBundle();\n                let code = '';\n\n                const captureStream = through(\n                    function write (data) {\n                        code += data;\n                    },\n                    function end () {\n                        if (hasError) {\n                            return;\n                        }\n\n                        resolve(code);\n                    });\n\n                input.on('error', handleError);\n                captureStream.on('error', handleError);\n\n                input.pipe(captureStream);\n            });\n        }\n    };\n}\n\nfunction createResourceReader(path, lassoContext) {\n    return {\n        readResource (options) {\n            const readStream = fs.createReadStream(path, options);\n\n            const filename = nodePath.basename(path);\n            // Use the file extension as the content type\n            const contentType = filename.substring(filename.lastIndexOf('.') + 1);\n\n            const transformContext = Object.create(lassoContext || {});\n            transformContext.contentType = contentType;\n            transformContext.path = path;\n            transformContext.dir = nodePath.dirname(path);\n\n            const readable = new DeferredReadable();\n\n            transforms.createTransformer(lassoContext.config.getTransforms(), transformContext)\n                .then((transformer) => {\n                    if (transformer.hasTransforms() === false) {\n                        // simply use the input stream since there are no transforms after the filtering\n                        readable.setWrappedStream(readStream);\n                        return;\n                    }\n\n                    readable.setWrappedStream(transformer.transform(\n                        readStream,\n                        transformContext));\n                })\n                .catch((err) => {\n                    readable.emit('error', err);\n                });\n\n            return readable;\n        }\n    };\n}\n\nexports.DEFAULT_READ_TIMEOUT = 10000;\nexports.readBundle = createReadBundleStream;\nexports.createBundleReader = createBundleReader;\nexports.createResourceReader = createResourceReader;\n"
  },
  {
    "path": "src/require/build-plugin-config.js",
    "content": "const ok = require('assert').ok;\nconst Transforms = require('./util/Transforms');\nconst extend = require('raptor-util').extend;\nconst defaultGlobals = {\n    jquery: ['$', 'jQuery']\n};\nconst lassoModulesClientTransport = require('lasso-modules-client/transport');\nconst getClientPath = lassoModulesClientTransport.getClientPath;\nconst lassoResolveFrom = require('lasso-resolve-from');\n\nfunction resolveGlobals(config) {\n    const globals = {};\n\n    Object.keys(defaultGlobals).forEach(function(moduleName) {\n        let varNames = defaultGlobals[moduleName];\n        const resolved = lassoResolveFrom(config.rootDir, moduleName);\n\n        if (resolved) {\n            if (!Array.isArray(varNames)) {\n                varNames = [varNames];\n            }\n            globals[resolved.path] = varNames;\n        }\n    });\n\n    if (config.globals) {\n        extend(globals, config.globals);\n    }\n\n    config.globals = globals;\n}\n\nfunction buildPluginConfig(userConfig, defaultProjectRoot) {\n    const config = userConfig ? extend({}, userConfig) : {};\n\n    config.rootDir = config.rootDir || defaultProjectRoot || process.cwd();\n\n    ok(config.rootDir, '\"rootDir\" is required');\n\n    config.runImmediately = config.runImmediately === true;\n\n    config.getClientPath = getClientPath;\n\n    if (config.transforms) {\n        if (config.transforms.length > 0) {\n            config.transforms = new Transforms(config.transforms, defaultProjectRoot);\n        } else {\n            config.transforms = undefined;\n        }\n    }\n\n    resolveGlobals(config);\n\n    if (config.modulesRuntimeGlobal) {\n        if (!config.unbundledTargetPrefix) {\n            // Use the modules global variable name as the unbundled\n            // target prefix (it will get sanitized later)\n            config.unbundledTargetPrefix = config.modulesRuntimeGlobal;\n        }\n\n        // Sanitize the global variable name\n        config.modulesRuntimeGlobal =\n            config.modulesRuntimeGlobal.replace(/[^a-zA-Z0-9\\_\\$]+/g, '_');\n    } else {\n        // Use empty string simply because this used as part of the read\n        // cache key for \"commonjs-def\" dependencies.\n        config.modulesRuntimeGlobal = '';\n    }\n\n    let prefix;\n    if ((prefix = config.unbundledTargetPrefix)) {\n        // Build a friendly looking prefix which is used to create\n        // nested directories when module output files are not bundled.\n        prefix = prefix.replace(/[^a-zA-Z0-9\\_]+/g, '-');\n\n        // remove any leading and trailing \"-\" characters that may\n        // have been created and store the result\n        config.unbundledTargetPrefix =\n            prefix.replace(/^-+/, '').replace(/-+$/, '');\n    }\n\n    config.extensions = userConfig.extensions || ['.js'];\n\n    return config;\n}\n\nmodule.exports = buildPluginConfig;\n"
  },
  {
    "path": "src/require/dep-require-remap.js",
    "content": "const nodePath = require('path');\n\nfunction create(config, lasso) {\n    return {\n        properties: {\n            from: 'string',\n            to: 'string',\n            fromDirname: 'string'\n        },\n\n        async init (lassoContext) {\n            const fromPath = this.resolvePath(this.from);\n            const toPath = this.resolvePath(this.to);\n\n            this.from = fromPath;\n            this.to = toPath;\n        },\n\n        calculateKey () {\n            return this.from + '|' + this.to;\n        },\n\n        getDir: function() {\n            return nodePath.dirname(this.to);\n        },\n\n        async getDependencies (lassoContext) {\n            return [\n                {\n                    type: 'commonjs-remap',\n                    from: this.from,\n                    to: this.to\n                }\n            ];\n        }\n    };\n}\n\nexports.create = create;\n"
  },
  {
    "path": "src/require/dep-require.js",
    "content": "const nodePath = require('path');\nconst ok = require('assert').ok;\nconst equal = require('assert').equal;\nconst VAR_REQUIRE_PROCESS = 'process=require(\"process\")';\nconst VAR_REQUIRE_BUFFER = 'Buffer=require(\"buffer\").Buffer';\n\nconst inspectCache = require('./inspect-cache');\nconst Deduper = require('./util/Deduper');\nconst normalizeMain = require('lasso-modules-client/transport').normalizeMain;\nconst lassoCachingFS = require('lasso-caching-fs');\nconst lassoPackageRoot = require('lasso-package-root');\nconst normalizeFSPath = require('./util/normalizeFSPath');\nconst crypto = require('crypto');\n\nfunction buildAsyncInfo(path, asyncBlocks, lassoContext) {\n    if (asyncBlocks.length === 0) {\n        return null;\n    }\n\n    const key = 'require-async|' + normalizeFSPath(path);\n    let asyncInfo = lassoContext.data[key];\n\n    if (!asyncInfo) {\n        asyncInfo = lassoContext.data[key] = {\n            asyncMeta: {},\n            asyncBlocks\n        };\n\n        asyncBlocks.forEach(function(asyncBlock, i) {\n            if (!asyncBlock.hasInlineDependencies &&\n                !asyncBlock.hasFunctionBody) {\n                // only generate a unique package name if the async\n                // function call was provided a `function` as the\n                // last argument or if an array of dependencies were\n                // inlined.\n                return;\n            }\n\n            const hash = '_' + crypto.createHash('sha1')\n                .update(key)\n                .update(String(i))\n                .digest('hex')\n                .substring(0, 6);\n\n            const name = asyncBlock.name = hash;\n            asyncInfo.asyncMeta[name] = asyncBlock.dependencies;\n        });\n    }\n\n    return asyncInfo;\n}\n\nfunction create(config, lasso) {\n    config = config || {};\n    const globals = config.globals;\n    const getClientPath = config.getClientPath;\n\n    const readyDependency = lasso.dependencies.createDependency({\n        type: 'commonjs-ready',\n        inline: 'end',\n        slot: config.lastSlot\n    }, __dirname);\n\n    const runtimeDependency = lasso.dependencies.createDependency({\n        type: 'commonjs-runtime'\n    }, __dirname);\n\n    function handleMetaRemap(metaEntry, deduper) {\n        const from = metaEntry.from;\n        const to = metaEntry.to;\n\n        const remapKey = deduper.remapKey(from, to);\n        if (!deduper.hasRemap(remapKey)) {\n            const fromPath = getClientPath(from);\n            let toPath;\n\n            if (to === false) {\n                toPath = false;\n            } else {\n                toPath = getClientPath(to);\n            }\n\n            deduper.addDependency(remapKey, {\n                type: 'commonjs-remap',\n                from: fromPath,\n                to: toPath,\n                fromFile: from\n            });\n        }\n    }\n\n    function handleMetaInstalled(metaEntry, deduper) {\n        const packageName = metaEntry.packageName;\n        const searchPath = metaEntry.searchPath;\n        const fromDir = metaEntry.fromDir;\n        const basename = nodePath.basename(searchPath);\n\n        if (basename === 'node_modules') {\n            const childName = packageName;\n            const parentPath = lassoPackageRoot.getRootDir(fromDir);\n            const pkg = lassoCachingFS.readPackageSync(nodePath.join(searchPath, packageName, 'package.json'));\n            const childVersion = (pkg && pkg.version) || '0';\n\n            const key = deduper.installedKey(parentPath, childName, childVersion);\n\n            if (!deduper.hasInstalled(key)) {\n                const clientParentPath = getClientPath(parentPath);\n\n                deduper.addDependency(key, {\n                    type: 'commonjs-installed',\n                    parentPath: clientParentPath,\n                    childName,\n                    childVersion,\n                    parentDir: parentPath\n                });\n            }\n        } else {\n            const key = deduper.searchPathKey(searchPath);\n            if (!deduper.hasSearchPath(key)) {\n                let clientSearchPath = getClientPath(searchPath);\n                if (!clientSearchPath.endsWith('/')) {\n                    // Search paths should always end with a forward slash\n                    clientSearchPath += '/';\n                }\n                // This is a non-standard standard search path entry\n                deduper.addDependency(key, {\n                    type: 'commonjs-search-path',\n                    path: clientSearchPath\n                });\n            }\n        }\n    }\n\n    function handleMetaMain(metaEntry, deduper) {\n        const dir = metaEntry.dir;\n        const main = metaEntry.main;\n\n        const key = deduper.mainKey(dir, main);\n\n        if (!deduper.hasMain(key)) {\n            const dirClientPath = getClientPath(metaEntry.dir);\n            const relativePath = normalizeMain(metaEntry.dir, metaEntry.main);\n\n            deduper.addDependency(key, {\n                type: 'commonjs-main',\n                dir: dirClientPath,\n                main: relativePath,\n                _sourceFile: metaEntry.main\n            });\n        }\n    }\n\n    function handleMetaBuiltin(metaEntry, deduper) {\n        const name = metaEntry.name;\n        const target = metaEntry.target;\n\n        const key = deduper.builtinKey(name, target);\n\n        if (!deduper.hasBuiltin(key)) {\n            const targetClientPath = getClientPath(metaEntry.target);\n\n            deduper.addDependency(key, {\n                type: 'commonjs-builtin',\n                name,\n                target: targetClientPath,\n                _sourceFile: metaEntry.target\n            });\n        }\n    }\n\n    function handleMeta(meta, deduper) {\n        for (let i = 0; i < meta.length; i++) {\n            const metaEntry = meta[i];\n            switch (metaEntry.type) {\n            case 'remap':\n                handleMetaRemap(metaEntry, deduper);\n                break;\n            case 'installed':\n                handleMetaInstalled(metaEntry, deduper);\n                break;\n            case 'main':\n                handleMetaMain(metaEntry, deduper);\n                break;\n            case 'builtin':\n                handleMetaBuiltin(metaEntry, deduper);\n                break;\n            default:\n                throw new Error('Unsupported meta entry: ' + JSON.stringify(metaEntry));\n            }\n        }\n    }\n    return {\n        properties: {\n            path: 'string',\n            from: 'string',\n            run: 'boolean',\n            wait: 'boolean',\n            resolved: 'object',\n            virtualModule: 'object',\n            requireHandler: 'object'\n        },\n\n        async init (lassoContext) {\n            if (!this.path && !this.virtualModule) {\n                const error = new Error('Invalid \"require\" dependency. \"path\" property is required');\n                console.error(module.id, error.stack, this);\n                throw error;\n            }\n\n            if (!this.resolved) {\n                const virtualModule = this.virtualModule;\n\n                if (virtualModule) {\n                    const path = virtualModule.path || this.path;\n                    ok(path, '\"path\" is required for a virtual module');\n\n                    this.path = path;\n                    if (!this.from) {\n                        this.from = nodePath.dirname(path);\n                    }\n\n                    const clientPath = virtualModule.clientPath || getClientPath(path);\n\n                    this.resolved = {\n                        path,\n                        clientPath\n                    };\n                } else if (this.path) {\n                    const from = this.from = this.from || this.getParentManifestDir();\n                    const path = this.path;\n                    const fromFile = this.getParentManifestPath();\n                    const fromFileRelPath = fromFile ? nodePath.relative(process.cwd(), fromFile) : '(unknown)';\n                    this.resolved = lassoContext.resolveCached(path, from);\n\n                    if (!this.resolved) {\n                        throw new Error('Module not found: ' + path + ' (from \"' + from + '\" and referenced in \"' + fromFileRelPath + '\")');\n                    }\n\n                    this.meta = this.resolved.meta;\n                }\n            }\n\n            if (this.run === true) {\n                if (this.wait == null && config.runImmediately === true) {\n                    this.wait = false;\n                }\n\n                this.wait = this.wait !== false;\n            }\n\n            ok(this.path);\n        },\n\n        toString: function() {\n            return '[require: ' + this.path + ']';\n        },\n\n        calculateKey() {\n            // This is a unique key that prevents the same dependency from being\n            // added to the dependency graph repeatedly\n            let key = 'modules-require:' + this.path + '@' + this.from;\n            if (this.run) {\n                key += '|run';\n\n                if (this.wait === false) {\n                    key += '|wait';\n                }\n            }\n            return key;\n        },\n\n        getDir: function() {\n            return nodePath.dirname(this.resolved.path);\n        },\n\n        getRequireHandler: function(lassoContext) {\n            const resolved = this.resolved;\n            let requireHandler = this.requireHandler;\n\n            if (!requireHandler) {\n                const virtualModule = this.virtualModule;\n                if (virtualModule) {\n                    const virtualPath = resolved.path || virtualModule.path || '';\n                    requireHandler = lassoContext.dependencyRegistry.createRequireHandler(virtualPath, lassoContext, virtualModule);\n                    requireHandler.includePathArg = false;\n                }\n            }\n\n            if (!requireHandler) {\n                requireHandler = lassoContext.dependencyRegistry.getRequireHandler(resolved.path, lassoContext);\n\n                if (!requireHandler) {\n                    return null;\n                }\n            }\n\n            const transforms = config.transforms;\n            if (transforms) {\n                const defaultCreateReadStream = requireHandler.createReadStream.bind(requireHandler);\n                const transformedRequireHandler = Object.create(requireHandler);\n\n                transformedRequireHandler.createReadStream = function createdTransformedReadStream() {\n                    const inStream = defaultCreateReadStream();\n                    return transforms.apply(resolved.path, inStream, lassoContext);\n                };\n                return transformedRequireHandler;\n            } else {\n                return requireHandler;\n            }\n        },\n\n        async getDependencies (lassoContext) {\n            ok(lassoContext, '\"lassoContext\" argument expected');\n\n            // the array of dependencies that we will be returning\n            const dependencies = [];\n            const deduper = new Deduper(lassoContext, dependencies);\n\n            // Include client module system if needed and we haven't included it yet\n            if (config.includeClient !== false) {\n                deduper.addRuntime(runtimeDependency);\n            }\n\n            if (this.meta) {\n                handleMeta(this.meta, deduper);\n            }\n\n            if (!lassoContext.isAsyncBundlingPhase()) {\n                // Add a dependency that will trigger all of the deferred\n                // run modules to run once all of the code has been loaded\n                // for the page\n                deduper.addReady(readyDependency);\n            }\n\n            const resolved = this.resolved;\n\n            if (resolved.voidRemap) {\n                // This module has been remapped to a void/empty object\n                // because it is a server-side only module. Nothing\n                // else to do.\n                return dependencies;\n            }\n\n            const run = this.run === true;\n            const wait = this.wait !== false;\n\n            if (resolved.type) {\n                // This is not really a require dependency since a type was provided\n                dependencies.push({\n                    type: resolved.type,\n                    path: resolved.path\n                });\n                return dependencies;\n            }\n\n            const requireHandler = this.getRequireHandler(lassoContext);\n\n            if (!requireHandler) {\n                // This is not really a dependency that compiles down to a CommonJS module\n                // so just add it to the dependency graph\n                dependencies.push(resolved.path);\n                return dependencies;\n            }\n\n            const dirname = nodePath.dirname(resolved.path);\n\n            return requireHandler.init()\n                .then(() => {\n                    if (requireHandler.getDependencies) {\n                        // A require extension can provide its own `getDependencies` method to provide\n                        // additional dependencies beyond what will automatically be discovered using\n                        // static code analysis on the CommonJS code associated with the dependency.\n                        return requireHandler.getDependencies().then((additionalDependencies) => {\n                            if (additionalDependencies && additionalDependencies.length) {\n                                additionalDependencies.forEach((dep) => {\n                                    dependencies.push(dep);\n                                });\n                            }\n                        });\n                    }\n                })\n                .then(() => {\n                    // Fixes https://github.com/lasso-js/lasso-require/issues/21\n                    // Static JavaScript objects should not need to be inspected\n                    if (requireHandler.object) {\n                        // Don't actually inspect the required module if it is an object.\n                        // For example, this would be the case with require('./foo.json')\n                        return requireHandler.getLastModified()\n                            .then((lastModified) => {\n                                return {\n                                    createReadStream: requireHandler.createReadStream.bind(requireHandler),\n                                    lastModified\n                                };\n                            });\n                    }\n\n                    return inspectCache.inspectCached(\n                        resolved.path,\n                        requireHandler,\n                        lassoContext,\n                        config);\n                })\n                .then((inspectResult) => {\n                    let asyncMeta;\n                    let asyncBlocks;\n\n                    if (inspectResult && inspectResult.asyncBlocks && inspectResult.asyncBlocks.length) {\n                        const asyncInfo = buildAsyncInfo(resolved.path, inspectResult.asyncBlocks, lassoContext);\n                        if (asyncInfo) {\n                            asyncBlocks = asyncInfo.asyncBlocks;\n                            asyncMeta = asyncInfo.asyncMeta;\n                        }\n                    }\n\n                    // require was for a source file\n                    let additionalVars;\n                    ok(inspectResult, 'inspectResult should not be null');\n\n                    // the requires that were read from inspection (may remain undefined if no inspection result)\n                    const requires = inspectResult.requires;\n\n                    if (inspectResult.foundGlobals && (inspectResult.foundGlobals.process || inspectResult.foundGlobals.Buffer)) {\n                        additionalVars = [];\n                        const addGlobalVar = (path, varCode) => {\n                            const resolved = lassoContext.resolve(path, dirname);\n                            if (resolved.meta) {\n                                handleMeta(resolved.meta, deduper);\n                            }\n\n                            const requireKey = deduper.requireKey(path, dirname);\n\n                            if (!deduper.hasRequire(requireKey)) {\n                                deduper.addDependency(requireKey, {\n                                    type: 'require',\n                                    path,\n                                    from: dirname\n                                });\n                            }\n\n                            additionalVars.push(varCode);\n                        };\n\n                        if (inspectResult.foundGlobals.process) {\n                            addGlobalVar('process', VAR_REQUIRE_PROCESS);\n                        }\n\n                        if (inspectResult.foundGlobals.Buffer) {\n                            addGlobalVar('buffer', VAR_REQUIRE_BUFFER);\n                        }\n                    }\n\n                    ok(inspectResult.createReadStream, 'createReadStream expected after inspectResult');\n                    ok(inspectResult.lastModified, 'lastModified expected after inspectResult');\n                    equal(typeof inspectResult.lastModified, 'number', 'lastModified should be a number');\n\n                    const globalVars = globals ? globals[this.resolved.path] : null;\n\n                    // Also check if the directory has an browser.json and if so we should include that as well\n                    let lassoJsonPath = nodePath.join(dirname, 'browser.json');\n                    if (lassoContext.cachingFs.existsSync(lassoJsonPath)) {\n                        dependencies.push({\n                            type: 'package',\n                            path: lassoJsonPath\n                        });\n                    } else {\n                        lassoJsonPath = nodePath.join(dirname, 'optimizer.json');\n                        if (lassoContext.cachingFs.existsSync(lassoJsonPath)) {\n                            // TODO Show a deprecation warning here\n                            dependencies.push({\n                                type: 'package',\n                                path: lassoJsonPath\n                            });\n                        }\n                    }\n\n                    // Include all additional dependencies (these were the ones found in the source code)\n                    if (requires && requires.length) {\n                        requires.forEach(function(inspectResultRequire) {\n                            const inspectResultResolved = inspectResultRequire.resolved;\n\n                            const meta = inspectResultResolved.meta;\n                            if (meta) {\n                                handleMeta(meta, deduper);\n                            }\n\n                            const path = inspectResultRequire.path;\n\n                            const requireKey = deduper.requireKey(path, dirname);\n\n                            if (!deduper.hasRequire(requireKey)) {\n                                deduper.addDependency(requireKey, {\n                                    type: 'require',\n                                    path: inspectResultRequire.path,\n                                    from: dirname,\n                                    resolved: inspectResultResolved\n                                });\n                            }\n                        });\n                    }\n\n                    const defKey = deduper.defKey(resolved.clientPath);\n\n                    if (!deduper.hasDef(defKey)) {\n                        const defDependency = {\n                            type: 'commonjs-def',\n                            path: resolved.clientPath,\n                            file: resolved.path\n                        };\n\n                        if (requireHandler.getDefaultBundleName) {\n                            // A `virtualModule` object provided a\n                            // `getDefaultBundleName` that we will use to\n                            // create the define dependency.\n                            defDependency.getDefaultBundleName = requireHandler.getDefaultBundleName.bind(requireHandler);\n                        }\n\n                        if (additionalVars) {\n                            defDependency._additionalVars = additionalVars;\n                        }\n\n                        if (requireHandler.object) {\n                            // If true, then the module will not be wrapped inside a factory function\n                            defDependency.object = true;\n                        }\n\n                        if (globalVars) {\n                            defDependency.globals = globalVars;\n                        }\n\n                        // Pass along the createReadStream and the lastModified to the def dependency\n                        defDependency.requireCreateReadStream = inspectResult.createReadStream;\n                        defDependency.inspected = inspectResult;\n                        defDependency.asyncBlocks = asyncBlocks;\n                        defDependency.requireLastModified = inspectResult.lastModified;\n\n                        deduper.addDependency(defKey, defDependency);\n                    }\n\n                    // Do we also need to add dependency to run the dependency?\n                    if (run === true) {\n                        const runKey = deduper.runKey(resolved.clientPath, wait);\n\n                        if (!deduper.hasRun(runKey)) {\n                            const runDependency = {\n                                type: 'commonjs-run',\n                                path: resolved.clientPath,\n                                wait,\n                                file: resolved.path\n                            };\n\n                            if (requireHandler.getDefaultBundleName) {\n                                // A `virtualModule` object provided a\n                                // `getDefaultBundleName` that we will use to\n                                // create the run dependency.\n                                runDependency.getDefaultBundleName = requireHandler.getDefaultBundleName.bind(requireHandler);\n                            }\n\n                            if (wait === false) {\n                                runDependency.wait = false;\n                            }\n\n                            deduper.addDependency(runKey, runDependency);\n                        }\n                    }\n\n                    if (asyncMeta) {\n                        return {\n                            dependencies,\n                            async: asyncMeta,\n                            dirname: nodePath.dirname(resolved.path),\n                            filename: resolved.path\n                        };\n                    } else {\n                        return dependencies;\n                    }\n                });\n        }\n    };\n}\n\nexports.create = create;\n"
  },
  {
    "path": "src/require/dep-runtime.js",
    "content": "const nodePath = require('path');\nconst fs = require('fs');\n\nconst lassoModulesClientMainPath = require.resolve('lasso-modules-client');\nconst modGlobalVarRegex = /\\$_mod/g;\n\nexports.create = function(config, lasso) {\n    const modulesRuntimeGlobal = config.modulesRuntimeGlobal;\n\n    return {\n        getDir: function() {\n            return nodePath.dirname(lassoModulesClientMainPath);\n        },\n\n        async read (lassoContext) {\n            let contents = await fs.promises.readFile(lassoModulesClientMainPath, 'utf8');\n\n            if (modulesRuntimeGlobal) {\n                contents = contents.replace(modGlobalVarRegex, modulesRuntimeGlobal);\n            }\n\n            return contents;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getSourceFile: function() {\n            return lassoModulesClientMainPath;\n        },\n\n        calculateKey () {\n            return 'modules-runtime';\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-builtin.js",
    "content": "const transport = require('lasso-modules-client/transport');\nconst nodePath = require('path');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n            name: 'string',\n            target: 'string'\n        },\n\n        async init(lassoContext) {},\n\n        getDir: function() {\n            return nodePath.dirname(this._sourceFile);\n        },\n\n        read: function(context) {\n            return transport.codeGenerators.builtin(\n                this.name,\n                this.target,\n                {\n                    modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                });\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget: function() {\n            return 'lasso-modules-meta';\n        },\n\n        getSourceFile: function() {\n            return this._sourceFile;\n        },\n\n        calculateKey () {\n            return 'modules-builtin:' + this.name + '>' + this.target;\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-define.js",
    "content": "const ok = require('assert').ok;\nconst nodePath = require('path');\nconst streamToString = require('./util/streamToString');\nconst transport = require('lasso-modules-client/transport');\nconst StringTransformer = require('./util/StringTransformer');\n\nfunction shouldPreresolvePath(path) {\n    return true;\n    // if (path.indexOf('$') !== -1) {\n    //     // If the require path has a special \"$\" character then\n    //     // we must replace with the preresolved path to avoid\n    //     // problems.\n    //     return true;\n    // }\n    //\n    // if (path.indexOf('node_modules') !== -1) {\n    //     // If the require path includes a \"node_modules\" directory in the path then\n    //     // preresolve since we normalize \"node_modules\" to \"$\"\n    //     return true;\n    // }\n    //\n    //\n    // if (path.charAt(0) === '.') {\n    //     return false;\n    // }\n    //\n    // return true;\n}\n\nfunction preresolvePath(require, stringTransformer) {\n    if (!require.argRange) {\n        // Can't preresolve the require if we don't know where it is in the string...\n        return;\n    }\n\n    const resolved = require.resolved;\n\n    if (shouldPreresolvePath(require.path)) {\n        stringTransformer.comment(require.argRange);\n        stringTransformer.insert(require.argRange[0], '\\'' + resolved.clientPath + '\\'');\n    }\n}\n\nfunction transformRequires(code, inspected, asyncBlocks, lassoContext) {\n    // We have two goals with this function:\n    // 1) Comment out all non-JavaScript module requires\n    //    require('./test.css'); --> /*require('./test.css');*/\n    // 2) Update the first argument for all require('lasso-loader').async(...) calls\n    //\n    // In addition, we want to *maintain line numbers* for the transformed code to be nice!\n\n    const stringTransformer = new StringTransformer();\n\n    function transformRequire(require) {\n        ok(require.resolved, '\"require.resolved\" expected');\n\n        if (require.resolved.voidRemap) {\n            if (require.range) {\n                stringTransformer.comment(require.range);\n                stringTransformer.insert(require.range[0], '({})');\n            }\n            return;\n        }\n\n        const resolved = require.resolved;\n\n        if (!resolved.isDir && (resolved.type || !lassoContext.dependencyRegistry.getRequireHandler(resolved.path, lassoContext))) {\n            if (require.range) {\n                stringTransformer.comment(require.range);\n                stringTransformer.insert(require.range[0], 'void 0');\n            }\n        } else {\n            preresolvePath(require, stringTransformer);\n        }\n    }\n\n    function transformAsyncCall(asyncBlock) {\n        const name = asyncBlock.name;\n\n        const firstArgRange = asyncBlock.firstArgRange;\n\n        if (asyncBlock.packageIdProvided) {\n            // If `name` is not provided then it means that there was no\n            // function body so there is no auto-generated async meta name.\n            if (name) {\n                const packageIdExpression = code.substring(asyncBlock.firstArgRange[0], asyncBlock.firstArgRange[1]);\n\n                // This path is taken when when async is called no arguments:\n                // For example:\n                // require('lasso-loader').async(blah, function() {...});\n                stringTransformer.comment(firstArgRange);\n                stringTransformer.insert(firstArgRange[0],\n                    '[' + JSON.stringify(name) + ',' + packageIdExpression + ']');\n            }\n        } else if (asyncBlock.hasInlineDependencies) {\n            ok(name, '\"asyncBlock.name\" required');\n            // This path is taken when when async is called with\n            // array of dependencies.\n            // For example:\n            // require('lasso-loader').async(['./a.js', './b.js'], function() {...});\n            stringTransformer.comment(firstArgRange);\n            stringTransformer.insert(firstArgRange[0], JSON.stringify(name));\n        } else {\n            ok(name, '\"asyncBlock.name\" required');\n            // This path is taken when when async is called no arguments:\n            // For example:\n            // require('lasso-loader').async(function() {...});\n            stringTransformer.insert(firstArgRange[0], JSON.stringify(name) + ', ');\n        }\n    }\n\n    if (asyncBlocks && asyncBlocks.length) {\n        asyncBlocks.forEach(transformAsyncCall);\n    }\n\n    inspected.allRequires.forEach(transformRequire);\n\n    return stringTransformer.transform(code);\n}\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n            path: 'string',\n            file: 'file',\n            globals: 'string',\n            wait: 'boolean',\n            object: 'boolean',\n            inspected: 'object',\n            requireCreateReadStream: 'function',\n            requireLastModified: 'function',\n            asyncBlocks: 'array'\n        },\n\n        getDir: function() {\n            return nodePath.dirname(this.file);\n        },\n\n        getSourceFile: function() {\n            return this.file;\n        },\n\n        read: function(lassoContext) {\n            const requireCreateReadStream = this.requireCreateReadStream;\n            const requireInspected = this.inspected;\n            const asyncBlocks = this.asyncBlocks;\n            const isObject = this.object;\n            const globals = this.globals;\n            const path = this.path;\n            const additionalVars = this._additionalVars;\n\n            ok(requireCreateReadStream, '\"requireCreateReadStream\" is required');\n            ok(requireInspected, '\"requireInspected\" is required');\n            ok(path, '\"path\" is required');\n\n            const stream = requireCreateReadStream();\n\n            return streamToString(stream)\n                .then((code) => {\n                    if (isObject) {\n                        return transport.codeGenerators.define(path, code, {\n                            object: true,\n                            modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                        });\n                    } else {\n                        const transformedCode = transformRequires(code, requireInspected, asyncBlocks, lassoContext);\n\n                        const defCode = transport.codeGenerators.define(\n                            path,\n                            transformedCode,\n                            {\n                                additionalVars,\n                                globals,\n                                modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                            });\n\n                        return defCode;\n                    }\n                });\n        },\n\n        async getLastModified (lassoContext) {\n            return this.requireLastModified;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget(lassoContext) {\n            return this.path;\n        },\n\n        calculateKey () {\n            return 'modules-define:' + this.path;\n        },\n\n        toString() {\n            return `[commonjs-def: path=\"${this.path}\"]`;\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-installed.js",
    "content": "const transport = require('lasso-modules-client/transport');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n            parentPath: 'string',\n            childName: 'string',\n            childVersion: 'string',\n            parentDir: 'string'\n        },\n\n        async init(lassoContext) {},\n\n        getDir: function() {\n            return this.parentDir;\n        },\n\n        read: function(context) {\n            return transport.codeGenerators.installed(\n                this.parentPath,\n                this.childName,\n                this.childVersion,\n                {\n                    modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                });\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget: function() {\n            return 'lasso-modules-meta';\n        },\n\n        getSourceFile: function() {\n            return this._sourceFile;\n        },\n\n        calculateKey () {\n            return 'modules-installed:' + this.parentPath + '|' + this.childName + '|' + this.childVersion;\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-loader-metadata.js",
    "content": "const transport = require('lasso-modules-client/transport');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {},\n\n        async init(lassoContext) {},\n\n        read: function(lassoContext) {\n            const loaderMetadata = lassoContext && lassoContext.loaderMetadata;\n            if (!loaderMetadata) {\n                return null;\n            }\n\n            return transport.codeGenerators.loaderMetadata(\n                loaderMetadata,\n                lassoContext,\n                {\n                    modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                });\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget: function() {\n            return 'lasso-modules-meta';\n        },\n\n        calculateKey () {\n            return 'loader-metadata';\n        },\n\n        isPageBundleOnlyDependency: function() {\n            return true;\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-main.js",
    "content": "const transport = require('lasso-modules-client/transport');\nconst nodePath = require('path');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n            dir: 'string',\n            main: 'string'\n        },\n\n        async init() {},\n\n        getDir: function() {\n            return nodePath.dirname(this._sourceFile);\n        },\n\n        read: function(context) {\n            return transport.codeGenerators.main(\n                this.dir,\n                this.main,\n                {\n                    modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                });\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        },\n\n        getSourceFile: function() {\n            return this._sourceFile;\n        },\n\n        calculateKey () {\n            return 'modules-main:' + this.dir + '|' + this.main;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget: function() {\n            return 'lasso-modules-meta';\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-ready.js",
    "content": "const transport = require('lasso-modules-client/transport');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n        },\n\n        async init() {\n            if (!this.slot) {\n                delete this.slot;\n            }\n        },\n\n        getDir: function() {\n            return null;\n        },\n\n        read: function(context) {\n            return transport.codeGenerators.ready({\n                modulesRuntimeGlobal: config.modulesRuntimeGlobal\n            });\n        },\n\n        calculateKey () {\n            return 'modules-ready';\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-remap.js",
    "content": "const transport = require('lasso-modules-client/transport');\nconst nodePath = require('path');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n            from: 'string',\n            to: 'string',\n            fromFile: 'string'\n        },\n\n        async init (lassoContext) {},\n\n        getDir: function() {\n            return this.fromFile ? nodePath.dirname(this.fromFile) : undefined;\n        },\n\n        read: function(context) {\n            return transport.codeGenerators.remap(\n                this.from,\n                this.to,\n                {\n                    modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                });\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        },\n\n        getSourceFile: function() {\n            return this._sourceFile;\n        },\n\n        calculateKey () {\n            return 'modules-remap:' + this.from + '|' + this.to;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget: function() {\n            return 'lasso-modules-meta';\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-run.js",
    "content": "const nodePath = require('path');\nconst transport = require('lasso-modules-client/transport');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n            path: 'string',\n            wait: 'boolean',\n            file: 'string' // The original source file that this dependency is assocaited with\n        },\n\n        async init(lassoContext) {},\n\n        getDir: function() {\n            return this.path ? nodePath.dirname(this.path) : undefined;\n        },\n\n        read: function(lassoContext) {\n            // the default is to wait so only output options\n            // if the wait value is not equal to the default value\n            const runOptions = (this.wait === false) ? { wait: false } : undefined;\n\n            return transport.codeGenerators.run(\n                // the path to the resource\n                this.path,\n\n                // options for runCode\n                runOptions,\n\n                // options that affect how the code is generated\n                {\n                    modulesRuntimeGlobal: config.modulesRuntimeGlobal\n                });\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget: function() {\n            let bundleName = this.path;\n\n            const ext = nodePath.extname(bundleName);\n\n            if (ext) {\n                bundleName = bundleName.substring(0, bundleName.length - ext.length);\n            }\n\n            return bundleName + '-run' + ext;\n        },\n\n        calculateKey () {\n            return 'modules-run:' + this.path + '|' + this.wait;\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/dep-transport-search-path.js",
    "content": "const transport = require('lasso-modules-client/transport');\n\nexports.create = function(config, lasso) {\n    return {\n        properties: {\n            path: 'string',\n            paths: 'string[]'\n        },\n\n        async init () {\n            if (!this.paths) {\n                this.paths = [];\n            }\n\n            if (this.path) {\n                this.paths.push(this.path);\n            }\n        },\n\n        getDir: function() {\n            return null;\n        },\n\n        read: function(context) {\n            return transport.codeGenerators.searchPath(this.paths, {\n                modulesRuntimeGlobal: config.modulesRuntimeGlobal\n            });\n        },\n\n        async getLastModified (lassoContext) {\n            return -1;\n        },\n\n        getUnbundledTargetPrefix: function(lassoContext) {\n            return config.unbundledTargetPrefix;\n        },\n\n        getUnbundledTarget: function() {\n            return 'lasso-modules-meta';\n        },\n\n        calculateKey () {\n            return 'modules-search-path:' + JSON.stringify(this.paths);\n        }\n    };\n};\n"
  },
  {
    "path": "src/require/index.js",
    "content": "const fs = require('fs');\nconst depRequire = require('./dep-require');\nconst depRequireRemap = require('./dep-require-remap');\nconst depTransportDef = require('./dep-transport-define');\nconst depTransportRun = require('./dep-transport-run');\nconst depTransportInstalled = require('./dep-transport-installed');\nconst depTransportMain = require('./dep-transport-main');\nconst depTransportRemap = require('./dep-transport-remap');\nconst depTransportReady = require('./dep-transport-ready');\nconst depTransportBuiltin = require('./dep-transport-builtin');\nconst depTransportSearchPath = require('./dep-transport-search-path');\nconst depLoaderMetadata = require('./dep-transport-loader-metadata');\nconst depRuntime = require('./dep-runtime');\nconst buildPluginConfig = require('./build-plugin-config');\nconst extend = require('raptor-util').extend;\n\nconst requireRegExp = /^require\\s+(.*)$/;\nconst requireRunRegExp = /^require-run\\s*:\\s*(.*)$/;\n\nmodule.exports = exports = function plugin(lasso, userConfig) {\n    const defaultProjectRoot = lasso.config.getProjectRoot();\n    const config = buildPluginConfig(userConfig, defaultProjectRoot);\n\n    lasso.on('lassoCacheCreated', function(cacheInfo) {\n        const lassoCache = cacheInfo.lassoCache;\n\n        lassoCache.configureCacheDefaults({\n            '*': { // Any profile\n                'lasso-require/inspect': {\n                    store: 'disk',\n                    encoding: 'utf8',\n                    valueType: 'json'\n                },\n                'lasso-require/transformed': {\n                    store: 'disk',\n                    singleFile: false,\n                    encoding: 'utf8'\n                }\n            }\n        });\n    });\n\n    function registerExtension(ext) {\n        lasso.dependencies.registerRequireExtension(ext, {\n            read: function(path) {\n                return fs.createReadStream(path, { encoding: 'utf8' });\n            },\n\n            async getLastModified (path, lassoContext) {\n                return lassoContext.getFileLastModified(path);\n            }\n        });\n    }\n\n    config.extensions.forEach(registerExtension);\n\n    lasso.dependencies.registerRequireExtension('json', {\n        object: true,\n\n        read: function(path) {\n            return fs.createReadStream(path, { encoding: 'utf8' });\n        },\n\n        getLastModified (path, lassoContext) {\n            return lassoContext.getFileLastModified(path);\n        }\n    });\n\n    lasso.dependencies.registerJavaScriptType('commonjs-def', depTransportDef.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-run', depTransportRun.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-installed', depTransportInstalled.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-main', depTransportMain.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-remap', depTransportRemap.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-ready', depTransportReady.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-search-path', depTransportSearchPath.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-runtime', depRuntime.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('commonjs-builtin', depTransportBuiltin.create(config, lasso));\n    lasso.dependencies.registerJavaScriptType('loader-metadata', depLoaderMetadata.create(config, lasso));\n\n    lasso.dependencies.registerPackageType('require', depRequire.create(config, lasso));\n    lasso.dependencies.registerPackageType('require-remap', depRequireRemap.create(config, lasso));\n\n    lasso.dependencies.addNormalizer(function(dependency) {\n        if (typeof dependency === 'string') {\n            let matches;\n\n            if ((matches = requireRegExp.exec(dependency))) {\n                return {\n                    type: 'require',\n                    path: matches[1]\n                };\n            } else if ((matches = requireRunRegExp.exec(dependency))) {\n                return {\n                    type: 'require',\n                    path: matches[1],\n                    run: true\n                };\n            }\n        } else if (!dependency.type) {\n            if (dependency.require) {\n                const reqDep = {\n                    type: 'require',\n                    path: dependency.require\n                };\n\n                extend(reqDep, dependency);\n                delete reqDep.require;\n\n                return reqDep;\n            } else if (dependency['require-run']) {\n                const reqRunDep = {\n                    type: 'require',\n                    run: true,\n                    path: dependency['require-run']\n                };\n\n                extend(reqRunDep, dependency);\n                delete reqRunDep['require-run'];\n\n                return reqRunDep;\n            }\n        }\n    });\n};\n\n// module.exports.getClientPath = require('lasso-modules-client/transport').getClientPath;\n"
  },
  {
    "path": "src/require/inspect-cache.js",
    "content": "const ok = require('assert').ok;\nconst logger = require('raptor-logging').logger(module);\nconst streamToString = require('./util/streamToString');\nconst inspect = require('./util/inspect');\nconst nodePath = require('path');\nconst extend = require('raptor-util/extend');\nconst normalizeFSPath = require('./util/normalizeFSPath');\n\nexports.inspectCached = function(path, requireHandler, lassoContext, config) {\n    const debugEnabled = logger.isDebugEnabled();\n\n    ok(path, '\"path\" is required');\n    ok(requireHandler, '\"requireHandler\" is required');\n\n    ok(lassoContext, '\"lassoContext\" is required');\n    ok(config, '\"config\" is required');\n\n    ok(typeof path === 'string', '\"path\" should be a string');\n    ok(typeof requireHandler.createReadStream === 'function', '\"requireHandler.createReadStream\" should be a function');\n    ok(typeof requireHandler.getLastModified === 'function', '\"requireHandler.getLastModified\" should be a function');\n    ok(typeof lassoContext === 'object', '\"lassoContext\" should be an object');\n    ok(typeof config === 'object', '\"config\" should be an object');\n\n    function resolveInspectedRequires(inspectResult) {\n        const allRequires = [];\n        const fromDir = nodePath.dirname(path);\n\n        function handleRequire(require) {\n            const resolved = lassoContext.resolveCached(require.path, fromDir);\n            const pathRelative = nodePath.relative(process.cwd(), path);\n            const fromRelative = nodePath.relative(process.cwd(), fromDir);\n            if (!resolved) {\n                throw new Error('Module not found: ' + require.path + ' (from \"' + fromRelative + '\" and referenced in \"' + pathRelative + '\")');\n            }\n\n            // Clone the require\n            require = extend({}, require);\n            require.resolved = resolved;\n            allRequires.push(require);\n            return require;\n        }\n\n        if (inspectResult.requires) {\n            inspectResult.requires = inspectResult.requires.map(handleRequire);\n        }\n\n        if (inspectResult.asyncBlocks) {\n            inspectResult.asyncBlocks.forEach(function(asyncBlock) {\n                asyncBlock.requires = asyncBlock.requires.map(handleRequire);\n            });\n        }\n\n        inspectResult.allRequires = allRequires;\n    }\n\n    // Get or create the required caches\n    const transformsId = config.transforms ? '/' + config.transforms.id : '';\n    let inspectCache = lassoContext.data['lasso-require/inspect'];\n    if (!inspectCache && lassoContext.cache) {\n        inspectCache = lassoContext.data['lasso-require/inspect'] = lassoContext.cache.getCache(\n            // Unique cache name based on the set of enabled require transforms:\n            'lasso-require/inspect' + (transformsId ? '-' + transformsId : ''), // NOTE: \".1\" is just needed for cache busting old versions\n            // Name of the cache configuration to use:\n            'lasso-require/inspect');\n    }\n\n    let src;\n    let lastModified;\n\n    function readSource() {\n        if (src != null) {\n            // We have already read in the source code for the require so just return that!\n            return Promise.resolve(src);\n        }\n\n        // Otherwise, let's read in the stream into a string value and invoke the callback when it is done.\n        const stream = requireHandler.createReadStream();\n        return streamToString(stream)\n            .then((_src) => {\n                src = _src;\n                return src;\n            });\n    }\n\n    let fromCache = true;\n\n    function cacheBuilder () {\n        fromCache = false;\n        return readSource()\n            .then((src) => {\n                return inspect(src, { filename: path });\n            });\n    }\n\n    function afterInspect (inspectResult) {\n        if (debugEnabled) {\n            logger.debug('Inspection result for ' + path + ': ' + JSON.stringify(inspectResult));\n        }\n\n        // Do a shallow clonse so that we don't modify the object stored in the cache\n        inspectResult = extend({}, inspectResult);\n        inspectResult.lastModified = lastModified || -1;\n        if (fromCache) {\n            inspectResult.fromCache = fromCache;\n        }\n\n        resolveInspectedRequires(inspectResult);\n\n        if (src) {\n            // If src is non-null then that means that the builder needed to be invoked to read\n            // the require dependency to inspect the source. Since we had to read the dependency let's\n            // also provide the src so that we don't need to re-read it to generate the final\n            // output bundle\n            inspectResult.createReadStream = function() {\n                return lassoContext.deferredStream(function() {\n                    this.push(src);\n                    this.push(null);\n                });\n            };\n        } else {\n            inspectResult.createReadStream = requireHandler.createReadStream.bind(requireHandler);\n        }\n\n        return inspectResult;\n    }\n\n    // Inspecting a JavaScript file is expensive since it requires parsing the JavaScript to find all of the\n    // requires. We really don't want to do that every time so we *always* calculate a cache key for the\n    // the dependency. In the normal case we use the \"lastModiifed\" time for the require, but in case where\n    // that is not available then we read in the JavaScript code for the require and calculate a fingerprint\n    // on the provided source and use that as a cache key.\n\n    /**\n     * This method does the final inspection after we have calculated the cache key.\n     * At this point we may or may not have actually read in the source for the require.\n     * @return {[type]} [description]\n     */\n    function doInspect(cacheKey) {\n        ok(cacheKey);\n\n        if (!inspectCache) {\n            return cacheBuilder().then(afterInspect);\n        }\n\n        // try to read the inspect result from the cache\n        return inspectCache.get(\n            cacheKey,\n            {\n                lastModified: lastModified && lastModified > 0 ? lastModified : undefined,\n                builder: cacheBuilder\n            })\n            .then(afterInspect);\n    }\n\n    function buildCacheKeyFromFingerprint() {\n        return new Promise((resolve, reject) => {\n            // We are going to need to read in the source code for the require to calculate the fingerprint.\n            // We will use the fingerprint as a cache key to avoid having to inspect the JavaScript in the\n            // case where there is cache hit. Since we have already read in the source this won't need to be\n            // done later in the pipeline.\n            src = '';\n            let fingerprint = null;\n\n            const stream = requireHandler.createReadStream();\n            const fingerprintStream = lassoContext.createFingerprintStream();\n\n            fingerprintStream\n                .on('fingerprint', function(_fingerprint) {\n                    fingerprint = _fingerprint;\n                })\n                .on('data', function(data) {\n                    src += data;\n                })\n                .on('end', function() {\n                    resolve(fingerprint);\n                })\n                .on('error', reject);\n\n            stream\n                .on('error', reject)\n                .pipe(fingerprintStream);\n        });\n    }\n\n    return requireHandler.getLastModified()\n        .then((_lastModified) => {\n            lastModified = _lastModified;\n\n            if (!lastModified || lastModified < 0) {\n                lastModified = undefined;\n            }\n\n            if (lastModified) {\n                return normalizeFSPath(path);\n            } else {\n                return buildCacheKeyFromFingerprint();\n            }\n        })\n        .then(doInspect);\n};\n"
  },
  {
    "path": "src/require/util/Deduper.js",
    "content": "const DeduperContext = require('./DeduperContext');\nconst ok = require('assert').ok;\n\nconst REQUIRE_DEDUPER_CONTEXT_KEY = 'dependency-require';\nconst hasOwn = Object.prototype.hasOwnProperty;\n\nclass Deduper {\n    constructor(lassoContext, dependencies) {\n        ok(lassoContext, '\"lassoContext\" is required');\n        ok(dependencies, '\"dependencies\" is required');\n\n        /*\n         * NOTE: The use of \"phaseData\" was necessary because we want to keep a cache that is independent of\n         * for each phase of the optimization process. The optimization is separated into phases such as \"app-bundle-mappings\",\n         * \"page-bundle-mappings\", \"async-page-bundle-mappings\", etc. We use the \"deduperContext\" to prevent adding the same\n         * require dependencies over and over again.\n         */\n        const deduperContext = lassoContext.phaseData[REQUIRE_DEDUPER_CONTEXT_KEY] ||\n            (lassoContext.phaseData[REQUIRE_DEDUPER_CONTEXT_KEY] = new DeduperContext());\n\n        this.dependencies = dependencies;\n\n        this.deduperContext = deduperContext;\n\n        const lookups = deduperContext.lookups;\n        this.lookupDef = lookups.def;\n        this.lookupRun = lookups.run;\n        this.lookupInstalled = lookups.installed;\n        this.lookupMain = lookups.main;\n        this.lookupRemap = lookups.remap;\n        this.lookupRequire = lookups.require;\n        this.lookupBuiltin = lookups.builtin;\n        this.lookupSearchPath = lookups.searchPath;\n    }\n\n    addDependency(key, d) {\n        this.lookupDef[key] = true;\n        this.dependencies.push(d);\n    }\n\n    // Define\n    defKey(path) {\n        return path;\n    }\n\n    hasDef(key) {\n        return hasOwn.call(this.lookupDef, key);\n    }\n\n    // Run\n    runKey(path, wait) {\n        return wait ? path : path + '|nowait';\n    }\n\n    hasRun(key) {\n        return hasOwn.call(this.lookupRun, key);\n    }\n\n    // Installed\n    installedKey(parentPath, childName, childVersion) {\n        return parentPath + '|' + childName + '|' + childVersion;\n    }\n\n    hasInstalled(key) {\n        return hasOwn.call(this.lookupInstalled, key);\n    }\n\n    // Main\n    mainKey(dir, main) {\n        return dir + '|' + main;\n    }\n\n    hasMain(key) {\n        return hasOwn.call(this.lookupMain, key);\n    }\n\n    // Remap\n    remapKey(from, to) {\n        return from + '|' + to;\n    }\n\n    hasRemap(key) {\n        return hasOwn.call(this.lookupRemap, key);\n    }\n\n    // Require\n    requireKey(path, from, run, wait) {\n        let key = path + '@' + from;\n        if (run) {\n            key += '|run|' + wait;\n        }\n        return key;\n    }\n\n    hasRequire(key) {\n        return hasOwn.call(this.lookupRequire, key);\n    }\n\n    // Builtin\n    builtinKey(name, target) {\n        return name + '>' + target;\n    }\n\n    hasBuiltin(key) {\n        return hasOwn.call(this.lookupBuiltin, key);\n    }\n\n    // Search path\n    searchPathKey(path) {\n        return path;\n    }\n\n    hasSearchPath(key) {\n        return hasOwn.call(this.lookupSearchPath, key);\n    }\n\n    addRuntime(runtimeDependency) {\n        if (this.deduperContext.runtimeInclude === false) {\n            this.dependencies.push(runtimeDependency);\n            this.deduperContext.runtimeInclude = true;\n        }\n    }\n\n    addReady(readyDependency) {\n        if (this.deduperContext.readyIncluded === false) {\n            // Add a dependency that will trigger all of the deferred\n            // run modules to run once all of the code has been loaded\n            // for the page\n            this.dependencies.push(readyDependency);\n            this.deduperContext.readyIncluded = true;\n        }\n    }\n\n    addProcess(d) {\n        if (this.deduperContext.processIncluded === false) {\n            this.dependencies.push(d);\n            this.deduperContext.processIncluded = true;\n        }\n    }\n}\n\nmodule.exports = Deduper;\n"
  },
  {
    "path": "src/require/util/DeduperContext.js",
    "content": "class DeduperContext {\n    constructor() {\n        this.lookups = {\n            def: {},\n            run: {},\n            installed: {},\n            main: {},\n            remap: {},\n            require: {},\n            builtin: {},\n            searchPath: {}\n        };\n        this.runtimeInclude = false;\n        this.readyIncluded = false;\n        this.processIncluded = false;\n    }\n}\n\nmodule.exports = DeduperContext;\n"
  },
  {
    "path": "src/require/util/StringTransformer.js",
    "content": "function StringTransformer() {\n    this.modifications = [];\n}\n\nStringTransformer.prototype = {\n    transform: function(str) {\n        if (this.modifications.length === 0) {\n            return str;\n        }\n\n        this.modifications.sort(function(a, b) {\n            const compare = b.index - a.index;\n            if (compare === 0) {\n                return a.precedence - b.precedence;\n            } else {\n                return compare;\n            }\n        });\n\n        for (let i = 0, len = this.modifications.length; i < len; i++) {\n            str = this.modifications[i].transform(str);\n        }\n\n        return str;\n    },\n\n    insert: function(index, newStr) {\n        this.modifications.push({\n            index,\n            precedence: 3,\n            toString: function() {\n                return 'insert ' + index + ' --> ' + newStr;\n            },\n            transform: function(str) {\n                return str.substring(0, index) + newStr + str.substring(index);\n            }\n        });\n    },\n\n    replace: function(range, replacement) {\n        this.modifications.push({\n            index: range[0],\n            precedence: 2,\n            toString: function() {\n                return 'replace ' + range + ' --> ' + replacement;\n            },\n            transform: function(str) {\n                return str.substring(0, range[0]) + replacement + str.substring(range[1]);\n            }\n        });\n    },\n\n    comment: function(range) {\n        this.modifications.push({\n            index: range[0],\n            precedence: 1,\n            toString: function() {\n                return 'comment ' + range;\n            },\n            transform: function(str) {\n                const code = str.substring(range[0], range[1]);\n                return str.substring(0, range[0]) + '/*' + code + '*/' + str.substring(range[1]);\n            }\n        });\n    }\n};\n\nmodule.exports = StringTransformer;\n"
  },
  {
    "path": "src/require/util/Transforms.js",
    "content": "const logger = require('raptor-logging').logger(module);\nconst crypto = require('crypto');\nconst ok = require('assert').ok;\nconst PassThrough = require('stream').PassThrough;\nconst inspect = require('util').inspect;\nconst util = require('util');\nconst stream = require('stream');\nconst resolveFrom = require('resolve-from');\n\nclass TransformAdaptorStream extends stream.Transform {\n    constructor(transform, lassoContext) {\n        super();\n        this.data = '';\n        this.transformFunc = transform.func;\n        this.lassoContext = lassoContext;\n        this.transformName = transform.name;\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        // On the last flush we apply the transform by calling the transform function on the\n        // data string that was collected from all input chunks\n        const transformFunc = this.transformFunc;\n        let result = transformFunc(this.data, this.lassoContext);\n        if (result == null) {\n            result = '';\n        }\n\n        if (typeof result === 'string') { // Did the transform synchronously return some data?\n            this.push(result);\n            callback();\n        } else if (typeof result.then === 'function') { // Did the transform return a promise\n            // The transform appears to have returned a Promise\n            result\n                .then((code) => {\n                    this.push(code);\n                    callback();\n                })\n                .catch((err) => {\n                    try {\n                        this.emit('error', err);\n                    } finally {\n                        callback();\n                    }\n                });\n        } else {\n            // Invalid transform...\n            try {\n                this.emit('error', new Error(`The ${this.transformName} did not return a valid value`));\n            } finally {\n                callback();\n            }\n        }\n    }\n}\n\nfunction resolvePath(path, projectRoot) {\n    let resolvedPath;\n\n    if (projectRoot) {\n        resolvedPath = resolveFrom(projectRoot, path);\n        if (resolvedPath) {\n            return resolvedPath;\n        }\n    } else {\n        resolvedPath = resolveFrom(process.cwd(), path);\n        if (resolvedPath) {\n            return resolvedPath;\n        }\n    }\n\n    return require.resolve(path);\n}\n\nclass Transforms {\n    constructor(transforms, projectRoot) {\n        this._transforms = new Array(transforms.length);\n\n        const shasum = crypto.createHash('sha1');\n\n        transforms.forEach((curTransform, i) => {\n            if (!curTransform) {\n                throw new Error('Invalid require transform at index ' + i);\n            }\n\n            let transformFunc;\n            let transformId;\n            let stream = true;\n            let transformName;\n\n            if (typeof curTransform === 'string') {\n                curTransform = {\n                    transform: curTransform\n                };\n            } else if (typeof curTransform === 'function') {\n                curTransform = {\n                    transform: curTransform\n                };\n            }\n\n            if (typeof curTransform === 'object') {\n                let transform = curTransform.transform;\n\n                if (transform) {\n                    if (typeof transform === 'string') {\n                        const transformPath = resolvePath(transform, projectRoot);\n                        transform = require(transformPath);\n                        transformId = transform.id || transformPath;\n                    }\n                } else {\n                    transform = curTransform;\n                }\n\n                const transformConfig = curTransform.config;\n\n                if (typeof transform === 'function') {\n                    stream = true;\n\n                    // Looks like a browserify style-transform\n                    transformFunc = function(path, lassoContext) {\n                        return transform(path, transformConfig);\n                    };\n\n                    transformId = transformFunc.toString();\n                } else if (transform.createTransform) {\n                    stream = transform.stream !== false;\n                    transformName = transform.name;\n\n                    transformFunc = transform.createTransform(transformConfig || {});\n                    transformId = transform.id || transform.createTransform.toString();\n                } else {\n                    throw new Error('Invalid require transform at index ' + i + ': ' + util.inspect(curTransform));\n                }\n            } else {\n                throw new Error('Invalid require transform at index ' + i + ': ' + util.inspect(curTransform));\n            }\n\n            if (!transformId) {\n                transformId = transformFunc.toString();\n            }\n\n            ok(typeof transformFunc === 'function', 'Invalid transform at index ' + i);\n\n            this._transforms[i] = {\n                func: transformFunc,\n                id: transformId,\n                name: transformName || transformFunc.name,\n                stream\n            };\n\n            shasum.update(transformId);\n        });\n\n        this.id = shasum.digest('hex');\n    }\n\n    apply(path, inStream, lassoContext) {\n        ok(inStream, 'inStream is required');\n        const transforms = this._transforms;\n\n        lassoContext = Object.create(lassoContext);\n        lassoContext.filename = path;\n\n        const len = transforms.length;\n        if (!len) {\n            // If there are no transforms then just return the input stream\n            return inStream;\n        }\n\n        function applyTransform(input, transform) {\n            if (transform.stream === false) {\n                // The TransformAdaptorStream class extends stream.Transform and it is used\n                // to convert a synchronous or Promise transform to a stream-based transform\n                return input.pipe(new TransformAdaptorStream(transform, lassoContext));\n            } else {\n                return input.pipe(transform.func(path, lassoContext));\n            }\n        }\n\n        return lassoContext.deferredStream(function() {\n            const deferredStream = this;\n\n            let finished = false;\n\n            function handleError(e) {\n                if (finished) {\n                    return;\n                }\n\n                finished = true;\n                deferredStream.emit('error', e);\n                deferredStream.push(null); // End the stream just in case\n            }\n\n            inStream.on('error', handleError);\n\n            const passThrough = new PassThrough({\n                encoding: 'utf8'\n            });\n\n            let out = passThrough;\n\n            for (let i = 0, len = transforms.length; i < len; i++) {\n                const curTransform = transforms[i];\n\n                const transformName = curTransform.name;\n\n                if (logger.isDebugEnabled()) {\n                    logger.debug('Applying transform ' + transformName);\n                }\n\n                // applyTransform will return a new stream that we can read from\n                out = applyTransform(out, curTransform);\n\n                if (typeof out.pipe !== 'function') {\n                    return handleError(new Error('Non-stream object returned from transform (transform=' + transformName + ', output=' + inspect(out) + ')'));\n                }\n\n                out.on('error', handleError);\n            }\n\n            // Now start the flow of data at the source by piping the input stream\n            // to the beginning of our transform chain (i.e. the initial pass thorugh stream)\n            inStream.pipe(passThrough);\n\n            return out;\n        });\n    }\n}\n\nmodule.exports = Transforms;\n"
  },
  {
    "path": "src/require/util/inspect.js",
    "content": "const path = require('path');\nconst espree = require('espree');\nconst codeFrame = require('@babel/code-frame').default;\nconst estraverse = require('estraverse');\nconst ok = require('assert').ok;\nconst cwd = process.cwd();\n\nconst parseOpts = {\n    range: true,\n    sourceType: 'script',\n    ecmaVersion: espree.latestEcmaVersion\n};\n\nconst shortCircuitRegExp = /require\\(|require\\.resolve\\(|.async\\(|#async|process|Buffer/;\n\nfunction isRequire(node) {\n    return node.type === 'CallExpression' &&\n        node.callee.type === 'Identifier' &&\n        node.callee.name === 'require' &&\n        node.arguments.length === 1 &&\n        node.arguments[0].type === 'Literal' &&\n        typeof node.arguments[0].value === 'string';\n}\n\nfunction isRequireResolve(node) {\n    return node.type === 'CallExpression' &&\n        node.callee.type === 'MemberExpression' &&\n        node.callee.object.type === 'Identifier' &&\n        node.callee.object.name === 'require' &&\n        node.callee.property.type === 'Identifier' &&\n        node.callee.property.name === 'resolve' &&\n        node.arguments.length === 1 &&\n        node.arguments[0].type === 'Literal';\n}\n\nfunction isRequireFor(node, moduleName) {\n    return node.type === 'CallExpression' &&\n        node.callee.type === 'Identifier' &&\n        node.callee.name === 'require' &&\n        node.arguments.length === 1 &&\n        node.arguments[0].type === 'Literal' &&\n        node.arguments[0].value === moduleName;\n}\n\nfunction isRequireForAsyncLoader(node) {\n    return isRequireFor(node, 'lasso-loader') ||\n        isRequireFor(node, 'raptor-loader');\n}\n\nfunction isAsyncNode(node, scope) {\n    if (!node.arguments || !node.arguments.length) {\n        return false;\n    }\n\n    if (node.type !== 'CallExpression' ||\n        node.callee.type !== 'MemberExpression' ||\n        node.callee.property.type !== 'Identifier' ||\n        node.callee.property.name !== 'async') {\n        return false;\n    }\n\n    if (isRequireForAsyncLoader(node.callee.object)) {\n        return true;\n    }\n\n    if (node.callee.object.type === 'Identifier' &&\n        (scope[node.callee.object.name] === 'lasso-loader')) {\n        return true;\n    }\n\n    return false;\n}\n\nfunction parseAsyncNode(node, scope) {\n    if (!isAsyncNode(node, scope)) {\n        return;\n    }\n\n    const args = node.arguments;\n    const numArguments = args.length;\n    if ((numArguments < 1) || (numArguments > 2)) {\n        return;\n    }\n\n    const dependencies = [];\n    let hasInlineDependencies = false;\n    let packageIdProvided;\n    const firstArg = args[0];\n\n    // We only care if about the async calls if the first argument is an array\n    if (numArguments === 2) {\n        if (firstArg.type === 'ArrayExpression') {\n            hasInlineDependencies = true;\n            // call is something like:\n            //     require('lasso-loader').async(['./dep1.js', './dep2.js'], callback)\n            const elems = firstArg.elements;\n            for (let i = 0; i < elems.length; i++) {\n                dependencies.push(elems[i].value);\n            }\n        } else {\n            // call is something like:\n            //    require('lasso-loader').async('somePackageId', callback)\n            //    require('lasso-loader').async(someVariable, callback)\n            packageIdProvided = true;\n        }\n    }\n\n    const callbackNode = args[numArguments - 1];\n\n    const hasFunctionBody =\n        (callbackNode.type === 'FunctionExpression') ||\n        (callbackNode.type === 'FunctionDeclaration');\n\n    return {\n        node,\n        requires: [],\n        dependencies,\n        args,\n        callbackNode,\n\n        // require('lasso-loader').async(packageId, function() {}) is used\n        // then `packageIdProvided` will be `true`\n        packageIdProvided,\n\n        // Store the range of the first arg in case we need to replace\n        // or add to it.\n        firstArgRange: args[0].range,\n\n        // If the first argument to require('lasso-loader').async([...], callback) is\n        // is used then `hasInlineDependencies` will be `true`\n        hasInlineDependencies,\n\n        // If the last argument to require('lasso-loader').async(...)\n        // is a `FunctionDeclaration` or `FunctionExpression` then\n        // `hasFunctionBody` will be `true`.\n        hasFunctionBody,\n\n        toString: function() {\n            return '[async: ' + this.name + ', dependencies=' + JSON.stringify(dependencies) + ']';\n        }\n    };\n}\n\nfunction recordGlobalsHelper(node, scope, foundGlobals) {\n    if (!node || node.type !== 'Identifier') {\n        return;\n    }\n\n    const id = node.name;\n\n    if (id === 'require' ||\n        id === 'exports' ||\n        id === 'module' ||\n        id === 'arguments' ||\n        id === '__dirname' ||\n        id === '__filename') {\n        // We don't require about these \"globals\"\n        return;\n    }\n\n    if (!scope[id]) {\n        foundGlobals[id] = true;\n    }\n}\n\nfunction recordGlobals(node, parentNode, scope, foundGlobals) {\n    if (node.type === 'Identifier') {\n        if (parentNode.type === 'MemberExpression' ||\n            parentNode.type === 'Property' ||\n            parentNode.type === 'VariableDeclarator' ||\n            parentNode.type === 'FunctionDeclaration' ||\n            parentNode.type === 'FunctionExpression') {\n            return;\n        }\n        recordGlobalsHelper(node, scope, foundGlobals);\n    } else if (node.type === 'MemberExpression') {\n        if (parentNode !== 'MemberExpression') {\n            recordGlobalsHelper(node.object, scope, foundGlobals);\n        }\n    } else if (node.type === 'Property') {\n        recordGlobalsHelper(node.value, scope, foundGlobals);\n    } else if (node.type === 'VariableDeclarator') {\n        recordGlobalsHelper(node.init, scope, foundGlobals);\n    } else if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {\n        if (node.type === 'FunctionDeclaration' && node.id) {\n            delete foundGlobals[node.id.name];\n        }\n\n        // Skip the params and the function ID and just look at the body nodes\n        node.body.body.forEach((bodyNode) => {\n            recordGlobalsHelper(bodyNode, scope, foundGlobals);\n        });\n    }\n}\n\nmodule.exports = function inspect(src, options) {\n    ok(src != null, 'src is requried');\n\n    const allowShortcircuit = !options || options.allowShortcircuit !== false;\n\n    if (allowShortcircuit && shortCircuitRegExp.test(src) === false) {\n        // Nothing of interest so nothing to do\n        return {\n            requires: [],\n            foundGlobals: {},\n            asyncBlocks: []\n        };\n    }\n\n    const requires = [];\n    const scopeStack = [{}];\n    const asyncScopeStack = [];\n    const asyncStack = [];\n    let curAsyncInfo = null;\n    let asyncBlocks = [];\n    const foundGlobals = {};\n\n    let parsedAst;\n    try {\n        parsedAst = espree.parse(src, parseOpts);\n    } catch (err) {\n        if (!err.lineNumber) {\n            throw err;\n        }\n\n        const filename = options && options.filename;\n        let errorLoc = '(' + err.lineNumber + ',' + err.column + '): ';\n        if (filename) {\n            errorLoc = path.relative(cwd, filename) + errorLoc;\n        }\n\n        const frame = codeFrame(src, err.lineNumber, err.column, { highlightCode: true });\n        throw new SyntaxError(errorLoc + err.message + '\\n' + frame);\n    }\n\n    estraverse.traverse(parsedAst, {\n        enter: function(node, parentNode) {\n            let scope = scopeStack[scopeStack.length - 1];\n\n            if (node.type === 'VariableDeclaration') {\n                node.declarations.forEach(function(varDecl) {\n                    if (varDecl.init && isRequireForAsyncLoader(varDecl.init)) {\n                        scope[varDecl.id.name] = 'lasso-loader';\n                    } else {\n                        scope[varDecl.id.name] = true;\n                    }\n                });\n            } else if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') {\n                scope = Object.create(scope);\n                node.params.forEach((param) => {\n                    scope[param.name] = true;\n                });\n\n                if (node.type === 'FunctionDeclaration') {\n                    scopeStack[scopeStack.length - 1][node.id.name] = true;\n                }\n\n                scopeStack.push(scope);\n            }\n\n            recordGlobals(node, parentNode, scope, foundGlobals);\n\n            let requirePath;\n\n            if (!scope.require && (isRequire(node) || isRequireResolve(node))) {\n                requirePath = node.arguments[0].value;\n\n                const range = node.range;\n\n                const firstArgRange = node.arguments[0].range;\n\n                if (asyncScopeStack.length) {\n                    // We are in the scope of an async callback function so this\n                    // is a dependency that will be lazily loaded\n                    if (requirePath !== 'lasso-loader' && requirePath !== 'raptor-loader') {\n                        const lastAsyncInfo = asyncScopeStack[asyncScopeStack.length - 1];\n\n                        lastAsyncInfo.requires.push({\n                            path: requirePath,\n                            range,\n                            argRange: firstArgRange\n                        });\n\n                        lastAsyncInfo.dependencies.push({\n                            type: 'require',\n                            path: requirePath\n                        });\n                    }\n                } else {\n                    requires.push({\n                        path: requirePath,\n                        range,\n                        argRange: firstArgRange\n                    });\n                }\n            }\n\n            let asyncInfo;\n            if ((asyncInfo = parseAsyncNode(node, scopeStack[scopeStack.length - 1]))) {\n                curAsyncInfo = asyncInfo;\n                asyncBlocks.push(asyncInfo);\n                asyncStack.push(asyncInfo);\n            } else if (curAsyncInfo && node === curAsyncInfo.callbackNode) {\n                // We are in the scope of the async callback function so\n                // all dependencies below this will be async\n                asyncScopeStack.push(curAsyncInfo);\n                curAsyncInfo = null;\n            }\n        },\n\n        leave: function(node, parentNode) {\n            if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') {\n                scopeStack.pop();\n            }\n\n            if (asyncStack.length && node === asyncStack[asyncStack.length - 1].node) {\n                asyncStack.pop();\n            } else if (asyncScopeStack.length && node === asyncScopeStack[asyncScopeStack.length - 1].callbackNode) {\n                asyncScopeStack.pop();\n            }\n        }\n    });\n\n    asyncBlocks = asyncBlocks.map((asyncBlock) => {\n        delete asyncBlock.node;\n        delete asyncBlock.args;\n        delete asyncBlock.callbackNode;\n        return asyncBlock;\n    });\n\n    return {\n        requires,\n        foundGlobals,\n        asyncBlocks\n    };\n};\n"
  },
  {
    "path": "src/require/util/normalizeFSPath.js",
    "content": "const lassoModulesClientTransport = require('lasso-modules-client/transport');\n\nfunction normalizeFSPath(path) {\n    return lassoModulesClientTransport.getClientPath(path);\n}\n\nmodule.exports = normalizeFSPath;\n"
  },
  {
    "path": "src/require/util/streamToString.js",
    "content": "module.exports = function(stream) {\n    return new Promise((resolve, reject) => {\n        let str = '';\n        stream\n            .on('data', function(data) {\n                str += data;\n            })\n            .on('error', function(err) {\n                reject(err);\n            })\n            .on('end', function() {\n                resolve(str);\n            });\n    });\n};\n"
  },
  {
    "path": "src/resolve/builtins.js",
    "content": "const lassoResolveFrom = require('lasso-resolve-from');\nconst extend = require('raptor-util/extend');\n\nfunction resolveBuiltin(target) {\n    const resolved = lassoResolveFrom(__dirname, target);\n    if (!resolved) {\n        throw new Error('Missing builtin: ' + target);\n    }\n    return resolved.path;\n}\n\nconst defaultBuiltins = {\n    assert: resolveBuiltin('assert'),\n    buffer: resolveBuiltin('buffer'),\n    events: resolveBuiltin('events'),\n    'lasso-loader': resolveBuiltin('lasso-loader'),\n    path: resolveBuiltin('path-browserify'),\n    process: resolveBuiltin('process'),\n    'raptor-loader': resolveBuiltin('lasso-loader'),\n    stream: resolveBuiltin('stream-browserify'),\n    string_decoder: resolveBuiltin('string_decoder'),\n    url: resolveBuiltin('url'),\n    util: resolveBuiltin('util')\n};\n\nexports.getBuiltins = function(additionalBuiltins) {\n    const allBuiltins = extend({}, defaultBuiltins);\n\n    function addBuiltins(builtins) {\n        Object.keys(builtins).forEach(function(packageName) {\n            const builtinTarget = builtins[packageName];\n\n            if (typeof builtinTarget !== 'string') {\n                throw new Error('Invalid builtin: ' + packageName + ' (target: ' + builtinTarget + ')');\n            }\n\n            allBuiltins[packageName] = builtinTarget;\n        });\n    }\n\n    if (additionalBuiltins) {\n        addBuiltins(additionalBuiltins);\n    }\n\n    return allBuiltins;\n};\n"
  },
  {
    "path": "src/resolve/getRequireRemapFromDir.js",
    "content": "const nodePath = require('path');\n\nmodule.exports = function(fromDir, lassoContext) {\n    const lassoJsonPath = nodePath.join(fromDir, 'browser.json');\n    let remap;\n\n    if (lassoContext.cachingFs.existsSync(lassoJsonPath)) {\n        const lassoPackage = lassoContext.readPackageFile(lassoJsonPath);\n        remap = lassoPackage.getRequireRemap(lassoContext);\n    }\n\n    return remap;\n};\n"
  },
  {
    "path": "src/resolve/index.js",
    "content": "const builtinsModule = require('./builtins');\nconst parseRequire = require('./parseRequire');\nconst nodePath = require('path');\nconst getRequireRemapFromDir = require('./getRequireRemapFromDir');\nconst lassoResolveFrom = require('lasso-resolve-from');\nconst ok = require('assert').ok;\nconst cachingFs = require('../caching-fs');\n\nconst _normalizePath = nodePath.sep === '/'\n    ? function _normalizePathUnix(path) {\n        // nothing to do for non-Windows platform\n        return path;\n    }\n    : function _normalizePathWindows(path) {\n        // replace back-slash with forward-slash\n        return path.replace(/[\\\\]/g, '/');\n    };\n\nexports.createResolver = function(lassoContext, getClientPath) {\n    const resolverConfig = lassoContext.config && lassoContext.config.resolver;\n    const requireConfig = lassoContext.config && lassoContext.config._requirePluginConfig;\n    const builtinsConfig = (resolverConfig && resolverConfig.builtins) || (requireConfig && requireConfig.builtins);\n\n    const postResolveFn = resolverConfig && resolverConfig.postResolve;\n    const builtins = builtinsModule.getBuiltins(builtinsConfig);\n\n    function resolve(targetModule, fromDir, options) {\n        ok(targetModule, '\"targetModule\" is required');\n        ok(typeof targetModule === 'string', '\"targetModule\" should be a string');\n        ok(typeof fromDir === 'string', '\"fromDir\" should be a string');\n\n        const parsedRequire = parseRequire(targetModule);\n\n        // Normalize the path by making sure the path separator is always forward slash\n        // (normalize does nothing on non-Windows platform)\n        targetModule = _normalizePath(parsedRequire.path);\n\n        const dependencyType = parsedRequire.type;\n\n        const resolveOptions = {\n            includeMeta: true\n        };\n\n        resolveOptions.extensions = lassoContext.dependencyRegistry.getRequireExtensionNames();\n\n        resolveOptions.remaps = function(dir) {\n            return lassoContext && getRequireRemapFromDir(dir, lassoContext);\n        };\n\n        let resolvedInfo = lassoResolveFrom(fromDir, targetModule, resolveOptions);\n\n        const isBuiltin = resolvedInfo && builtins && builtins[targetModule] === resolvedInfo.path;\n\n        if (!(resolvedInfo && !isBuiltin)) {\n            if (targetModule.charAt(0) === '.') {\n                return null;\n            }\n\n            const resolvedBuiltin = builtins[targetModule];\n\n            if (resolvedBuiltin) {\n                resolvedInfo = {\n                    path: resolvedBuiltin,\n                    meta: [\n                        {\n                            type: 'builtin',\n                            name: targetModule,\n                            target: resolvedBuiltin\n                        }\n                    ]\n                };\n            } else if (options && options.moduleFallbackToRelative) {\n                const resolvedPath = nodePath.resolve(fromDir, targetModule);\n\n                // Since the path looked like it was for a module we should check\n                // to see if the fallback technique actually found a file. If file\n                // does not exist for fallback path, then we'll report an error\n                // that the module does not exist by re-throwing the original error.\n                if (cachingFs.existsSync(resolvedPath)) {\n                    // Fallback technique found the path.\n                    // We might want to log something here to suggest that relative\n                    // paths be prefixed with \".\" to avoid the extra work of trying to\n                    // resolve path using NodeJS module search path.\n                    resolvedInfo = {\n                        path: resolvedPath\n                    };\n                }\n            }\n        }\n\n        if (resolvedInfo) {\n            if (postResolveFn) {\n                postResolveFn(resolvedInfo, lassoContext);\n            }\n\n            const result = {\n                path: resolvedInfo.path,\n                meta: resolvedInfo.meta,\n                clientPath: getClientPath(resolvedInfo.path)\n            };\n\n            if (resolvedInfo.voidRemap) {\n                result.voidRemap = true;\n            }\n\n            if (dependencyType) {\n                result.type = dependencyType;\n            }\n\n            return result;\n        } else {\n            // Path is not a module or resolved path\n            throw new Error('Failed to resolve \"' + targetModule + '\". Target file does not exist. Started search from directory \"' + fromDir + '\".');\n        }\n    }\n\n    function resolveCached(targetModule, fromDir, options) {\n        if (!lassoContext.cache) {\n            return resolve(targetModule, fromDir, options);\n        }\n\n        const key = targetModule + '@' + fromDir;\n        const cache = lassoContext.cache.getSyncCache('resolve');\n\n        let result = cache.getSync(key);\n\n        if (result === undefined) {\n            result = resolve(targetModule, fromDir, options);\n            cache.putSync(key, result || null);\n        }\n\n        return result || undefined;\n    }\n\n    return {\n        resolve,\n        resolveCached\n    };\n};\n"
  },
  {
    "path": "src/resolve/parseRequire.js",
    "content": "module.exports = function parseRequire(path) {\n    const typeSeparatorIndex = path.indexOf(':');\n\n    // NOTE: Windows paths may have drive letter followed by colon.\n    // If colon is the second character then assume it is a\n    // file system path.\n    if (typeSeparatorIndex !== -1 &&\n            typeSeparatorIndex > 1 /* Fixes Issue: https://github.com/lasso-js/lasso/issues/65 */) {\n        const type = path.substring(0, typeSeparatorIndex).trim();\n        path = path.substring(typeSeparatorIndex + 1).trim();\n\n        return {\n            type,\n            path\n        };\n    } else {\n        return {\n            path\n        };\n    }\n};\n"
  },
  {
    "path": "src/transforms.js",
    "content": "const inspect = require('util').inspect;\nconst ok = require('assert').ok;\nconst DeferredReadable = require('./util').DeferredReadable;\nconst PassThrough = require('stream').PassThrough;\nconst through = require('through');\n\nfunction Transformer(transforms) {\n    this.transforms = transforms;\n}\n\nfunction handleNonStreamTransform(inStream, transform, applyTransform, handleError) {\n    let code = '';\n\n    const outStream = through(\n        function write(data) {\n            code += data;\n        },\n        function end() {\n            function handleTransformedCode(transformedCode) {\n                outStream.push(transformedCode);\n                outStream.push(null);\n            }\n\n            const transformedCode = applyTransform(code, transform);\n\n            if (transformedCode != null) {\n                if (typeof transformedCode === 'string') {\n                    handleTransformedCode(transformedCode);\n                } else if (typeof transformedCode.then === 'function') {\n                    transformedCode\n                        .then(function(transformedCode) {\n                            handleTransformedCode(transformedCode);\n                        })\n                        .catch(handleError);\n                } else {\n                    handleError(new Error('Invalid return for transform: ' + transformedCode));\n                }\n            }\n        });\n\n    return outStream;\n}\n\nTransformer.prototype = {\n    hasTransforms () {\n        return this.transforms.length !== 0;\n    },\n\n    transform (inStream, lassoContext) {\n        const transforms = this.transforms;\n\n        if (!transforms.length) {\n            return inStream;\n        }\n\n        ok(lassoContext, 'lassoContext is required');\n        ok(inStream, 'inStream is required');\n        const config = lassoContext.config;\n        ok(config, 'config expected in context');\n\n        function applyTransform(input, transform) {\n            return transform.transform(input, lassoContext);\n        }\n\n        return new DeferredReadable(function() {\n            const deferredStream = this;\n\n            function handleError(e) {\n                deferredStream.emit('error', e);\n                deferredStream.push(null); // End the stream just in case\n            }\n\n            inStream.on('error', handleError);\n\n            const passThrough = new PassThrough();\n\n            let out = passThrough;\n\n            for (let i = 0, len = transforms.length; i < len; i++) {\n                const transform = transforms[i];\n\n                if (transform.stream === true) {\n                    // applyTransform will return a new stream that we can read from\n                    out = applyTransform(out, transform);\n\n                    if (typeof out.pipe !== 'function') {\n                        return handleError(\n                            new Error('Non-stream object returned from transform (transform=' +\n                            inspect(transform) + ', output=' + inspect(out) + ')'));\n                    }\n                } else {\n                    // The transform doesn't want a stream so we have to do some additional processing...\n                    out = out.pipe(handleNonStreamTransform(out, transform, applyTransform, handleError));\n                }\n\n                out.on('error', handleError);\n            }\n\n            // Add some listeners to the output stream returned by the final transform\n\n            out.on('data', function(data) {\n                deferredStream.push(data);\n            });\n\n            out.on('end', function() {\n                deferredStream.push(null);\n            });\n\n            // Now start the flow of data at the source by piping the input stream\n            // to the beginning of our transform chain (i.e. the initial pass thorugh stream)\n            inStream.pipe(passThrough);\n        });\n    }\n};\n\nasync function filterTransform (lassoContext, transformConfig) {\n    return transformConfig.filter ? transformConfig.filter(lassoContext) : true;\n}\n\nexports.createTransformer = async function (unfilteredTransforms, lassoContext) {\n    if (unfilteredTransforms) {\n        ok(Array.isArray(unfilteredTransforms), 'unfilteredTransforms should be an array');\n    }\n\n    const contentType = lassoContext.contentType;\n    ok(typeof contentType === 'string', '\"contentType\" is required');\n\n    const filteredTransforms = [];\n    for (const unfilteredTransform of unfilteredTransforms) {\n        const keep = await filterTransform(lassoContext, unfilteredTransform);\n        if (keep) {\n            filteredTransforms.push(unfilteredTransform);\n        }\n    }\n\n    return new Transformer(filteredTransforms);\n};\n"
  },
  {
    "path": "src/util/CombinedStream.js",
    "content": "const Readable = require('stream').Readable;\n\nconst inherit = require('raptor-util/inherit');\n\nfunction CombinedStream(options) {\n    CombinedStream.$super.call(this, options);\n\n    const streams = this.streams = [];\n    const combined = this;\n    let separator;\n    let curStream;\n    let i = -1;\n    let len;\n    let paused = false;\n    let reading = false;\n\n    if (options) {\n        separator = options.separator;\n        delete options.separator;\n    }\n\n    function onError(err) {\n        combined.emit('error', err);\n    }\n\n    function onData(chunk) {\n        if (combined.push(chunk) === false) {\n            paused = true;\n            curStream.pause();\n        }\n    }\n\n    let depth = 0;\n\n    /*\n    Node.js internally uses process.nextTick() during stream data\n    flow events. Node.js checks to make sure that process.nextTick()\n    is not called with too much recursion because this will starve\n    I/O event processing. The dependency streams may have read all of\n    their data so process.nextTick() could be called recursively more than\n    the allowed limit. The recommended approach for avoiding this limit\n    is to use setImmediate() to give the event loop a chance to handle\n    I/O events.\n\n    Recursive process.nextTick detected\" from within stream code #6065\n    https://github.com/joyent/node/issues/6065\n\n    stream: readable _read blocking script execution #7401\n    https://github.com/joyent/node/issues/7401\n    */\n    function cautiousNext() {\n        depth++;\n        if (depth > 100) {\n            depth = 0;\n            setImmediate(next);\n        } else {\n            next();\n        }\n    }\n\n    function next() {\n        if (curStream) {\n            combined.emit('endStream', {\n                stream: curStream,\n                index: i\n            });\n        }\n\n        if (++i >= len) {\n            // we're done\n            combined.push(null);\n        } else {\n            if (separator && curStream) {\n                combined.push(separator);\n            }\n            combined.curStream = curStream = streams[i];\n            combined.emit('beginStream', {\n                stream: curStream,\n                index: i\n            });\n\n            if (typeof curStream === 'string') {\n                onData(curStream);\n                cautiousNext();\n            } else {\n                curStream.on('end', cautiousNext);\n                curStream.on('error', onError);\n                curStream.on('data', onData);\n                // make sure the current stream is resumed\n                curStream.resume();\n            }\n        }\n    }\n\n    this._read = function() {\n        if (reading) {\n            if (paused) {\n                curStream.resume();\n            }\n        } else {\n            reading = true;\n            len = streams.length;\n\n            if (len === 0) {\n                combined.push(null);\n            } else {\n                cautiousNext();\n            }\n        }\n    };\n}\n\nCombinedStream.prototype.addStream = function(stream) {\n    this.streams.push(stream);\n};\n\nCombinedStream.prototype.getStream = function(index) {\n    return this.streams[index];\n};\n\nCombinedStream.prototype.getStreamCount = function(stream) {\n    return this.streams.length;\n};\n\nCombinedStream.prototype.forEachStream = function(fn) {\n    return this.streams.forEach(fn);\n};\n\ninherit(CombinedStream, Readable);\n\nmodule.exports = CombinedStream;\n"
  },
  {
    "path": "src/util/DeferredReadable.js",
    "content": "const Readable = require('stream').Readable;\nconst inherit = require('raptor-util/inherit');\n\nfunction DeferredReadable(startFn, options) {\n    if (startFn && typeof startFn !== 'function') {\n        options = startFn;\n        startFn = null;\n    }\n\n    DeferredReadable.$super.call(this, options);\n\n    let readCalled = false;\n    let wrappedStream = null;\n    let paused = false;\n    const _this = this;\n\n    let ended = false;\n    let chunkCount = 0;\n\n    let queuedEmits;\n\n    this.on('ready', function (wrappedStream) {\n        _this.setWrappedStream(wrappedStream);\n    });\n\n    function startReadingWrappedStream() {\n        wrappedStream\n            .on('end', function() {\n                ended = true;\n                _this.push(null);\n            })\n            .on('error', function(err) {\n                _this.emit('error', err);\n            })\n            .on('data', function(data) {\n                chunkCount++;\n                if (_this.push(data) === false) {\n                    paused = true;\n                    wrappedStream.pause();\n                }\n            })\n            .resume();\n    }\n\n    this.emit = function(type) {\n        if (readCalled || type !== 'error') {\n            Readable.prototype.emit.apply(this, arguments);\n        } else {\n            // Queue up error events if we haven't started reading\n            if (!queuedEmits) {\n                queuedEmits = [arguments];\n            } else {\n                queuedEmits.push(arguments);\n            }\n        }\n    };\n\n    this._read = function() {\n        if (readCalled) {\n            if (wrappedStream && paused) {\n                paused = false;\n                wrappedStream.resume();\n            }\n        } else {\n            readCalled = true;\n\n            if (queuedEmits) {\n                for (let i = 0, len = queuedEmits.length; i < len; i++) {\n                    Readable.prototype.emit.apply(this, queuedEmits[i]);\n                }\n                queuedEmits = undefined;\n            }\n\n            if (wrappedStream) {\n                startReadingWrappedStream();\n            } else if (startFn) {\n                const result = startFn.call(this);\n\n                if (result) {\n                    this.setWrappedStream(result);\n                }\n            }\n        }\n    };\n\n    this.setWrappedStream = function(stream) {\n        wrappedStream = stream;\n\n        if (readCalled) {\n            startReadingWrappedStream();\n        }\n    };\n\n    this.toString = function() {\n        return '[DeferredReadable readCalled=' + readCalled + ', ended=' + ended + ', chunkCount=' + chunkCount + ', wrappedStream=' + wrappedStream + ']';\n    };\n}\n\ninherit(DeferredReadable, Readable);\n\nmodule.exports = DeferredReadable;\n"
  },
  {
    "path": "src/util/caching-stream.js",
    "content": "const inherit = require('raptor-util/inherit');\n\nconst Transform = require('stream').Transform;\nconst Readable = require('stream').Readable;\n\n// ReplayStream\nfunction ReplayStream(cachingStream, options) {\n    ReplayStream.$super.call(this, options);\n\n    const _this = this;\n    const _chunks = cachingStream._chunks;\n    let _pos = 0;\n\n    function continueReading() {\n        while (_pos < _chunks.length) {\n            if (_this.push(_chunks[_pos++]) === false) {\n                break;\n            }\n        }\n    }\n\n    if (cachingStream._finished === false) {\n        cachingStream\n            .on('_newData', continueReading)\n            .once('end', function() {\n                cachingStream.removeListener('_newData', continueReading);\n            });\n    }\n\n    this._read = continueReading;\n\n    this.toString = function(size) {\n        return '[ReplayStream chunkCount=' + _chunks.length + ', pos=' + _pos + ']';\n    };\n}\n\ninherit(ReplayStream, Readable);\n\n// CachingStream\nfunction CachingStream(options) {\n    CachingStream.$super.call(this, options);\n    this._chunks = [];\n    this._finished = false;\n}\n\nCachingStream.prototype._transform = function(chunk, encoding, callback) {\n    // console.log(module.id, 'caching stream push: '÷, chunk.toString('utf8'));\n    this._chunks.push(chunk); // Cache the chunk\n    this.emit('_newData');\n\n    this.push(chunk);\n    callback();\n};\n\nCachingStream.prototype._flush = function(callback) {\n    // console.log(module.id, 'caching stream end');\n    this._chunks.push(null);\n    this.emit('_newData');\n    this._finished = true;\n    callback();\n};\n\nCachingStream.prototype.createReplayStream = function(options) {\n    return new ReplayStream(this, options);\n};\n\nCachingStream.prototype.toString = function() {\n    return '[CachingStream len=' + this._chunks.length + ']';\n};\n\ninherit(CachingStream, Transform);\n\nexports.create = function(options) {\n    return new CachingStream(options);\n};\n"
  },
  {
    "path": "src/util/fingerprint-stream.js",
    "content": "const crypto = require('crypto');\nconst inherit = require('raptor-util/inherit');\nconst Transform = require('stream').Transform;\n\nfunction FingerprintStream(options) {\n    FingerprintStream.$super.call(this, options);\n    this._shasum = crypto.createHash('sha1');\n    this._fingerprint = null;\n}\n\nFingerprintStream.prototype._transform = function(chunk, encoding, callback) {\n    this._shasum.update(chunk);\n    this.push(chunk);\n    callback();\n};\n\nFingerprintStream.prototype._flush = function(callback) {\n    this._fingerprint = this._shasum.digest('hex');\n    this._shasum = null;\n    this.emit('fingerprint', this._fingerprint);\n\n    callback();\n};\n\nFingerprintStream.prototype.on = function(event, callback) {\n    if (event === 'fingerprint' && this._fingerprint) {\n        callback.call(this, this._fingerprint);\n        return this;\n    } else {\n        return FingerprintStream.$super.prototype.on.apply(this, arguments);\n    }\n};\n\ninherit(FingerprintStream, Transform);\n\nexports.create = function() {\n    return new FingerprintStream();\n};\n"
  },
  {
    "path": "src/util/hash.js",
    "content": "const crypto = require('crypto');\n\nexports.HASH_OVERFLOW_LENGTH = 8;\n\nexports.generate = function (str, len) {\n    let hash = crypto.createHash('sha1')\n        .update(str)\n        .digest('hex');\n\n    if (len != null) hash = hash.substring(0, len);\n    return hash;\n};\n"
  },
  {
    "path": "src/util/index.js",
    "content": "const cachingStream = require('./caching-stream');\nconst fingerprintStream = require('./fingerprint-stream');\nconst DeferredReadable = require('./DeferredReadable');\nconst logger = require('raptor-logging').logger(module);\n// var DEFAULT_READ_FILE_OPTIONS = {encoding: 'utf8'};\n\nfunction merge(src, dest) {\n    if (src != null &&\n        dest != null &&\n        !Array.isArray(src) &&\n        !Array.isArray(dest) &&\n        typeof src === 'object' &&\n        typeof dest === 'object') {\n        Object.getOwnPropertyNames(src)\n            .forEach(function(prop) {\n                const descriptor = Object.getOwnPropertyDescriptor(src, prop);\n                descriptor.value = merge(descriptor.value, dest[prop]);\n                Object.defineProperty(dest, prop, descriptor);\n            });\n\n        return dest;\n    }\n\n    return src;\n}\n\nfunction streamToString(stream, callback) {\n    let str = '';\n    stream.on('data', function(data) {\n        str += data;\n    });\n\n    stream.on('error', function(err) {\n        callback(err);\n    });\n\n    stream.on('end', function() {\n        callback(null, str);\n    });\n}\n\nfunction readStream(func) {\n    // Calling read will do one of the following\n    // 1) Return the actual value or null if there no data\n    // 2) Invoke our callback with a value\n    // 3) Return a stream\n    const stream = new DeferredReadable(function() {\n        // this function will be called when it is time to start reading data\n        let finished = false;\n\n        function callback(err, value) {\n            if (finished) {\n                logger.warn(new Error('read callback invoked after finish'));\n                return;\n            }\n\n            if (err) {\n                stream.emit('error', err);\n                return;\n            }\n\n            if (value == null) {\n                stream.push(null);\n                finished = true;\n            } else {\n                if (typeof value === 'string') {\n                    stream.push(value);\n                    stream.push(null);\n                    finished = true;\n                } else if (typeof value.pipe === 'function') {\n                    // Looks like a stream...\n                    value.pipe(this);\n                    finished = true;\n                } else if (typeof value.then === 'function') {\n                    // Looks like a promise...\n                    value\n                        .then((value) => {\n                            callback(null, value);\n                        })\n                        .catch(callback);\n                } else {\n                    // Hopefully a Buffer\n                    stream.push(value);\n                    stream.push(null);\n                    finished = true;\n                }\n            }\n        };\n\n        const result = func(callback);\n\n        if (!finished) {\n            // callback was not invoked\n            if (result === null) {\n                callback(null, null);\n            } else if (result === undefined) {\n                // waiting on callback\n            } else if (result && typeof result.pipe === 'function') {\n                finished = true;\n                return result;\n            } else if (result && typeof result.then === 'function') {\n                result.then((promiseResult) => {\n                    if (promiseResult && typeof promiseResult.pipe === 'function') {\n                        finished = true;\n                        stream.emit('ready', promiseResult);\n                    } else {\n                        callback(null, promiseResult);\n                    }\n                }).catch((err) => {\n                    callback(err);\n                });\n            } else {\n                callback(null, result);\n                // A stream was returned, so we will return it\n            }\n        }\n    });\n\n    return stream;\n}\n\nexports.merge = merge;\nexports.streamToString = streamToString;\nexports.createCachingStream = cachingStream.create;\nexports.createFingerprintStream = fingerprintStream.create;\nexports.readStream = readStream;\nexports.DeferredReadable = require('./DeferredReadable');\n"
  },
  {
    "path": "src/util/prebuild.js",
    "content": "const nodePath = require('path');\n\nexports.buildPrebuildFileName = function (file) {\n    return `${file}.prebuild.json`;\n};\n\nexports.buildPrebuildName = function (pagePath) {\n    const name = pagePath && nodePath.basename(pagePath);\n\n    if (name) {\n        const extLen = nodePath.extname(name).length;\n        return (extLen && name.slice(0, 0 - extLen)) || name;\n    }\n\n    return 'page';\n};\n"
  },
  {
    "path": "src/util/stringify-attrs.js",
    "content": "module.exports = function stringifyAttributes (obj) {\n    let str = '';\n    for (const key in obj) {\n        const val = obj[key];\n        if (val === false || val == null) {\n            continue;\n        }\n\n        str += ' ' + key;\n\n        if (val !== true) {\n            str += '=' + JSON.stringify(val);\n        }\n    }\n\n    return str;\n};\n"
  },
  {
    "path": "src/util/url-reader.js",
    "content": "const http = require('http');\nconst https = require('https');\nconst DeferredReadable = require('./DeferredReadable');\n\nfunction createUrlReadStream(url) {\n    const stream = new DeferredReadable(function() {\n        const parsedUrl = new URL(url, 'file:');\n        const isSecure = parsedUrl.protocol === 'https:';\n        const get = isSecure ? https.get : http.get;\n\n        const options = {\n            hostname: parsedUrl.hostname,\n            port: parsedUrl.port || (isSecure ? 443 : 80),\n            path: parsedUrl.pathname + (parsedUrl.search ? parsedUrl.search : '')\n        };\n\n        const req = get(options, function(res) {\n            if (res.statusCode < 200 || res.statusCode >= 300) {\n                stream.emit('error', 'Request to ' + url + ' failed with a HTTP status code ' + res.statusCode);\n                return;\n            }\n\n            res\n                .on('end', function() {\n                    stream.push(null);\n                })\n                .on('error', function(err) {\n                    stream.emit('error', err);\n                })\n                .on('data', function(data) {\n                    stream.push(data);\n                });\n        });\n\n        req.on('error', function(err) {\n            stream.emit('error', 'Request to ' + url + ' failed. Error: ' + (err.stack || err));\n        });\n    }, {\n        encoding: 'utf8'\n    });\n\n    return stream;\n}\n\nexports.createUrlReadStream = createUrlReadStream;\n"
  },
  {
    "path": "src/writers/Writer.js",
    "content": "const nodePath = require('path');\nconst fileSep = nodePath.sep;\nconst logger = require('raptor-logging').logger(module);\nconst EventEmitter = require('events').EventEmitter;\nconst extend = require('raptor-util').extend;\nconst createError = require('raptor-util/createError');\nconst reader = require('../reader');\nconst ok = require('assert').ok;\nconst equal = require('assert').equal;\n\nasync function initWriter (writer, lassoContext) {\n    if (!writer._initialized && writer.impl.init) {\n        await writer.impl.init(lassoContext);\n        writer._initialized = true;\n    }\n}\n\nfunction Writer(impl) {\n    Writer.$super.call(this);\n    this.impl = impl || {};\n\n    // Lasso writer `init` function should only be called once. We call it the\n    // first time that either writing a resource or bundle is attempted.\n    this._initialized = false;\n}\n\nWriter.prototype = {\n    __LassoWriter: true,\n\n    setLasso: function(lasso) {\n        this.lasso = lasso;\n    },\n\n    getLasso: function() {\n        return this.lasso;\n    },\n\n    getInPlaceUrlForFile: function(path, lassoContext) {\n        ok(lassoContext, 'lassoContext is required');\n\n        if (typeof path !== 'string') {\n            throw new Error('Path for in-place file should be a string. Actual: ' + path);\n        }\n\n        const config = lassoContext.config;\n\n        if (typeof config.getInPlaceUrlPrefix() === 'string') {\n            const projectRoot = config.getProjectRoot();\n            if (projectRoot && path.startsWith(projectRoot + fileSep)) {\n                const suffix = path.substring(projectRoot.length);\n                return config.getInPlaceUrlPrefix() + suffix;\n            }\n        }\n\n        return null;\n    },\n\n    getInPlaceUrlForBundle: function(bundle, lassoContext) {\n        ok(lassoContext, 'lassoContext is required');\n\n        const dependency = bundle.dependency;\n        if (!dependency) {\n            throw new Error('\"dependency\" expected for in-place bundle');\n        }\n\n        if (!dependency.getSourceFile) {\n            throw new Error('\"getSourceFile\" expected for in-place dependency');\n        }\n\n        if (!bundle.inPlaceDeployment) {\n            throw new Error('inPlaceDeployment should be true');\n        }\n\n        const sourceFile = dependency.getSourceFile();\n        return this.getInPlaceUrlForFile(sourceFile, lassoContext);\n    },\n\n    async writeBundle (bundle, onBundleWrittenCallback, lassoContext) {\n        if (!bundle.hasContent()) return;\n\n        ok(lassoContext, 'lassoContext is required');\n\n        const done = (err) => {\n            if (err) {\n                throw createError('Error while writing bundle \"' + bundle + '\" Error: ' + err, err);\n            }\n\n            bundle.setWritten(true);\n\n            if (onBundleWrittenCallback) {\n                onBundleWrittenCallback(bundle);\n            }\n\n            const data = { bundle };\n\n            this.emit('bundleWritten', data);\n            lassoContext.emit('bundleWritten', data);\n\n            logger.info('Bundle ' + bundle + ' written.');\n\n            return bundle;\n        };\n\n        if (bundle.isWritten() || bundle.url) {\n            if (logger.isInfoEnabled()) {\n                logger.info('Bundle (' + bundle.getKey() + ') already written. Skipping writing...');\n            }\n\n            return done();\n        } else if ((bundle.inPlaceDeployment === true) && !bundle.isInline()) {\n            const inPlaceUrl = this.getInPlaceUrlForBundle(bundle, lassoContext);\n            if (inPlaceUrl) {\n                if (logger.isInfoEnabled()) {\n                    logger.info('In-place deployment enabled for (' + bundle.getKey() + '). Skipping writing...');\n                }\n                bundle.setUrl(inPlaceUrl);\n                return done();\n            }\n        }\n\n        lassoContext = Object.create(lassoContext);\n        lassoContext.bundle = bundle;\n        lassoContext.dependencies = bundle.dependencies;\n\n        const bundleReader = reader.createBundleReader(bundle, lassoContext);\n\n        logger.info('Writing bundle ' + bundle + '...');\n\n        const checkBundleUpToDate = async () => {\n            if (bundle.isInline()) return;\n            // We make the assumption that the bundle was populated with its URL\n            // and marked as written if it was indeed up-to-date\n            return this.checkBundleUpToDate(bundle, lassoContext);\n        };\n\n        const writeBundle = async () => {\n            // If the bundle is written then there is nothing to do\n            if (bundle.isWritten()) return;\n\n            let completed = false;\n\n            function handleError(e) {\n                if (!completed) {\n                    completed = true;\n                    throw e;\n                }\n            }\n\n            if (bundle.isInline()) {\n                try {\n                    const code = await bundleReader.readBundleFully();\n                    logger.info('Code for inline bundle ' + bundle.getLabel() + ' generated.');\n                    bundle.setCode(code);\n                } catch (err) {\n                    return handleError(err);\n                }\n            } else {\n                try {\n                    await this.impl.writeBundle(bundleReader, lassoContext);\n                    logger.info('Bundle written:', bundle.getLabel());\n                } catch (err) {\n                    return handleError(err);\n                }\n            }\n        };\n\n        await checkBundleUpToDate();\n        await writeBundle();\n\n        return done();\n    },\n\n    async writeResource (path, lassoContext) {\n        ok(lassoContext, 'lassoContext is required');\n\n        const done = (writeResult) => {\n            ok(writeResult, 'writeResult expected');\n            ok(writeResult.url, 'writeResult.url expected');\n\n            const result = extend(writeResult || {}, {\n                sourceFile: path\n            });\n\n            this.emit('resourceWritten', result);\n            lassoContext.emit('resourceWritten', result);\n\n            return result;\n        };\n\n        const config = this.config;\n\n        if (config.isInPlaceDeploymentEnabled()) {\n            const url = this.getInPlaceUrlForFile(path, lassoContext);\n            if (url) {\n                return done({ url });\n            }\n        }\n\n        lassoContext = Object.create(lassoContext);\n        lassoContext.path = path;\n\n        const resourceReader = reader.createResourceReader(path, lassoContext);\n\n        try {\n            await initWriter(this, lassoContext);\n            const writeResult = await this.impl.writeResource(resourceReader, lassoContext);\n            return done(writeResult);\n        } catch (err) {\n            throw createError('Error while writing resource \"' + path + '\": ' + (err.stack || err), err);\n        }\n\n        // this.checkResourceUpToDate(path, lassoContext, function(err, resourceInfo) {\n        //     if (err) {\n        //         return callback(err);\n        //     }\n        //\n        //     if (resourceInfo) {\n        //         return callback(null, resourceInfo);\n        //     }\n        //\n        //\n        // });\n    },\n\n    async writeResourceBuffer (buff, path, lassoContext) {\n        ok(lassoContext, 'lassoContext is required');\n\n        const done = (writeResult) => {\n            ok(writeResult, 'writeResult expected');\n            ok(writeResult.url, 'writeResult.url expected');\n\n            writeResult = writeResult || {};\n\n            this.emit('resourceWritten', writeResult);\n            lassoContext.emit('resourceWritten', writeResult);\n\n            return writeResult;\n        };\n\n        lassoContext = Object.create(lassoContext);\n        lassoContext.path = path;\n\n        try {\n            await initWriter(this, lassoContext);\n            const writeResult = await this.impl.writeResourceBuffer(buff, lassoContext);\n            return done(writeResult);\n        } catch (err) {\n            throw createError('Error while writing resource buffer: ', err);\n        }\n    },\n\n    async checkBundleUpToDate (bundle, lassoContext) {\n        ok(lassoContext, 'lassoContext is required');\n\n        if (this.impl.checkBundleUpToDate) {\n            const resourceInfo = await this.impl.checkBundleUpToDate(bundle, lassoContext);\n            return resourceInfo === false ? null : resourceInfo;\n        }\n    },\n\n    checkResourceUpToDate: function(path, lassoContext, callback) {\n        ok(lassoContext, 'lassoContext is required');\n        equal(typeof callback, 'function', 'callback function is required');\n\n        if (this.impl.checkResourceUpToDate) {\n            this.impl.checkResourceUpToDate(path, lassoContext, function(err, resourceInfo) {\n                if (err) {\n                    return callback(err);\n                }\n\n                if (resourceInfo === false) {\n                    resourceInfo = null;\n                }\n\n                return callback(null, resourceInfo);\n            });\n        } else {\n            return callback();\n        }\n    },\n\n    async writeBundles (iteratorFunc, onBundleWrittenCallback, lassoContext) {\n        ok(lassoContext, 'lassoContext is required');\n\n        await initWriter(this, lassoContext);\n        let promise = Promise.resolve();\n\n        iteratorFunc((bundle) => {\n            if (bundle.hasContent()) {\n                promise = promise.then(() => {\n                    return this.writeBundle(bundle, onBundleWrittenCallback, lassoContext);\n                });\n            }\n        });\n\n        return promise;\n    },\n\n    buildResourceCacheKey(cacheKey, lassoContext) {\n        if (this.impl.buildResourceCacheKey) {\n            return this.impl.buildResourceCacheKey(cacheKey, lassoContext);\n        } else {\n            return cacheKey;\n        }\n    }\n};\n\nrequire('raptor-util').inherit(Writer, EventEmitter);\n\nmodule.exports = Writer;\n"
  },
  {
    "path": "src/writers/file-writer.js",
    "content": "const MAX_FILE_LENGTH = 255;\n\nconst util = require('../util');\nconst nodePath = require('path');\nconst fs = require('fs');\nconst ok = require('assert').ok;\nconst logger = require('raptor-logging').logger(module);\nconst mkdirp = require('mkdirp');\nconst crypto = require('crypto');\nconst raptorAsync = require('raptor-async');\nconst Duplex = require('stream').Duplex;\nconst hashUtil = require('../util/hash');\n\nfunction filePathToUrlWindows(path) {\n    return path.replace(/[\\\\]/g, '/');\n}\n\nfunction filePathToUrlUnix(path) {\n    return path;\n}\n\nfunction enforceFileLengthLimits(path) {\n    return path.split(nodePath.sep).map(part => {\n        if (part.length < MAX_FILE_LENGTH) return part;\n        const overflow = part.slice(MAX_FILE_LENGTH - hashUtil.HASH_OVERFLOW_LENGTH);\n        const hash = hashUtil.generate(overflow);\n        return part.slice(0, MAX_FILE_LENGTH - hashUtil.HASH_OVERFLOW_LENGTH) + hash.slice(0, hashUtil.HASH_OVERFLOW_LENGTH);\n    }).join(nodePath.sep);\n}\n\nconst filePathToUrl = nodePath.sep === '/' ? filePathToUrlUnix : filePathToUrlWindows;\n\n/**\n * Utility function to generate a random string of characters\n * suitable for use in a filename. This function is needed\n * to generate a temporary file name\n *\n * @param  {int} len The length of the character sequence\n * @return {String} The random characters with the specified length\n */\nfunction randomStr(len) {\n    return crypto.randomBytes(Math.ceil(len / 2))\n        .toString('hex') // convert to hexadecimal format\n        .slice(0, len); // return required number of characters\n}\n\n/**\n * This \"getUrl(lassoContext)\" function is added to a bundle instance\n * to provide a mechanism to generate a bundle URL based on a\n * base path that might change. Unless a URL prefix is specififed\n * the URL is generated relative to a base path or the CWD.\n *\n * @param {Object} lassoContext An object with lassoContextual information needed to generate a URL\n */\nfunction getBundleUrl(lassoContext) {\n    let url = this.url;\n\n    if (url) {\n        return url;\n    }\n\n    const outputFile = this.outputFile;\n    let urlPrefix = this.urlPrefix;\n    const outputDir = this.outputDir;\n\n    ok(lassoContext.config, 'lassoContext.config expected');\n    ok(outputFile, 'outputFile expected');\n\n    if (typeof urlPrefix === 'string') {\n        const relPath = filePathToUrl(outputFile.substring(outputDir.length));\n        if (urlPrefix.endsWith('/')) {\n            urlPrefix = urlPrefix.slice(0, -1);\n        }\n        url = urlPrefix + relPath;\n        return url;\n    } else {\n        const basePath = lassoContext.basePath ? nodePath.resolve(process.cwd(), lassoContext.basePath) : process.cwd();\n        return filePathToUrl(nodePath.relative(basePath, outputFile));\n    }\n}\n\n/**\n * Internal function help write out a file and to possibly generate a fingerprint\n * in the process if fingerprints are enabled.\n *\n * On success, the callback will be invoked with an object that contains the following\n * properties:\n * - fingerprint: The string fingerprint if calculateFingerprint is set to true\n * - outputFile: The output file. If calculateFingerprint is set to true then the fingerprint\n *               will be injected into the filename\n *\n *\n * @param  {ReadableStream} inStream          The input stream to read from\n * @param  {string}         outputFile        The output file path\n * @param  {boolean}        calculateFingerprint If true then a fingerprint will be calculated and passed to the callback\n * @return void\n */\nasync function writeFile (inStream, outputFile, calculateFingerprint, fingerprintLength) {\n    const outputDir = nodePath.dirname(outputFile);\n    let done = false;\n\n    await mkdirp(outputDir);\n\n    let outStream;\n    const tempFile = outputFile + '.' + process.pid + '.' + randomStr(4);\n\n    return new Promise((resolve, reject) => {\n        function handleError(err) {\n            if (done) {\n                return;\n            }\n\n            done = true;\n            reject(err);\n        }\n\n        function handleSuccess(result) {\n            if (done) {\n                return;\n            }\n\n            done = true;\n            resolve(result);\n        }\n\n        if (calculateFingerprint) {\n            logger.debug(`Writing bundle to temp file ${tempFile}... (calculating fingerprint)`);\n\n            // Pipe the stream to a temporary file and when the fingerprint is known,\n            // rename the file to include the known fingerprint\n\n            outStream = fs.createWriteStream(tempFile);\n            const fingerprintStream = util.createFingerprintStream();\n            let fingerprint;\n\n            outStream\n                .on('close', function() {\n                    if (done) {\n                        return;\n                    }\n\n                    if (fingerprintLength && fingerprint.length > fingerprintLength) {\n                        fingerprint = fingerprint.substring(0, fingerprintLength);\n                    }\n\n                    const ext = nodePath.extname(outputFile);\n                    outputFile = outputFile.slice(0, 0 - ext.length) + '-' + fingerprint + ext;\n\n                    fs.stat(outputFile, function (error, stats) {\n                        if (error) {\n                            fs.rename(tempFile, outputFile, function(err) {\n                                if (err && !fs.existsSync(outputFile)) {\n                                    return handleError(err);\n                                }\n\n                                handleSuccess({\n                                    fingerprint,\n                                    outputFile\n                                });\n                            });\n                        } else {\n                            // If it already exists then just use that file, but delete the temp file\n                            fs.unlink(tempFile, function() {\n                                handleSuccess({\n                                    fingerprint,\n                                    outputFile\n                                });\n                            });\n                        }\n                    });\n                });\n\n            fingerprintStream\n                .on('fingerprint', function(_fingerprint) {\n                    fingerprint = _fingerprint;\n                })\n                .on('error', handleError)\n                .pipe(outStream);\n\n            inStream\n                .on('error', handleError)\n                .pipe(fingerprintStream);\n        } else {\n            logger.debug(`Writing bundle to temp file ${tempFile}... (no fingerprint)`);\n\n            // No fingerprint is needed so simply pipe out the input stream\n            // to the output file\n            outStream = fs.createWriteStream(tempFile);\n\n            inStream\n                .on('error', handleError)\n                .pipe(outStream)\n                .on('close', function() {\n                    if (done) {\n                        return;\n                    }\n\n                    fs.rename(tempFile, outputFile, function(err) {\n                        if (err && !fs.existsSync(outputFile)) {\n                            return handleError(err);\n                        }\n\n                        handleSuccess({\n                            outputFile\n                        });\n                    });\n                });\n        }\n    });\n}\n\nmodule.exports = function fileWriter(fileWriterConfig, lassoConfig) {\n    // The directory to place the built bundle and resource files\n    const outputDir = nodePath.resolve(process.cwd(), fileWriterConfig.outputDir || 'static');\n\n    // Boolean value to indicate if including fingerprints in the output files is enabled\n    // or not.\n    const fingerprintsEnabled = fileWriterConfig.fingerprintsEnabled !== false;\n\n    // Optional URL prefix to use when generating URLs to the bundled files\n    let urlPrefix = fileWriterConfig.urlPrefix;\n\n    // Boolean value to indicate if the target slot should be added to the output filename\n    // e.g. \"head\" or \"body\"\n    const includeSlotNames = fileWriterConfig.includeSlotNames;\n\n    // If fingerprints are enabled then this flag will be used to determine how many characters\n    // the fingerprint should contain\n    const fingerprintLength = fileWriterConfig.fingerprintLength || 8;\n\n    // Boolean value to indicate if CSS URLs should be relative\n    const relativeUrlsEnabled = fileWriterConfig.relativeUrlsEnabled;\n\n    /**\n     * Calculate the output file for  a given bundle given\n     * the configuration for the file writer.\n     *\n     * @param  {lasso/src/Bundle} bundle The lasso Bundle\n     * @return {String} The output file path for the bundle\n     */\n    function getOutputFileForBundle(bundle) {\n        if (bundle.outputFile) {\n            return bundle.outputFile;\n        }\n        let relativePath;\n\n        if (bundle.dependency && bundle.dependency.getSourceFile) {\n            relativePath = bundle.dependency.getSourceFile();\n        } else if (bundle.relativeOutputPath) {\n            // We are being told to use a relative path that\n            // we should join with the output directory\n            relativePath = bundle.relativeOutputPath;\n        }\n\n        const targetExt = bundle.getContentType();\n\n        return getOutputFile(\n            relativePath,\n            bundle.getName(),\n            targetExt,\n            bundle.getSlot());\n    }\n\n    function getOutputFileFromFileName (path, relativePath) {\n        const filename = nodePath.basename(path);\n\n        return getOutputFile(\n            relativePath,\n            filename);\n    }\n\n    function getOutputFileForResource(path, fingerprintsEnabled, lassoContext) {\n        let relativePath;\n\n        if (lassoConfig.isBundlingEnabled() === false || fingerprintsEnabled === false) {\n            // When bundling is disabled we maintain the directory structure\n            // so we want to provide the sourceFile so that we can\n            // know which deeply nested resource path to use\n\n            relativePath = lassoContext.getClientPath(path);\n\n            const pageName = lassoContext.pageName;\n            const flags = lassoContext.flags;\n            if (pageName) {\n                let prefix = pageName.replace(/[\\\\\\/]/g, '-');\n\n                if (flags && !flags.isEmpty()) {\n                    prefix += '-' + flags.getKey();\n                }\n\n                relativePath = prefix + '/' + relativePath;\n            }\n        }\n\n        return getOutputFileFromFileName(path, relativePath);\n    }\n\n    function buildResourceCacheKey(cacheKey, lassoContext) {\n        const lassoConfig = lassoContext.config;\n        const pageName = lassoContext.pageName;\n\n        if (pageName && (lassoConfig.isBundlingEnabled() === false || fingerprintsEnabled === false)) {\n            return pageName + '-' + cacheKey;\n        }\n\n        return cacheKey;\n    }\n\n    function getOutputFile(relativePath, filename, targetExt, slotName) {\n        let outputPath;\n        if (relativePath) {\n            outputPath = nodePath.join(outputDir, relativePath);\n        }\n\n        if (!outputPath) {\n            ok(filename, '\"filename\" or \"sourceFile\" expected');\n            outputPath = nodePath.join(outputDir, filename.replace(/^\\//, '').replace(/[^A-Za-z0-9_\\-\\.]/g, '-'));\n        }\n\n        const dirname = nodePath.dirname(outputPath);\n        let basename = nodePath.basename(outputPath);\n\n        const lastDot = basename.lastIndexOf('.');\n        let ext;\n        let nameNoExt;\n\n        if (lastDot !== -1) {\n            ext = basename.substring(lastDot + 1);\n            nameNoExt = basename.substring(0, lastDot);\n        } else {\n            ext = '';\n            nameNoExt = basename;\n        }\n\n        if (includeSlotNames && slotName) {\n            nameNoExt += '-' + slotName;\n        }\n\n        basename = nameNoExt;\n        if (ext) {\n            basename += '.' + ext;\n        }\n\n        if (targetExt && ext != targetExt) { // eslint-disable-line eqeqeq\n            basename += '.' + targetExt;\n        }\n\n        return enforceFileLengthLimits(nodePath.join(dirname, basename));\n    }\n\n    function getResourceUrlForHashed (path, lassoContext) {\n        let basePath;\n\n        if (lassoContext && lassoContext.bundle && lassoContext.bundle.isStyleSheet() && relativeUrlsEnabled !== false) {\n            // We should calculate a relative path from the CSS bundle to the resource bundle\n            basePath = nodePath.dirname(getOutputFileForBundle(lassoContext.bundle));\n            return filePathToUrl(nodePath.relative(basePath, path));\n        }\n\n        if (typeof urlPrefix === 'string') {\n            const relPath = filePathToUrl(path.substring(outputDir.length));\n            if (urlPrefix.endsWith('/')) {\n                urlPrefix = urlPrefix.slice(0, -1);\n            }\n            return urlPrefix + relPath;\n        } else {\n            basePath = lassoContext.basePath ? nodePath.resolve(process.cwd(), lassoContext.basePath) : process.cwd();\n            return filePathToUrl(nodePath.relative(basePath, path));\n        }\n    }\n\n    function getResourceUrl (path, lassoContext) {\n        ok(path, 'path is required');\n        ok(path.startsWith(outputDir), 'resource expected to be in the output directory. path=' + path + ', outputDir=' + outputDir);\n        return getResourceUrlForHashed(path, lassoContext);\n    }\n\n    return {\n        buildResourceCacheKey,\n\n        /**\n         * This method is used to determine if writing a bundle\n         * should be bypassed.\n         *\n         * @param  {lasso/src/Bundle} The bundle instance\n         * @param  {Object} Contextual information\n         * @return {[type]}            [description]\n         */\n        async checkBundleUpToDate (bundle, lassoContext) {\n            return false;\n            // NOTE: We used to do a last modified check based on file modified datas,\n            //       but there were edge cases that caused problem. For example, even though\n            //       none of the files in the bundle were modified, a separate file that impacts\n            //       how the bundle code may be generated may have been modified. The\n            //       saves from a timestamp check are minimal.\n        },\n\n        checkResourceUpToDate: function(path, lassoContext, callback) {\n            if (fingerprintsEnabled) {\n                return callback(null, false);\n            }\n\n            const outputFile = getOutputFileForResource(path, fingerprintsEnabled, lassoContext);\n\n            const work = {\n                async sourceLastModified () {\n                    return lassoContext.getFileLastModified(path);\n                },\n                async outputLastModified (callback) {\n                    return lassoContext.getFileLastModified(outputFile);\n                }\n            };\n\n            raptorAsync.parallel(work, function(err, results) {\n                if (err) {\n                    return callback(err);\n                }\n\n                if (results.outputLastModified >= results.sourceLastModified) {\n                    // The resource has not been modified so let the lasso\n                    // know what URL to use for the resource\n                    const url = getResourceUrl(outputFile, lassoContext);\n\n                    callback(null, {\n                        url,\n                        outputFile\n                    });\n                } else {\n                    // Resource is not up-to-date and needs to be written\n                    callback(null, false);\n                }\n            });\n        },\n\n        async writeBundle (reader, lassoContext) {\n            return new Promise((resolve, reject) => {\n                const input = reader.readBundle();\n                const bundle = lassoContext.bundle;\n\n                ok(input, '\"input\" is required');\n                ok(bundle, '\"bundle\" is required');\n\n                input.on('error', reject);\n\n                let calculateFingerprint = bundle.config.fingerprintsEnabled;\n                if (calculateFingerprint === undefined) {\n                    calculateFingerprint = fingerprintsEnabled;\n                }\n\n                calculateFingerprint = calculateFingerprint === true && !bundle.getFingerprint();\n\n                const outputFile = getOutputFileForBundle(bundle);\n\n                logger.debug('Writing bundle \"' + bundle.getLabel() + '\" to file \"' + outputFile + '\"...');\n\n                writeFile(input, outputFile, calculateFingerprint, fingerprintLength)\n                    .then((result) => {\n                        logger.debug('Writing bundle \"' + bundle.getLabel() + '\" to file \"' + outputFile + '\" COMPLETED');\n                        bundle.setFingerprint(result.fingerprint);\n                        bundle.setWritten(true);\n                        bundle.getUrl = getBundleUrl;\n                        bundle.urlPrefix = urlPrefix;\n                        bundle.outputDir = outputDir;\n                        bundle.outputFile = result.outputFile;\n                        resolve();\n                    }).catch((err) => {\n                        logger.debug('Writing bundle \"' + bundle.getLabel() + '\" to file \"' + outputFile + '\" FAILED! - Error:', err);\n                        reject(err);\n                    });\n            });\n        },\n\n        async writeResource (reader, lassoContext) {\n            let done = false;\n\n            const input = reader.readResource();\n            const path = lassoContext.path;\n\n            ok(input, '\"input\" is required');\n            ok(path, '\"path\" is required');\n\n            return new Promise((resolve, reject) => {\n                function handleError (err) {\n                    if (done) {\n                        return;\n                    }\n\n                    done = true;\n                    reject(err);\n                }\n\n                input.on('error', handleError);\n\n                const calculateFingerprint = fingerprintsEnabled === true;\n                const outputFileForResource = getOutputFileForResource(path, calculateFingerprint, lassoContext);\n\n                writeFile(\n                    input,\n                    outputFileForResource,\n                    calculateFingerprint,\n                    fingerprintLength)\n                    .then((result) => {\n                        const outputFile = result.outputFile;\n                        const url = getResourceUrl(outputFile, lassoContext);\n                        resolve({ url, outputFile });\n                    }).catch(handleError);\n            });\n        },\n\n        async writeResourceBuffer (buff, lassoContext) {\n            let done = false;\n\n            const input = new Duplex();\n            input.push(buff);\n            input.push(null);\n\n            const path = lassoContext.path;\n\n            ok(input, '\"input\" is required');\n            ok(path, '\"path\" is required');\n\n            return new Promise((resolve, reject) => {\n                function handleError (err) {\n                    if (done) {\n                        return;\n                    }\n\n                    done = true;\n                    reject(err);\n                }\n\n                input.on('error', handleError);\n\n                const calculateFingerprint = false;\n                const outputFileForResource = getOutputFileFromFileName(path, null);\n\n                writeFile(\n                    input,\n                    outputFileForResource,\n                    calculateFingerprint,\n                    fingerprintLength)\n                    .then((result) => {\n                        const outputFile = result.outputFile;\n                        const url = getResourceUrlForHashed(outputFile, lassoContext);\n                        resolve({ url, outputFile });\n                    }).catch(handleError);\n            });\n        }\n    };\n};\n"
  },
  {
    "path": "src/writers/index.js",
    "content": "const Writer = require('./Writer');\n\nfunction createWriter(writerImpl) {\n    return new Writer(writerImpl);\n}\n\nexports.Writer = Writer;\nexports.fileWriter = require('./file-writer');\nexports.createWriter = createWriter;\n"
  },
  {
    "path": "test/.eslintrc",
    "content": "{\n  \"globals\": {\n    \"it\": 1,\n    \"describe\": 1,\n    \"context\": 1,\n    \"beforeEach\": 1,\n    \"afterEach\": 1\n  }\n}\n"
  },
  {
    "path": "test/.gitignore",
    "content": "*.marko.js\n*.dust.js\n~*/\nactual.*\nactual-*"
  },
  {
    "path": "test/api-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nvar nodePath = require('path');\nrequire('chai').config.includeStack = true;\nvar rmdirRecursive = require('./util').rmdirRecursive;\nvar lasso = require('lasso');\nvar buildDir = nodePath.join(__dirname, 'build');\n\nlet _log = console.log;\n\ndescribe('lasso/api' , function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/api'),\n        async function (dir, helpers) {\n            var name = nodePath.basename(dir);\n            var outputDir = nodePath.join(buildDir, name);\n            rmdirRecursive(outputDir);\n            helpers.getName = function() {\n                return name;\n            };\n            helpers.getOutputDir = function() {\n                return outputDir;\n            };\n\n            var main = require(nodePath.join(dir, 'test.js'));\n            return main.check(lasso, helpers);\n        });\n});\n"
  },
  {
    "path": "test/autotest.js",
    "content": "'use strict';\n\nvar fs = require('fs');\nvar enabledTest = process.env.TEST;\nvar path = require('path');\nvar assert = require('assert');\n\nvar enabledTestNames = enabledTest && enabledTest.split(/[\\s*,\\s*/]/);\nvar enabledTests = null;\n\nif (enabledTestNames && enabledTestNames.length > 1) {\n    enabledTests = {};\n    enabledTest = null;\n    enabledTestNames.forEach((testName) => {\n        enabledTests[testName] = true;\n    });\n}\n\nvar fs = require('fs');\nvar enabledTest = process.env.TEST;\nvar path = require('path');\nvar assert = require('assert');\n\nfunction compareHelper(dir, actual, suffix) {\n    var actualPath = path.join(dir, 'actual' + suffix);\n    var expectedPath = path.join(dir, 'expected' + suffix);\n\n    var isObject = typeof actual === 'string' ? false : true;\n    var actualString = isObject ? JSON.stringify(actual, null, 4) : actual;\n    fs.writeFileSync(actualPath, actualString, { encoding: 'utf8' });\n\n    var expectedString;\n\n    try {\n        expectedString = fs.readFileSync(expectedPath, { encoding: 'utf8' });\n    } catch(e) {\n        expectedString = isObject ? '\"TBD\"' : 'TBD';\n        fs.writeFileSync(expectedPath, expectedString, {encoding: 'utf8'});\n    }\n\n    if (isObject) {\n        actual = JSON.parse(actualString);\n    }\n\n    var expected = isObject ? JSON.parse(expectedString) : expectedString;\n    assert.deepEqual(actual, expected);\n}\n\nfunction autoTest (name, dir, run, options) {\n    options = options || {};\n\n    var helpers = {\n        compare(actual, suffix) {\n            compareHelper(dir, actual, suffix);\n        }\n    };\n\n    return run(dir, helpers);\n}\n\nexports.scanDir = function(autoTestDir, run, options) {\n    describe('autotest', function() {\n        fs.readdirSync(autoTestDir)\n            .forEach(function(name) {\n                if (name.charAt(0) === '.') {\n                    return;\n                }\n\n                if (enabledTests && !enabledTests[name]) {\n                    return;\n                }\n\n                var itFunc = it;\n\n                if (enabledTest && name === enabledTest) {\n                    itFunc = it.only;\n                }\n\n                if (name.endsWith('-skip')) {\n                    itFunc = it.skip;\n                }\n\n                var dir = path.join(autoTestDir, name);\n\n                itFunc(`[${name}] `, function () {\n                    return autoTest(name, dir, run, options);\n                });\n            });\n    });\n};\n"
  },
  {
    "path": "test/autotests/api/config-fingerprint/foo.js",
    "content": "console.log('Foo!');"
  },
  {
    "path": "test/autotests/api/config-fingerprint/test.js",
    "content": "const expect = require('chai').expect;\n\nexports.check = function (lasso, helpers) {\n    var config = {\n        bundles: [\n            {\n                name: 'foo',\n                dependencies: [\n                    \"require: \" + require.resolve('./foo.js')\n                ]\n            }\n        ]\n    };\n\n    var myLasso1 = lasso.create(config);\n    var myLasso2 = lasso.create(config);\n    expect(myLasso1.config.getConfigFingerprint()).to.equal(myLasso2.config.getConfigFingerprint());\n};\n"
  },
  {
    "path": "test/autotests/api/lasso-lassoPage-promise/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/api/lasso-lassoPage-promise/foo.js",
    "content": "foo"
  },
  {
    "path": "test/autotests/api/lasso-lassoPage-promise/test.js",
    "content": "const nodePath = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function (lasso, helpers) {\n    lasso.configure({\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        outputDir: helpers.getOutputDir()\n    });\n\n    const lassoPageResult = await lasso.lassoPage({\n        pageName: helpers.getName(),\n        dependencies: [\n            nodePath.join(__dirname, 'browser.json')\n        ]\n    });\n\n    expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1);\n};\n"
  },
  {
    "path": "test/autotests/api/lasso-lassoResource-buffer/test.js",
    "content": "'use strict';\n\nconst fs = require('fs');\nconst nodePath = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function(lasso, helpers) {\n    lasso.configure({\n        bundlingEnabled: true,\n        fingerprintsEnabled: true,\n        outputDir: helpers.getOutputDir()\n    });\n\n    const imgPath = nodePath.join(__dirname, 'ebay.png');\n\n    const buffer = await fs.promises.readFile(imgPath);\n    const result = await lasso.lassoResource(buffer, {\n        extension: 'png'\n    });\n\n    expect(result.url).to.equal('/static/cf6691ad.png');\n};\n"
  },
  {
    "path": "test/autotests/api/lasso-lassoResource-buffer-name/test.js",
    "content": "'use strict';\n\nconst fs = require('fs');\nconst nodePath = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function(lasso, helpers) {\n    lasso.configure({\n        bundlingEnabled: true,\n        fingerprintsEnabled: true,\n        outputDir: helpers.getOutputDir()\n    });\n\n    const imgPath = nodePath.join(__dirname, 'ebay.png');\n\n    const buffer = await fs.promises.readFile(imgPath);\n    const result = await lasso.lassoResource(buffer, {\n        name: 'test',\n        extension: 'png'\n    });\n\n    expect(result.url).to.equal('/static/test-cf6691ad.png');\n};\n"
  },
  {
    "path": "test/autotests/api/lasso-lassoResource-promise/foo.txt",
    "content": "foo"
  },
  {
    "path": "test/autotests/api/lasso-lassoResource-promise/test.js",
    "content": "const nodePath = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function (lasso, helpers) {\n    lasso.configure({\n        bundlingEnabled: true,\n        fingerprintsEnabled: true,\n        outputDir: helpers.getOutputDir()\n    });\n\n    const result = await lasso.lassoResource(nodePath.join(__dirname, 'foo.txt'));\n    expect(result.url).to.equal('/static/foo-0beec7b5.txt');\n};\n"
  },
  {
    "path": "test/autotests/api/myLasso-lassoPage-promise/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/api/myLasso-lassoPage-promise/foo.js",
    "content": "foo"
  },
  {
    "path": "test/autotests/api/myLasso-lassoPage-promise/test.js",
    "content": "var nodePath = require('path');\nvar expect = require('chai').expect;\n\nexports.check = async function (lasso, helpers) {\n    var myLasso = lasso.create({\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        outputDir: helpers.getOutputDir()\n    });\n\n    const lassoPageResult = await myLasso.lassoPage({\n        pageName: helpers.getName(),\n        dependencies: [\n            nodePath.join(__dirname, 'browser.json')\n        ]\n    });\n\n    expect(lassoPageResult.getOutputFilesWithInfo().length).to.equal(1);\n};\n"
  },
  {
    "path": "test/autotests/api/myLasso-lassoResource-promise/foo.txt",
    "content": "foo"
  },
  {
    "path": "test/autotests/api/myLasso-lassoResource-promise/test.js",
    "content": "const nodePath = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function (lasso, helpers) {\n    const myLasso = lasso.create({\n        bundlingEnabled: true,\n        fingerprintsEnabled: true,\n        outputDir: helpers.getOutputDir()\n    });\n\n    const result = await myLasso.lassoResource(nodePath.join(__dirname, 'foo.txt'));\n    expect(result.url).to.equal('/static/foo-0beec7b5.txt');\n};\n"
  },
  {
    "path": "test/autotests/api/pollute-default-config/test.js",
    "content": "const expect = require('chai').expect;\n\nexports.check = function (lasso, helpers) {\n    const myLasso1 = lasso.create({\n        require: {\n            test: 'abc'\n        }\n    });\n\n    const myLasso2 = lasso.create({\n\n    });\n\n    const defaultLasso = lasso.getDefaultLasso();\n    const requirePlugin1 = myLasso1.getConfig().getPlugins()[0];\n    const requirePlugin2 = myLasso2.getConfig().getPlugins()[0];\n    const requirePlugin3 = defaultLasso.getConfig().getPlugins()[0];\n\n    expect(requirePlugin1.config.test).to.equal('abc');\n    expect(requirePlugin2.config.test).to.not.exist;\n    expect(requirePlugin3.config.test).to.not.exist;\n};\n"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/a.js",
    "content": "a.js"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/b.js",
    "content": "b.js"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/foo-async.js",
    "content": "console.log('foo-async');\nrequire('./foo-something-else');"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/foo-something-else.js",
    "content": "console.log('foo-something-else');"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/foo.js",
    "content": "console.log('foo');\n\nrequire('lasso-loader').async([\n    './a.js',\n    './b.js'\n], function(err) {\n    require('./foo-async');\n});"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/async-dependencies/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-async-dependencies-async.js',\n                    'bundling-async-dependencies.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('bundling-async-dependencies.js')).to.contain(\"console.log('foo')\");\n                expect(writerTracker.getCodeForFilename('bundling-async-dependencies.js')).to.contain('.async(\"');\n\n\n                expect(writerTracker.getCodeForFilename('bundling-async-dependencies-async.js')).to.contain(\"a.js\");\n                expect(writerTracker.getCodeForFilename('bundling-async-dependencies-async.js')).to.contain(\"b.js\");\n                expect(writerTracker.getCodeForFilename('bundling-async-dependencies-async.js')).to.contain(\"console.log('foo-async')\");\n                expect(writerTracker.getCodeForFilename('bundling-async-dependencies-async.js')).to.contain(\"console.log('foo-something-else')\");\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/async-flags/DO_NOT_INCLUDE_ME.js",
    "content": "DO_NOT_INCLUDE_ME"
  },
  {
    "path": "test/autotests/bundling/async-flags/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ],\n    \"async\": {\n        \"foo\": [\n            {\n                \"if-flag\": \"INVALID\",\n                \"dependencies\": [\n                    \"./DO_NOT_INCLUDE_ME.js\"\n                ]\n            }\n        ]\n    }\n}"
  },
  {
    "path": "test/autotests/bundling/async-flags/foo.js",
    "content": "foo"
  },
  {
    "path": "test/autotests/bundling/async-flags/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/async-flags/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-async-flags.js'\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('bundling-async-flags.js')).to.equal('foo');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/async-package/bar.js",
    "content": "console.log('bar');"
  },
  {
    "path": "test/autotests/bundling/async-package/browser.json",
    "content": "{\n    \"async\": {\n        \"foo\": [\n            \"require: ./foo.js\"\n        ],\n\n        \"bar\": [\n            \"require: ./bar.js\"\n        ]\n    }\n}"
  },
  {
    "path": "test/autotests/bundling/async-package/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/bundling/async-package/main.js",
    "content": "var packageId = 'foo';\n\nconsole.log('main');\nrequire('lasso-loader').async(packageId, function(err) {\n    require('./foo');\n});\n\nvar callback = function(err) {\n    require('./bar');\n};\n\nrequire('lasso-loader').async('bar', callback);"
  },
  {
    "path": "test/autotests/bundling/async-package/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/async-package/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'foo',\n                dependencies: [\n                    'require: ./foo'\n                ]\n            },\n            {\n                name: 'bar',\n                dependencies: [\n                    'require: ./bar'\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    'require: ./main'\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bar.js',\n                    'bundling-async-package.js',\n                    'foo.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('bar.js')).to.contain(\"console.log('bar')\");\n                expect(writerTracker.getCodeForFilename('bundling-async-package.js')).to.contain(\".async('bar', callback)\");\n                expect(writerTracker.getCodeForFilename('bundling-async-package.js')).to.contain(\"console.log('main')\");\n                expect(writerTracker.getCodeForFilename('foo.js')).to.contain(\"console.log('foo')\");\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/bundle-getImageInfo-skip/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/bundle-getImageInfo-skip/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: []\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            {\n                type: 'require',\n                path: require.resolve('../../../../taglib/helper-getImageInfo')\n            }\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var fooCode = writerTracker.getCodeForFilename(writerTracker.getOutputFilenames()[0]);\n    expect(fooCode).to.contain('lassoImage.getImageInfo');\n};\n"
  },
  {
    "path": "test/autotests/bundling/bundles/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/bundles/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/bundles/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\",\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/bundles/c.js",
    "content": "c"
  },
  {
    "path": "test/autotests/bundling/bundles/d.js",
    "content": "d"
  },
  {
    "path": "test/autotests/bundling/bundles/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/bundles/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'bundle1',\n                dependencies: [\n                    path.join(__dirname, 'a.js'),\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            {\n                name: 'bundle2',\n                dependencies: [\n                    path.join(__dirname, 'c.js'),\n                    path.join(__dirname, 'd.js')\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'a.js'),\n                    path.join(__dirname, 'b.js'),\n                    path.join(__dirname, 'c.js'),\n                    path.join(__dirname, 'd.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundle1.js',\n                        'bundle2.js'\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('bundle1.js')).to.equal('a\\nb');\n                expect(writerTracker.getCodeForFilename('bundle2.js')).to.equal('c\\nd');\n\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-default/a.js",
    "content": "a\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-default/b.js",
    "content": "b\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-default/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"a.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-default/c.js",
    "content": "c\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-default/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-default/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'everything',\n                dependencies: [\n                    'a.js',\n                    'b.js',\n                    'c.js'\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './a.js'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var fooCode = writerTracker.getCodeForFilename('everything.js');\n    expect(fooCode).to.equal('a\\n\\nb\\n\\nc\\n');\n};"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-lean/a.js",
    "content": "a\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-lean/b.js",
    "content": "b\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-lean/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"a.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-lean/c.js",
    "content": "c\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-lean/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/bundling-strategy-lean/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingStrategy: 'lean',\n        bundles: [\n            {\n                name: 'everything',\n                dependencies: [\n                    'a.js',\n                    'b.js',\n                    'c.js'\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './a.js',\n            './a.js'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var everythingCode = writerTracker.getCodeForFilename('everything.js');\n    expect(everythingCode).to.equal('a\\n');\n};"
  },
  {
    "path": "test/autotests/bundling/bundling-virtual-module/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/bundling-virtual-module/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            {\n                type: 'require',\n                virtualModule: {\n                    path: __dirname + '/x/y/z',\n                    clientPath: '/x/y/z',\n                    read (lassoContext) {\n                        return 'abc';\n                    },\n                    getDefaultBundleName: function(pageBundleName, lassoContext) {\n                        return 'xyz';\n                    }\n                }\n            }\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var everythingCode = writerTracker.getCodeForFilename('xyz.js');\n    expect(everythingCode).to.contain('abc');\n};\n"
  },
  {
    "path": "test/autotests/bundling/csp-nonce-inline-script/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/csp-nonce-inline-script/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/csp-nonce-inline-script/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\",\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/csp-nonce-inline-script/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/csp-nonce-inline-script/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: true\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-csp-nonce-inline-script.js'\n                    ]);\n\n                    var body = lassoPageResult.getSlotHtml('body', {\n                        inlineScriptAttrs: {\n                            nonce: 'abc'\n                        }\n                    });\n\n                    expect(body).to.equal(\n                        '<script src=\"/static/bundling-csp-nonce-inline-script.js\"></script>\\n' +\n                        '<script nonce=\"abc\">a</script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-base64/expected.css",
    "content": ".foo {\n    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE8AAAAeCAYAAABt5kPUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGNzdGMTE3NDA3MjA2ODExODhDNkIzODA1MTg5Nzc0NiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRTg2MEMyMzZFNzIxMUUyQjZGMEE2ODM0MDRENkNFNiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRTg2MEMyMjZFNzIxMUUyQjZGMEE2ODM0MDRENkNFNiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODAxMTc0MDcyMDY4MTE5OTRDOTI2RkUxMEEyMEJFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkY3N0YxMTc0MDcyMDY4MTE4OEM2QjM4MDUxODk3NzQ2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Yff30gAAE/BJREFUeNrsWgdwHdW5/s+Wu7u3q3fJspqLLMuVYINt3AgQwjPFYCCN+ogpLyRgCKQHAo/H8OAFhgAOxQQCDt3E2Bg74IK7ZMuyZCFbVpescnvZet5/9kpuhJbMvJkwb2d2tPferd/5/6+cFTHDESCiAPrBZjD7+oBqOpjHjoE5MACEFwAoBbZwGekgDh2D95QJ8HthGsjUAAKpheCGYYJ3b0fibwmd5nIERPx6A67L4KRF1SlU5jhgdrkTMj0C9IcN0A0K00oUEHkCPicP51S5QBIIuPg48Byet3OVfQ/UiADoIaBmDAjnAOCdQNVjAIIXvx8CIuUCWDoQORe2awPQFjsEeDjgkXifBM4uuwPSXaVg4j5w/L45SOpBSGgBe3t04QgPCT0AezqfxedS7d84wYLAUR+0bckHt1eG1tZWEOArLCrl4JtGK+wX8+CteC64iXESeJQLxoxCVaNZI6hmn3KwScGp8AicC9wyB5YF//IL91V2ZjVocRzc7DkM1WQINBwhrLKRFcf3xIdTV1zcLgEunOKzgUOg4euwcF/1AB148BlxuNnVCg5sNevL4IBVdn6NB4rSBLtNvy7LVwaPYP0lsH2neeKwNHMYt/kvQJvCTOS4ylwJ1K8RcJ8LHmFExiMwAg9EEGxRIewzx9sUrJkAV+aFoMRpgGaRv38SBKsgU4SFEzw2xzEBEFEMHCMrjy1NyAlK+OKRI6lbJkjVTDQ4MbWyz0ghx0/2f7R8SjCIQ0SgRFQyLY1Go8X4Nx2o5eKiUdOKxUK839/NeT1dpiiZaQ4KF/sG4L9juSAR+imCJNjWy85IA7+Tg56g4R2ImGM1w8hCBXQqDi6uGdCriOSw7OASo6r+aaKlKWA4CewNI1xI9WGUVuLHvwrwLg3MRBDB7CO8sxN4WTeZvAKhKQVlQ41qyQmfw+T0lOGzFRovRXBQCIoi27ZoAp/QoDwWkMCKCQdKOH48qyoETW9sWpDcum252d19NtqWDGR3QmlKGklqnyTn9x+QamueETPTn7+owpVcbwpwsFc9rV0tmD/JA1V5jsJnPgqsaOxJXhLTrDzKxILa/Y9FTCyXxB0NJczn51a6/ifTLQTo6Q+GFYY2xWsNbbneCuy8mmoDVWhJFJtsT/ZKRFSJI6NFSJ/1TH76zNf3q70PmVogEwE0TEuTA/G236Q7x240QT+NhpjoiadYFQEHKqAdre0N1f8nY2zTUuUxOdO3e8xpdx1q2XpOfkEur6pqXLAvLOENqmp69NkXntEbDy6hoz4Cb9BuVyHl96iOF1ZV2Uwkpse7u6dr9ftvybnthisvO6N6/89f6z4xdrjh9QrJbJ940YrVfc8OB/Q0+3uejN6xbV3w9FzENMe+sSP4q43N0RtvW5h5zaKJ7nW2qLCH4SW8r77pRusjq6kaGPOpFmYrq0xbtTSJJnon6V2vPTo23PCDAjmD1qv9UySsGt2MQ33ni9rYjHkbUxenI0VtIX24kUpcp5zagR7yo8MP3RWMty0SeRceH4N8z4wXnJXzoHn80ODWbVtkrL4wsQJBMEMhX+Dun72t7ambQ1xoPjUNhMKCFqGs7GUEb5tjSu2QfviIYg0PT7IGBy/RDjYvYFXI9nNkZ/UIv71vwXVNBe1v7RpuN030ebh4ndwAMUEIhfU0t1ccnlysvJbvEz6qLZL7mvpUX+ewPqOpV7302LBeBiKxhUUUifb0NYWXXzHD9yanDwKvduWpO5ZspdGOUpswcVCJq2Q3cZWu4pxj6jhvTcIc3OgDU51mRVuW0Wh7LdtPwP2GRG/yRYciayMiZ6GpXzL5qXNLM+atZ2B+Jo9xMgxEmya/smfZdjTUskl1yPZM+Pjs8jvPzvFXmI07huGee39qA8/fe8stEHniD/+V2PDBZZzXyyoQHNOmrnZf+/3zxNKS98E0Dztqa3rx+w4hP2+3cu6iFzi3O6w3NZ/LKtIMBDyewe6K3qlz31zXoi3Hs7rZ4GKacKkJUynOk3f++zkZi8+ucK3yO/n9U4udR3DcmypypA2LJ3pWRlSrpKNfq2EAWjrlt7bE586f6FudLx4JmS0P3mn2b7uIUR4THy5nzjpH5Z0LEIuPiZTdQfy1PZDsbeP8tVuFwiuepdqxGTR6tNxCAH1WUohzkt7O8RxrL2w9TA3D+eNyL3xhlIb+3sIjTXzY+sDDvaG6qQJWPgN9TvmdNxf6pzezM7W19sLmzZtTaqs1NFYmNmz8AQICNJkER82knRmPP/odPj09ru1rAO1gEyTWbwBtbx1oBxrBCobAe+vyR5Tzzn2c7U9cLlD31J87vuXjC0GW4ycnivICueW15SXfqi6Q25DX0KpYkMSVWZaoaoFX5mLPXVN49Xm1njcAPzMAB4J63gNrB++JJC0k5LjKp1Vu5HzVa7i0ce/zuRf8EiE0wIiihiUAwo0AiS6wjq3HLhjUhMJl9yJ3W/gjwxqmyAUNHimrgwEg8Ap0BrYvwHW+iNufVXX9kQO1nxxbt1TE1tXNBBT6Z3w8IW/JGsWRjgY/KxUERvfXdu5aQqMxF3GmTijPnfP75IYP1MjK58Boa7cTgrpjFx7EYVFRUHfuAv3wYRDHj3uJvLeeVRrmRQoZ+3dcpmRNg8RxY0zhe7PTHszyCAPsuGDcBAbIyE+giBxU5TrAg4njpnMyfvdeY/TbuBsPDgKbDob+7f0ZY+89P/PS+xR/x32WHZWRf5F/rPABHBjMtyQTL60hThpYoYNgDt0OfP6SZiL6u6g2VIyKC+l6ODAlZ+Erm3vfeNCB/Ghgrt3V/sxdRf4zNhK7mSmcbJSYaNR1rrpNM6KiA3mQKeq04mt/x/MOSzNi6PXxGKIfNwYCVtNZzMuxbziP29T27e9Wt32cSw1DIpJ0mjLhbtE4oLAYjqlT41h1QbQzfosXwNXdNlP2xuQE81yWCR6vECzPcaxr6VNt0PP9AgxFDfvCLPhne3j4pF+DZvzdwXO7xuVKO5u6kmcC/hZKGNl7u6CqWJ408A0fHq8nEbQGVOpENVUHS1BxMyDe5iGcJNF4h4Atg14iScyul7FDOR+MKKcRbfdMLsp9qsFddUMk2lzGKq59ePOio8ObzyvLXLBWM6NYG4JtRQRehp5Q3fRD/e9cxarOwDbP89a+Lwm+dw4f22QDLAgcODNjqK8OSKpJ5NbBoRLbgiDKaE245JZtbxPkjNOBO1Gr6H8wVej19bgtKDBSkWI8ksMlse54rx3H0l384e5ho7tjULfH1Y65IyUv4uWC2MbAVkhVYZZX2NdE4czROHegWy25eryxBWLN843eD25HQZgDZtJzWrGMToMAkE/7fWQOwR0+GKzJv/jRD5t/+RjjM8Z39V0v3jomY+5aVg4EeUzkFFtx93W9dKuKVSehAhNMUTUFVzzmU/Lt9h0V+IpyHmbPmwLr1mwBASvHBmBEu7FyOdfxz5+d0Rhwp7olQwdiIhj8KPGScAK9nn7yJAAe1xXQAVsZtJOimtPBQbqTD6T6gdkPAsMx3Tk29oefq+1//JU1ek1r5C8vonMVYmhikyB6NKqHkAdjVsoPc0VsfEbzkxn4GCZWrXiyxT/tmmPhfbWs+tqGPvxm2+CmC8qyFr5rUbQEKAy9wb21h/rXLHXY1iQBZZkL/zox7+I16BGBiifuVUJbt2zZ5bBx/XbkZIdDBz1lHLHawvj5t9bQUBy3PxtBtALMpoyOPmdpZm9eqTshuX6GhOYe2cub7xdx1xSzMKfBRKJjWMOWoJDm5NkcYIpnUSj6wkba8XhFnLAs99Wlzr4/nh0nI8gRQUe1XcUpeW8CpxzBXh6kWiApjLnORB9omb0bDS5nlouGG/cgmKV2JbKKTPaBUwvoNUXfffj9Az9aZRsXrL69nc/9pDRj7rus8lgC2X70iTtVPSyxCuQw8s0svfEhh+CB020NRTItr6iCpVdcjKCnp/fp4fB4e+IT/aHr0ovfULfvaNX21iOYLD+eiqGtsE4nyGfNspWWR36LUgEeS7/UHx9QfgJJzc1GfDBilDkEKPA7xW5qiwpAY08Mwkn0+Aja7HI3ZLl5G0gBzfPLO0O1x8uT06DaemU+VhpnA8r2qfzxT/jsxY9ZWEkU1Ra0EO4axlGRsc58wJdeBXzmvDS98U7fyaVOmBkf2gIVZTf/ubFz1Q97w/Vn2sob3DHv6PCWxRPzlqzvDu2deqj/3UsZ1zFLk++buhZv+W+HBzb+3dQtKxJUTMHHFErHbAfDsEfJCoVkfJJ5/t/8AlxXXm6DZKcLBiDyIsu80lmzIf2Rh8B3z12K6/JLs5Urr8jK/84l6QsrHB6qG9YoB4VDhr9r2Fg8s1SBkgwHxrcktqJpT2PFNQvahzS7GnO8AnQP69Mbu5MzmViAxUG2Mx6r8ParujWSbUVnmAiu1VaojqkA7sOsr4nFhRkcK0souQ7Eqnvwt9gMTCLpp0wQsKId/IixiTGl6Hv3s4FkSmtZBuzuWLnCwHPt6Vh5i45cx47jMarVFl51v4IDIglsVtv9qZXqIkwYPw4E9Gt/SW7ecgeeTWA8lvjrez9SFi98XT5nzjBRZMBUgUoXAQ6B5HJyQCwvA0wcELrvgUcSH2y6lshy1GkklLHfvvEmIs2K0fiIWUGQVm4ZvnvJNO9a5Lm+uEZtsEbFg3FhIG5BMQL7/LbAvZaKqDGmUAksnKy+WuiNz0xEYWKKJkwReJeT2DeO1BjvRChCwPkm29aFc5Xj9iQwelb/R6pQToBHWfeGG0CPtuC15qwpSjtjE3q9c1iVoRGeu+7gil8f6l97EWtX1qLlmQvfrcg+d4thal8418NJs76xV543509WDL0TSrDRdnRC8J5frNYPNueyxMH5fMD5Uf3xL5+eBlYgAJHHn/xx4r31N2LORbUe9Atez5G6jImbaFI/4T4RvNauZMVFj7W/VdeRqHAjMCKLTogcW9lnNM6+657r+tO6fZGLbOAwomVnCh13XFByN5WK2+0gwLjLUBUabrgpVUb8iGey7EkDrEisvm5Z23/bE9bg1gWnTLLRlMiQeBD4YB3wgheml1z/a7QlNJUyKL+v+6W7DSuZxvbFTGvNLv/Rg24pB1xSJq5Zn7sKrBUxMazQWw9PNj5prSWKwpLEfLO7p06orHiK83o2oucLkFhc1CKRKr3x4PfNox2LRr0h2hxLWr78HiWtqp/bfVS2Rm4ao1iPyhPlUEdi5v0BbXd1ofIiKuo6t0wGseLcb+8Lz97fmfx+36BWDA7Ojl+EJ9oDl2XfVlsm9Rv8dU/D4A/Pt0HCgTDan/sxCews5tJmPAlGpAfMBKWJbg8mi5lWYPdNVrS3msi+IeLwBdH7laU8kQc47yTkvThIaKxVzKklaWf+DfPt6y3H1l7ClJWzyZ6AbiUBBWS1yLs3dwb2fKkZRsLenrGpKHXrtqzIUyuf1ZsPXWDPXI7MWNicx6eAYqpMR+01iwMZ6QMZV19+7Uc157/z5H4oXLNruCmpodoiwZfmSn+cN9H90ut7wn8OBfXMlEcceafBTmGOXGPEgvi8Qt/tizKv/u6stA+KfCZylAZq3fUrzK5XH7AtCjfyPMSeyzLYfB0qh8jMHLslTvaHUHkvNAO7LrH6PrzNLlJXQZNQcftk1FfdQC8XyJiFY+5EZa8/Y03DrVuw+gSWKmw/QC26cNx9Z2W4yrYxg/xlFv4XP2VEa2BmDcQdlZV/5vNyt9KkKuN32QiCk1oW5jNttMrwJuUEn59XL02pfdh54bduFGpq6o+ADyxBcvVH9HEZXqHN7xU6a4uV9zH4r67MkVa5nHw8rNOCuE6x72nqxQdWE1YazfGLrVNLlUeWzvBfO61EafTIAmS6MO1YMQQ4uZXzVmNwVbOQ6/LRJ0g2UtRiUyw8a2kipfVwaZOfEUpv/C7nGddAE+05hFg+omS3ECXvIO+b/Fe8aZNwPJjOQjbvh+ev7B6OH5nUH2mYyIyzjtGrKveCl2eW3PAo84GKmPalVmJGorZvw1gGNBwGCwkfjTOYwaDfGhgqtwYH8oRJE71G6xGNc7kGkAPbhKKCTmqYFidjCikqhsi4GoiYPLy2K2i/GTPxASuyJZYaYPfROHgVHi2KJaPCVh05po0tzXK4WvrVWJpTaKstkptVgyaZ10OgobpAgaosC3gzDEbXy1itHlsArODePJroGg+cmA1ShkCDdRHOXdVNlKJm4J1RgsEdI1rKxjBetNsdRc4/PfUeFo1wCIHiMY4l9EDWOw3LtwfjHWM5HACek5JXzXz9zBxPdT3y3z84DT/amriiSQ5ymRm7mUTKs84ElVULjh77TJnxRZNMUWBYNzGHktDZew2aAg9/163UjDHrziQKARZassAn7sMQsm9epdt+Ac7eZ3D29JXF8u1nGPLUjBwqbS8o+b1ELsB2LEXK60HDlZt6l8HaDJNCamJUZ2Q0IijoPpDnVAQohsIi4N0yq1HX9cItg9GWsRIOjIZcODZrwes+pag+ovb9c+8wTk4RwOIWtjQzxsga+AA09bIFvvpbMHtcRkBlsY2BzOyjRU9xFp+zMED0FFAmVgdF2rOYP/3suTmCALJfVTkHWIUJeO+RZG/BgZ6/3MDakymuJHgTZZnzH+gO7jnlvwn+OfD+xReClchmS2JoOZIINMdeIyBn7+p4+o6o2pfDlFbDFp+Uu/T5MRlzGnQj/s+/PfvXX5jYYKuKXoh6qzGwOFJA4t/B6CcTDvWtuZ4nDrvKZNGfQN/3hAd9nSGq/w8e4wDVX4vrNPtfQHibA3lgbdrU9+aVlqWbiujvxjThrs6/ZGWOt7qBTXT+I8v/CjAAJOOJ0FaTyhsAAAAASUVORK5CYII=');\n}"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-base64/foo.css",
    "content": ".foo {\n    background-image: url(ebay-logo.png?base64);\n}"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-base64/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-base64/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'foo.css')\n                ]\n            },\n            check(lassoPageResult, writerTracker, helpers) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-css-inline-resource-base64-head.css'\n                ]);\n\n                var actualCSS = writerTracker.getCodeForFilename('bundling-css-inline-resource-base64-head.css');\n                helpers.compare(actualCSS, '.css');\n            }\n        }\n    ];\n};\n"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-utf8/expected.css",
    "content": ".foo {\n    background-image: url('data:image/svg+xml;utf8,<?xml version=\"1.0\"?>%0A<svg viewBox=\"0 0 120 120\" version=\"1.1\"%0A  xmlns=\"http://www.w3.org/2000/svg\">%0A  <circle cx=\"60\" cy=\"60\" r=\"50\"/>%0A</svg>%0A');\n}"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-utf8/foo.css",
    "content": ".foo {\n    background-image: url(./circle.svg?utf8);\n}"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-utf8/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/css-inline-resource-utf8/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'foo.css')\n                ]\n            },\n            check(lassoPageResult, writerTracker, helpers) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-css-inline-resource-utf8-head.css'\n                    ]);\n\n                var actualCSS = writerTracker.getCodeForFilename('bundling-css-inline-resource-utf8-head.css');\n                helpers.compare(actualCSS, '.css');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/css-resources-multiple-pages-no-bundling/foo.css",
    "content": ".foo {\n    background-image: url('./foo.resource');\n}"
  },
  {
    "path": "test/autotests/bundling/css-resources-multiple-pages-no-bundling/foo.resource",
    "content": "foo"
  },
  {
    "path": "test/autotests/bundling/css-resources-multiple-pages-no-bundling/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/css-resources-multiple-pages-no-bundling/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: false,\n        bundlingEnabled: false\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                pageName: 'css-resources-multiple-pages-no-bundling-page1',\n                dependencies: [\n                    path.join(__dirname, 'foo.css')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                var resources = lassoPageResult.resources;\n                var outputFiles = resources.map((resource) => {\n                    return resource.outputFile;\n                });\n\n                expect(outputFiles[0]).to.contain('css-resources-multiple-pages-no-bundling-page1');\n            }\n        },\n        {\n            lassoOptions: {\n                pageName: 'css-resources-multiple-pages-no-bundling-page2',\n                dependencies: [\n                    path.join(__dirname, 'foo.css')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                var resources = lassoPageResult.resources;\n                var outputFiles = resources.map((resource) => {\n                    return resource.outputFile;\n                });\n\n                expect(outputFiles[0]).to.contain('css-resources-multiple-pages-no-bundling-page2');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/custom-dependency-type-no-bundling/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/custom-dependency-type-no-bundling/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: false,\n        plugins: [\n            {\n                plugin: function(lasso, config) {\n                    lasso.dependencies.registerJavaScriptType('foo', {\n                        properties: {\n                        },\n\n                        async init (lassoContext) {},\n\n                        read: function(lassoContext) {\n                            return 'FOO';\n                        }\n                    });\n                }\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {type: 'foo'}\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'foo-bundling-custom-dependency-type-no-bundling.js'\n                    ]);\n\n                    var jsFile = lassoPageResult.getJavaScriptFiles()[0];\n                    expect(writerTracker.getCodeForPath(jsFile)).to.equal(\"FOO\");\n\n            }\n        }\n    ];\n};\n"
  },
  {
    "path": "test/autotests/bundling/dedupe/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/dedupe/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/dedupe/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\",\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/dedupe/c.js",
    "content": "c"
  },
  {
    "path": "test/autotests/bundling/dedupe/d.js",
    "content": "d"
  },
  {
    "path": "test/autotests/bundling/dedupe/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/dedupe/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'bundle1',\n                dependencies: [\n                    path.join(__dirname, 'a.js'),\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            {\n                name: 'bundle2',\n                dependencies: [\n                    path.join(__dirname, 'b.js'),\n                    path.join(__dirname, 'c.js')\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'a.js'),\n                    path.join(__dirname, 'b.js'),\n                    path.join(__dirname, 'c.js'),\n                    path.join(__dirname, 'd.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundle1.js',\n                        'bundle2.js',\n                        'bundling-dedupe.js',\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('bundle1.js')).to.equal('a\\nb');\n                expect(writerTracker.getCodeForFilename('bundle2.js')).to.equal('c');\n                expect(writerTracker.getCodeForFilename('bundling-dedupe.js')).to.equal('d');\n\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/dependency-code/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/dependency-code/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: false\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            {\n                type: 'js',\n                code: 'abc123',\n                virtualPath: path.join(__dirname, 'virtual/foo.js')\n            }\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    expect(lassoPageResult.getJavaScriptUrls()[0]).to.contain('/virtual/foo.js');\n    \n    var fooCode = writerTracker.getCodeForFilename(writerTracker.getOutputFilenames()[0]);\n    expect(fooCode).to.contain('abc123');\n};"
  },
  {
    "path": "test/autotests/bundling/escape-external-css-url/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/escape-external-css-url/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        type: 'css',\n                        url: 'https://fonts.googleapis.com/css?family=Open+Sans&subset=latin'\n                    }\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(lassoPageResult.getBodyHtml()).to.equal('');\n                expect(lassoPageResult.getHeadHtml()).to.equal('<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Open+Sans&subset=latin\">');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/escape-external-js-url/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/escape-external-js-url/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        type: 'js',\n                        url: 'https://maps.googleapis.com/maps/api/js?key=KEY&callback=CB'\n                    }\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(lassoPageResult.getBodyHtml()).to.equal('<script src=\"https://maps.googleapis.com/maps/api/js?key=KEY&callback=CB\"></script>');\n                expect(lassoPageResult.getHeadHtml()).to.equal('');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/external-js/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/external-js/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    'js: http://code.jquery.com/jquery-1.11.0.min.js'\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(lassoPageResult.getBodyHtml()).to.equal('<script src=\"http://code.jquery.com/jquery-1.11.0.min.js\"></script>');\n                expect(lassoPageResult.getHeadHtml()).to.equal('');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/external-js-inlined/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/external-js-inlined/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        type: 'js',\n                        url: 'http://code.jquery.com/jquery-1.11.0.min.js',\n                        external: false\n                    }\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(lassoPageResult.getBodyHtml()).to.equal('<script src=\"/static/bundling-external-js-inlined-445d8c96.js\"></script>');\n                expect(lassoPageResult.getHeadHtml()).to.equal('');\n            }\n        }\n    ];\n};\n"
  },
  {
    "path": "test/autotests/bundling/external-js-integrity/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/external-js-integrity/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        type: 'js',\n                        url: 'https://maps.googleapis.com/maps/api/js?key=KEY&callback=CB',\n                        attributes: { integrity:'abc123' }\n                    }\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(lassoPageResult.getBodyHtml()).to.equal('<script src=\"https://maps.googleapis.com/maps/api/js?key=KEY&callback=CB\" integrity=\"abc123\"></script>');\n                expect(lassoPageResult.getHeadHtml()).to.equal('');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/fingerprints/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\",\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/fingerprints/foo.css",
    "content": ".foo {\n    color: red;\n}"
  },
  {
    "path": "test/autotests/bundling/fingerprints/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/bundling/fingerprints/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/fingerprints/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-fingerprints-15c73efd.css',\n                        'bundling-fingerprints-b691c0e8.js'\n                    ]);\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/glob-patterns/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"style/*.css\",\n        \"require: require/*.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/glob-patterns/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/glob-patterns/require/bar.js",
    "content": "module.exports=\"BAR\";"
  },
  {
    "path": "test/autotests/bundling/glob-patterns/require/foo.js",
    "content": "module.exports=\"FOO\";"
  },
  {
    "path": "test/autotests/bundling/glob-patterns/style/style1.css",
    "content": ".style1 {}"
  },
  {
    "path": "test/autotests/bundling/glob-patterns/style/style2.css",
    "content": ".style2 {}"
  },
  {
    "path": "test/autotests/bundling/glob-patterns/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-glob-patterns.css',\n                        'bundling-glob-patterns.js'\n                    ]);\n\n                    var jsFile = lassoPageResult.getJavaScriptFiles()[0];\n                    var cssFile = lassoPageResult.getCSSFiles()[0];\n\n                    expect(writerTracker.getCodeForPath(cssFile)).to.equal(\".style1 {}\\n.style2 {}\");\n                    expect(writerTracker.getCodeForPath(jsFile)).to.contain(\"FOO\");\n                    expect(writerTracker.getCodeForPath(jsFile)).to.contain(\"BAR\");\n                    expect(writerTracker.getCodeForPath(jsFile)).to.contain(\"$_mod.def\");\n\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/glob-patterns-relative-paths/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./style/*.css\",\n        \"require: ./require/*.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/glob-patterns-relative-paths/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/glob-patterns-relative-paths/require/bar.js",
    "content": "module.exports=\"BAR\";"
  },
  {
    "path": "test/autotests/bundling/glob-patterns-relative-paths/require/foo.js",
    "content": "module.exports=\"FOO\";"
  },
  {
    "path": "test/autotests/bundling/glob-patterns-relative-paths/style/style1.css",
    "content": ".style1 {}"
  },
  {
    "path": "test/autotests/bundling/glob-patterns-relative-paths/style/style2.css",
    "content": ".style2 {}"
  },
  {
    "path": "test/autotests/bundling/glob-patterns-relative-paths/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-glob-patterns-relative-paths.css',\n                        'bundling-glob-patterns-relative-paths.js'\n                    ]);\n\n                    var jsFile = lassoPageResult.getJavaScriptFiles()[0];\n                    var cssFile = lassoPageResult.getCSSFiles()[0];\n\n                    expect(writerTracker.getCodeForPath(cssFile)).to.equal(\".style1 {}\\n.style2 {}\");\n                    expect(writerTracker.getCodeForPath(jsFile)).to.contain(\"FOO\");\n                    expect(writerTracker.getCodeForPath(jsFile)).to.contain(\"BAR\");\n                    expect(writerTracker.getCodeForPath(jsFile)).to.contain(\"$_mod.def\");\n\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/inline-async-script/a.js",
    "content": "var a;"
  },
  {
    "path": "test/autotests/bundling/inline-async-script/b.js",
    "content": "var b;"
  },
  {
    "path": "test/autotests/bundling/inline-async-script/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/inline-async-script/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/inline-async-script/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: true\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-inline-async-script.js'\n                    ]);\n\n                    var body = lassoPageResult.getSlotHtml('body', {\n                        externalScriptAttrs: {\n                            async: true\n                        }\n                    });\n\n                    expect(body).to.equal(\n                        '<script src=\"/static/bundling-inline-async-script.js\" async></script>\\n' +\n                        '<script>(function() { var run = function() { var a; }; if (document.readyState !== \"complete\") { window.addEventListener(\"load\", run); } else { run(); } })();</script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/inline-css-html-chars/expected.html",
    "content": "<style>.foo {\n    background-image: url(\"data:image/svg+xml;utf8,<svg></svg>\")\n}</style>"
  },
  {
    "path": "test/autotests/bundling/inline-css-html-chars/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/inline-css-html-chars/style.css",
    "content": ".foo {\n    background-image: url(\"data:image/svg+xml;utf8,<svg></svg>\")\n}"
  },
  {
    "path": "test/autotests/bundling/inline-css-html-chars/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'style.css'),\n                        inline: true\n                    }\n                ]\n            },\n            check(lassoPageResult, writerTracker, helpers) {\n                var head = lassoPageResult.getSlotHtml('head');\n                helpers.compare(head, '.html');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/inline-defer-script/a.js",
    "content": "var a;"
  },
  {
    "path": "test/autotests/bundling/inline-defer-script/b.js",
    "content": "var b;"
  },
  {
    "path": "test/autotests/bundling/inline-defer-script/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/inline-defer-script/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/inline-defer-script/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: true\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-inline-defer-script.js'\n                    ]);\n\n                    var body = lassoPageResult.getSlotHtml('body', {\n                        externalScriptAttrs: {\n                            defer: true\n                        }\n                    });\n\n                    expect(body).to.equal(\n                        '<script src=\"/static/bundling-inline-defer-script.js\" defer></script>\\n' +\n                        '<script>(function() { var run = function() { var a; }; if (document.readyState === \"loading\") { document.addEventListener(\"DOMContentLoaded\", run); } else { run(); } })();</script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/inline-script-external-attrs/a.js",
    "content": "var a;"
  },
  {
    "path": "test/autotests/bundling/inline-script-external-attrs/b.js",
    "content": "var b;"
  },
  {
    "path": "test/autotests/bundling/inline-script-external-attrs/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/inline-script-external-attrs/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/inline-script-external-attrs/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: true\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-inline-script-external-attrs.js'\n                ]);\n\n                var body = lassoPageResult.getSlotHtml('body', {\n                    externalScriptAttrs: {\n                        x: 1\n                    }\n                });\n\n                expect(body).to.equal(\n                    '<script src=\"/static/bundling-inline-script-external-attrs.js\" x=1></script>\\n' +\n                    '<script>var a;</script>'\n                );\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/intersection/bar.js",
    "content": "BAR"
  },
  {
    "path": "test/autotests/bundling/intersection/common.js",
    "content": "COMMON"
  },
  {
    "path": "test/autotests/bundling/intersection/foo.js",
    "content": "FOO"
  },
  {
    "path": "test/autotests/bundling/intersection/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/intersection/page1.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"foo.js\",\n        \"common.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection/page2.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"common.js\",\n        \"bar.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'common',\n                dependencies: [\n                    {\n                        'intersection': [\n                            path.join(__dirname, 'page1.browser.json'),\n                            path.join(__dirname, 'page2.browser.json')\n                        ]\n                    }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                pageName: 'page1',\n                dependencies: [\n                    path.join(__dirname, 'page1.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getCodeForFilename('page1.js')).to.equal(\"FOO\");\n\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'common.js',\n                        'page1.js'\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.equal(\"COMMON\");\n            }\n        },\n        {\n            lassoOptions: {\n                pageName: 'page2',\n                dependencies: [\n                    path.join(__dirname, 'page2.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getCodeForFilename('page2.js')).to.equal(\"BAR\");\n\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'common.js',\n                        'page2.js'\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.equal(\"COMMON\");\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/a.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/ab.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/abc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/bc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-100percent/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'common',\n                dependencies: [\n                    {\n                        threshold: '100%',\n                        intersection: [\n                            // a.js is found in 2/3 (100%)\n                            // b.js is found in 2/3 (66.6%)\n                            // c.js if found in 1/3 (33.3%)\n                            path.join(__dirname, 'a.browser.json'),\n                            path.join(__dirname, 'ab.browser.json'),\n                            path.join(__dirname, 'abc.browser.json')\n                        ]\n                    }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'abc.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-intersection-threshold-100percent.js',\n                    'common.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.equal('a=true;');\n                expect(writerTracker.getCodeForFilename('bundling-intersection-threshold-100percent.js')).to.equal('b=true;\\nc=true;');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/a.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/ab.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/abc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/bc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'common',\n                dependencies: [\n                    {\n                        threshold: 2,\n                        intersection: [\n                            // a.js is found in 2/3 (100%)\n                            // b.js is found in 2/3 (66.6%)\n                            // c.js if found in 1/3 (33.3%)\n                            path.join(__dirname, 'a.browser.json'),\n                            path.join(__dirname, 'ab.browser.json'),\n                            path.join(__dirname, 'abc.browser.json')\n                        ]\n                    }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'abc.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-intersection-threshold-2.js',\n                    'common.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.equal('a=true;\\nb=true;');\n                expect(writerTracker.getCodeForFilename('bundling-intersection-threshold-2.js')).to.equal('c=true;');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2-require/a.js",
    "content": "'THIS_IS_A'\nrequire('./shared');"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2-require/b.js",
    "content": "'THIS_IS_B'\nrequire('./shared');"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2-require/main.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./a\",\n        \"require: ./b\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2-require/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2-require/shared.js",
    "content": "'THIS_IS_SHARED'"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2-require/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'common',\n                dependencies: [\n                    {\n                        intersection: [\n                            'require: ./a',\n                            'require: ./b'\n                        ]\n                    }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'main.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-intersection-threshold-2-require.js',\n                    'common.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.contain('THIS_IS_SHARED');\n                expect(writerTracker.getCodeForFilename('bundling-intersection-threshold-2-require.js')).to.contain('THIS_IS_A');\n                expect(writerTracker.getCodeForFilename('bundling-intersection-threshold-2-require.js')).to.contain('THIS_IS_B');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/a.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/ab.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/abc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/bc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-2str/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'common',\n                dependencies: [\n                    {\n                        threshold: '2',\n                        intersection: [\n                            // a.js is found in 2/3 (100%)\n                            // b.js is found in 2/3 (66.6%)\n                            // c.js if found in 1/3 (33.3%)\n                            path.join(__dirname, 'a.browser.json'),\n                            path.join(__dirname, 'ab.browser.json'),\n                            path.join(__dirname, 'abc.browser.json')\n                        ]\n                    }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'abc.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-intersection-threshold-2str.js',\n                    'common.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.equal('a=true;\\nb=true;');\n                expect(writerTracker.getCodeForFilename('bundling-intersection-threshold-2str.js')).to.equal('c=true;');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/a.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/ab.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/abc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/bc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-3/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'common',\n                dependencies: [\n                    {\n                        threshold: 3,\n                        intersection: [\n                            // a.js is found in 2/3 (100%)\n                            // b.js is found in 2/3 (66.6%)\n                            // c.js if found in 1/3 (33.3%)\n                            path.join(__dirname, 'a.browser.json'),\n                            path.join(__dirname, 'ab.browser.json'),\n                            path.join(__dirname, 'abc.browser.json')\n                        ]\n                    }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'abc.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-intersection-threshold-3.js',\n                    'common.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.equal('a=true;');\n                expect(writerTracker.getCodeForFilename('bundling-intersection-threshold-3.js')).to.equal('b=true;\\nc=true;');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/a.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/ab.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/abc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./a.js\",\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/bc.browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./b.js\",\n        \"./c.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/intersection-threshold-50percent/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'common',\n                dependencies: [\n                    {\n                        threshold: '50%',\n                        intersection: [\n                            // a.js is found in 2/3 (100%)\n                            // b.js is found in 2/3 (66.6%)\n                            // c.js if found in 1/3 (33.3%)\n                            path.join(__dirname, 'a.browser.json'),\n                            path.join(__dirname, 'ab.browser.json'),\n                            path.join(__dirname, 'abc.browser.json')\n                        ]\n                    }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'abc.browser.json')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'bundling-intersection-threshold-50percent.js',\n                    'common.js'\n                ]);\n\n                expect(writerTracker.getCodeForFilename('common.js')).to.equal('a=true;\\nb=true;');\n                expect(writerTracker.getCodeForFilename('bundling-intersection-threshold-50percent.js')).to.equal('c=true;');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/modules-ready-lastSlot/body.js",
    "content": "console.log('body');"
  },
  {
    "path": "test/autotests/bundling/modules-ready-lastSlot/head.js",
    "content": "console.log('head');"
  },
  {
    "path": "test/autotests/bundling/modules-ready-lastSlot/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/modules-ready-lastSlot/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        require: {\n            lastSlot: 'body'\n        }\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        type: 'require',\n                        path: path.join(__dirname, 'head.js'),\n                        run: true,\n                        wait: false,\n                        slot: 'head'\n                    },\n                    {\n                        type: 'require',\n                        path: path.join(__dirname, 'body.js'),\n                        run: true,\n                        wait: false\n                    }\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                var htmlBySlot = lassoPageResult.getHtmlBySlot();\n                expect(htmlBySlot.head).to.equal('<script src=\"/static/bundling-modules-ready-lastSlot.js\"></script>');\n                expect(htmlBySlot.body).to.equal('<script src=\"/static/bundling-modules-ready-lastSlot.js\"></script>\\n<script>$_mod.ready();</script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/no-bundles/main.js",
    "content": "require('foo');\nconsole.log('[MAIN]');\n"
  },
  {
    "path": "test/autotests/bundling/no-bundles/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/no-bundles/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: []\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            'require: ./main'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var fooCode = writerTracker.getCodeForFilename(writerTracker.getOutputFilenames()[0]);\n    expect(fooCode).to.contain('[MAIN]');\n    expect(fooCode).to.contain('[FOO]');\n    expect(fooCode).to.contain('[FOO_INDEX]');\n    expect(fooCode).to.contain('[BAR]');\n    expect(fooCode).to.contain('[BAZ]');\n};"
  },
  {
    "path": "test/autotests/bundling/recurseInto-all/main.js",
    "content": "require('foo');\nconsole.log('[MAIN]');\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-all/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-all/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'foo',\n                dependencies: [\n                    // Specified for a single dependency:\n                    { path: 'require: foo', recurseInto: 'all' }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            'require: ./main'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var fooCode = writerTracker.getCodeForFilename('foo.js');\n    expect(fooCode).to.not.contain('[MAIN]');\n    expect(fooCode).to.contain('[FOO]');\n    expect(fooCode).to.contain('[FOO_INDEX]');\n    expect(fooCode).to.contain('[BAR]');\n    expect(fooCode).to.contain('[BAZ]');\n};"
  },
  {
    "path": "test/autotests/bundling/recurseInto-dir/main.js",
    "content": "require('foo');\nconsole.log('[MAIN]');\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-dir/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-dir/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'foo',\n                dependencies: [\n                    // Specified for a single dependency:\n                    { path: 'require: foo', recurseInto: 'dir' }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            'require: ./main'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var fooCode = writerTracker.getCodeForFilename('foo.js');\n    expect(fooCode).to.not.contain('[MAIN]');\n    expect(fooCode).to.not.contain('[FOO]');\n    expect(fooCode).to.contain('[FOO_INDEX]');\n    expect(fooCode).to.not.contain('[BAR]');\n    expect(fooCode).to.not.contain('[BAZ]');\n};"
  },
  {
    "path": "test/autotests/bundling/recurseInto-dirtree/main.js",
    "content": "require('foo');\nconsole.log('[MAIN]');\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-dirtree/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-dirtree/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'foo',\n                dependencies: [\n                    // Specified for a single dependency:\n                    { path: 'require: foo', recurseInto: 'dirtree' }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            'require: ./main'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var fooCode = writerTracker.getCodeForFilename('foo.js');\n    expect(fooCode).to.not.contain('[MAIN]');\n    expect(fooCode).to.contain('[FOO]');\n    expect(fooCode).to.contain('[FOO_INDEX]');\n    expect(fooCode).to.contain('[BAR]');\n    expect(fooCode).to.not.contain('[BAZ]');\n};"
  },
  {
    "path": "test/autotests/bundling/recurseInto-module/main.js",
    "content": "require('foo');\nconsole.log('[MAIN]');\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-module/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/recurseInto-module/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'foo',\n                dependencies: [\n                    // Specified for a single dependency:\n                    { path: 'require: foo', recurseInto: 'module' }\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            'require: ./main'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var fooCode = writerTracker.getCodeForFilename('foo.js');\n    expect(fooCode).to.not.contain('[MAIN]');\n    expect(fooCode).to.contain('[FOO]');\n    expect(fooCode).to.contain('[FOO_INDEX]');\n    expect(fooCode).to.not.contain('[BAR]');\n    expect(fooCode).to.not.contain('[BAZ]');\n};"
  },
  {
    "path": "test/autotests/bundling/registerRequireExtension-not-cacheable/foo.js",
    "content": "$$FOO$$"
  },
  {
    "path": "test/autotests/bundling/registerRequireExtension-not-cacheable/hello.dynamic",
    "content": ""
  },
  {
    "path": "test/autotests/bundling/registerRequireExtension-not-cacheable/hello.js",
    "content": "$$HELLO$$"
  },
  {
    "path": "test/autotests/bundling/registerRequireExtension-not-cacheable/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/registerRequireExtension-not-cacheable/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            function(lasso, pluginConfig) {\n                lasso.dependencies.registerRequireExtension(\n                    'dynamic',\n                    {\n                        read: function(filename, lassoContext) {\n                            var target = lassoContext.data.target;\n                            return 'module.exports = require(\"./' + target + '\")';\n                        }\n                    });\n            }\n        ]\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                flags: ['hello'],\n                data: {\n                    target: 'hello'\n                },\n                dependencies: [\n                    `require: ${path.join(__dirname, 'hello.dynamic')}`\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames().length).to.equal(1);\n                expect(writerTracker.getCodeForFilename(writerTracker.getOutputFilenames()[0])).to.contain('$$HELLO$$');\n                expect(writerTracker.getCodeForFilename(writerTracker.getOutputFilenames()[0])).to.not.contain('$$FOO$$');\n            }\n        },\n        {\n            lassoOptions: {\n                flags: ['foo'],\n                data: {\n                    target: 'foo'\n                },\n                dependencies: [\n                    `require: ${path.join(__dirname, 'hello.dynamic')}`\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames().length).to.equal(1);\n                expect(writerTracker.getCodeForFilename(writerTracker.getOutputFilenames()[0])).to.contain('$$FOO$$');\n                expect(writerTracker.getCodeForFilename(writerTracker.getOutputFilenames()[0])).to.not.contain('$$HELLO$$');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/resource-absolute-path/foo.js",
    "content": "console.log('MAIN');\n"
  },
  {
    "path": "test/autotests/bundling/resource-absolute-path/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/resource-absolute-path/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'foo.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-resource-absolute-path.js'\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('bundling-resource-absolute-path.js')).to.equal(\"console.log('MAIN');\\n\");\n\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/slots/foo.css",
    "content": "foo_css"
  },
  {
    "path": "test/autotests/bundling/slots/foo.js",
    "content": "foo_js"
  },
  {
    "path": "test/autotests/bundling/slots/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/slots/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'foo.js'),\n                    path.join(__dirname, 'foo.css')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-slots-body.js',\n                        'bundling-slots-head.css'\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('bundling-slots-head.css')).to.equal('foo_css');\n                expect(writerTracker.getCodeForFilename('bundling-slots-body.js')).to.equal('foo_js');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/slots-inline-beginning/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/slots-inline-beginning/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/slots-inline-beginning/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/slots-inline-beginning/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: 'beginning'\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n\n                expect(writerTracker.getOutputFilenames()).to.deep.equal(['bundling-slots-inline-beginning-body.js']);\n\n                var body = lassoPageResult.getSlotHtml('body');\n\n                expect(body).to.equal('<script>a</script>\\n<script src=\"/static/bundling-slots-inline-beginning-body.js\"></script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/slots-inline-end/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/slots-inline-end/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/slots-inline-end/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/slots-inline-end/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: 'end'\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n\n                expect(writerTracker.getOutputFilenames()).to.deep.equal(['bundling-slots-inline-end-body.js']);\n\n                var body = lassoPageResult.getSlotHtml('body');\n\n                expect(body).to.equal('<script src=\"/static/bundling-slots-inline-end-body.js\"></script>\\n<script>a</script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/slots-inline-false/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/slots-inline-false/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/slots-inline-false/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/slots-inline-false/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: false\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n\n                expect(writerTracker.getOutputFilenames()).to.deep.equal(['bundling-slots-inline-false-body.js']);\n\n                var body = lassoPageResult.getSlotHtml('body');\n                expect(body).to.equal('<script src=\"/static/bundling-slots-inline-false-body.js\"></script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/slots-inline-in-place/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/slots-inline-in-place/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/slots-inline-in-place/c.js",
    "content": "c"
  },
  {
    "path": "test/autotests/bundling/slots-inline-in-place/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/slots-inline-in-place/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: false\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    path.join(__dirname, 'a.js'),\n                    {\n                        path: path.join(__dirname, 'b.js'),\n                        inline: 'in-place'\n                    },\n                    path.join(__dirname, 'c.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                    'a.js',\n                    'c.js'\n                ]);\n\n                var body = lassoPageResult.getSlotHtml('body');\n\n                expect(body).to.equal(\n                    '<script src=\"/static/bundling-slots-inline-in-place/test-bundling-project$0.0.0/a.js\"></script>\\n' +\n                    '<script>b</script>\\n' +\n                    '<script src=\"/static/bundling-slots-inline-in-place/test-bundling-project$0.0.0/c.js\"></script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/slots-inline-true/a.js",
    "content": "a"
  },
  {
    "path": "test/autotests/bundling/slots-inline-true/b.js",
    "content": "b"
  },
  {
    "path": "test/autotests/bundling/slots-inline-true/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/slots-inline-true/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'a.js'),\n                        inline: true\n                    },\n                    path.join(__dirname, 'b.js')\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n\n                expect(writerTracker.getOutputFilenames()).to.deep.equal(['bundling-slots-inline-true-body.js']);\n\n                var body = lassoPageResult.getSlotHtml('body');\n\n                expect(body).to.equal('<script src=\"/static/bundling-slots-inline-true-body.js\"></script>\\n<script>a</script>');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/bundling/slots-override/foo.css",
    "content": "foo_css"
  },
  {
    "path": "test/autotests/bundling/slots-override/foo.js",
    "content": "foo_js"
  },
  {
    "path": "test/autotests/bundling/slots-override/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/bundling/slots-override/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        includeSlotNames: true\n    };\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            lassoOptions: {\n                dependencies: [\n                    {\n                        path: path.join(__dirname, 'foo.js'),\n                        slot: 'head'\n                    },\n                    {\n                        path: path.join(__dirname, 'foo.css'),\n                        slot: 'body'\n                    }\n\n                ]\n            },\n            check(lassoPageResult, writerTracker) {\n                expect(writerTracker.getOutputFilenames()).to.deep.equal([\n                        'bundling-slots-override-body.css',\n                        'bundling-slots-override-head.js'\n                    ]);\n\n                expect(writerTracker.getCodeForFilename('bundling-slots-override-body.css')).to.equal('foo_css');\n                expect(writerTracker.getCodeForFilename('bundling-slots-override-head.js')).to.equal('foo_js');\n\n                expect(lassoPageResult.getHeadHtml()).to.contain('bundling-slots-override-head.js');\n                expect(lassoPageResult.getBodyHtml()).to.contain('bundling-slots-override-body.css');\n            }\n        }\n    ];\n};"
  },
  {
    "path": "test/autotests/dep-require/async/bar.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-require/async/expected.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"commonjs-runtime\"\n        },\n        {\n            \"type\": \"commonjs-ready\",\n            \"inline\": \"end\"\n        },\n        {\n            \"type\": \"commonjs-builtin\",\n            \"name\": \"lasso-loader\",\n            \"target\": \"/lasso-loader$x.x.x/src/index\",\n            \"_sourceFile\": \"/node_modules/lasso-loader/src/index.js\"\n        },\n        {\n            \"type\": \"require\",\n            \"path\": \"lasso-loader\",\n            \"from\": \"/test/autotests/dep-require/async\",\n            \"resolved\": {\n                \"path\": \"/node_modules/lasso-loader/src/index.js\",\n                \"meta\": [\n                    {\n                        \"type\": \"builtin\",\n                        \"name\": \"lasso-loader\",\n                        \"target\": \"/node_modules/lasso-loader/src/index.js\"\n                    }\n                ],\n                \"clientPath\": \"/lasso-loader$x.x.x/src/index\"\n            }\n        },\n        {\n            \"type\": \"commonjs-def\",\n            \"path\": \"/autotest$0/foo\",\n            \"file\": \"/test/autotests/dep-require/async/foo.js\",\n            \"inspected\": {\n                \"requires\": [\n                    {\n                        \"path\": \"lasso-loader\",\n                        \"range\": [\n                            0,\n                            23\n                        ],\n                        \"argRange\": [\n                            8,\n                            22\n                        ],\n                        \"resolved\": {\n                            \"path\": \"/node_modules/lasso-loader/src/index.js\",\n                            \"meta\": [\n                                {\n                                    \"type\": \"builtin\",\n                                    \"name\": \"lasso-loader\",\n                                    \"target\": \"/node_modules/lasso-loader/src/index.js\"\n                                }\n                            ],\n                            \"clientPath\": \"/lasso-loader$x.x.x/src/index\"\n                        }\n                    }\n                ],\n                \"foundGlobals\": {},\n                \"asyncBlocks\": [\n                    {\n                        \"requires\": [\n                            {\n                                \"path\": \"./bar\",\n                                \"range\": [\n                                    57,\n                                    73\n                                ],\n                                \"argRange\": [\n                                    65,\n                                    72\n                                ],\n                                \"resolved\": {\n                                    \"path\": \"/test/autotests/dep-require/async/bar.js\",\n                                    \"meta\": [],\n                                    \"clientPath\": \"/autotest$0/bar\"\n                                }\n                            }\n                        ],\n                        \"dependencies\": [\n                            {\n                                \"type\": \"require\",\n                                \"path\": \"./bar\"\n                            }\n                        ],\n                        \"firstArgRange\": [\n                            30,\n                            96\n                        ],\n                        \"hasInlineDependencies\": false,\n                        \"hasFunctionBody\": true,\n                        \"name\": \"_HASH\"\n                    }\n                ],\n                \"lastModified\": -1,\n                \"allRequires\": [\n                    {\n                        \"path\": \"lasso-loader\",\n                        \"range\": [\n                            0,\n                            23\n                        ],\n                        \"argRange\": [\n                            8,\n                            22\n                        ],\n                        \"resolved\": {\n                            \"path\": \"/node_modules/lasso-loader/src/index.js\",\n                            \"meta\": [\n                                {\n                                    \"type\": \"builtin\",\n                                    \"name\": \"lasso-loader\",\n                                    \"target\": \"/node_modules/lasso-loader/src/index.js\"\n                                }\n                            ],\n                            \"clientPath\": \"/lasso-loader$x.x.x/src/index\"\n                        }\n                    },\n                    {\n                        \"path\": \"./bar\",\n                        \"range\": [\n                            57,\n                            73\n                        ],\n                        \"argRange\": [\n                            65,\n                            72\n                        ],\n                        \"resolved\": {\n                            \"path\": \"/test/autotests/dep-require/async/bar.js\",\n                            \"meta\": [],\n                            \"clientPath\": \"/autotest$0/bar\"\n                        }\n                    }\n                ]\n            },\n            \"asyncBlocks\": [\n                {\n                    \"requires\": [\n                        {\n                            \"path\": \"./bar\",\n                            \"range\": [\n                                57,\n                                73\n                            ],\n                            \"argRange\": [\n                                65,\n                                72\n                            ],\n                            \"resolved\": {\n                                \"path\": \"/test/autotests/dep-require/async/bar.js\",\n                                \"meta\": [],\n                                \"clientPath\": \"/autotest$0/bar\"\n                            }\n                        }\n                    ],\n                    \"dependencies\": [\n                        {\n                            \"type\": \"require\",\n                            \"path\": \"./bar\"\n                        }\n                    ],\n                    \"firstArgRange\": [\n                        30,\n                        96\n                    ],\n                    \"hasInlineDependencies\": false,\n                    \"hasFunctionBody\": true,\n                    \"name\": \"_HASH\"\n                }\n            ],\n            \"requireLastModified\": -1\n        }\n    ],\n    \"async\": {\n        \"_HASH\": [\n            {\n                \"type\": \"require\",\n                \"path\": \"./bar\"\n            }\n        ]\n    },\n    \"dirname\": \"/test/autotests/dep-require/async\",\n    \"filename\": \"/test/autotests/dep-require/async/foo.js\"\n}"
  },
  {
    "path": "test/autotests/dep-require/async/foo.js",
    "content": "require('lasso-loader').async(function() {\n    var bar = require('./bar');\n    bar.sayHello();\n});"
  },
  {
    "path": "test/autotests/dep-require/async/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/async/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/builtin/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-builtin\",\n        \"name\": \"path\",\n        \"target\": \"/path-browserify$1.0.1/index\",\n        \"_sourceFile\": \"/node_modules/path-browserify/index.js\"\n    },\n    {\n        \"type\": \"require\",\n        \"path\": \"path\",\n        \"from\": \"/test/autotests/dep-require/builtin\",\n        \"resolved\": {\n            \"path\": \"/node_modules/path-browserify/index.js\",\n            \"meta\": [\n                {\n                    \"type\": \"builtin\",\n                    \"name\": \"path\",\n                    \"target\": \"/node_modules/path-browserify/index.js\"\n                }\n            ],\n            \"clientPath\": \"/path-browserify$1.0.1/index\"\n        }\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/foo\",\n        \"file\": \"/test/autotests/dep-require/builtin/foo.js\",\n        \"inspected\": {\n            \"requires\": [\n                {\n                    \"path\": \"path\",\n                    \"range\": [\n                        11,\n                        26\n                    ],\n                    \"argRange\": [\n                        19,\n                        25\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/node_modules/path-browserify/index.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"builtin\",\n                                \"name\": \"path\",\n                                \"target\": \"/node_modules/path-browserify/index.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/path-browserify$1.0.1/index\"\n                    }\n                }\n            ],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": [\n                {\n                    \"path\": \"path\",\n                    \"range\": [\n                        11,\n                        26\n                    ],\n                    \"argRange\": [\n                        19,\n                        25\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/node_modules/path-browserify/index.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"builtin\",\n                                \"name\": \"path\",\n                                \"target\": \"/node_modules/path-browserify/index.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/path-browserify$1.0.1/index\"\n                    }\n                }\n            ]\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/builtin/foo.js",
    "content": "var path = require('path');\npath.join(__dirname, 'hello-world');"
  },
  {
    "path": "test/autotests/dep-require/builtin/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/builtin/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/globals-custom/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-installed\",\n        \"parentPath\": \"/autotest$0\",\n        \"childName\": \"foo\",\n        \"childVersion\": \"1.2.0\",\n        \"parentDir\": \"/test/autotests/dep-require/globals-custom\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/foo$1.2.0\",\n        \"main\": \"\",\n        \"_sourceFile\": \"/test/autotests/dep-require/globals-custom/node_modules/foo/index.js\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/foo$1.2.0/index\",\n        \"file\": \"/test/autotests/dep-require/globals-custom/node_modules/foo/index.js\",\n        \"globals\": [\n            \"FOO\"\n        ],\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/globals-custom/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/globals-custom/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: 'foo',\n        from: dirname\n    };\n};\n\nexports.getPluginConfig = function() {\n    var globals = {};\n    var fooPath = require.resolve('foo');\n    globals[fooPath] = ['FOO'];\n\n    return {\n        globals: globals\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/globals-jquery/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-installed\",\n        \"parentPath\": \"/autotest$0\",\n        \"childName\": \"jquery\",\n        \"childVersion\": \"1.2.0\",\n        \"parentDir\": \"/test/autotests/dep-require/globals-jquery\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/jquery$1.2.0\",\n        \"main\": \"\",\n        \"_sourceFile\": \"/test/autotests/dep-require/globals-jquery/node_modules/jquery/index.js\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/jquery$1.2.0/index\",\n        \"file\": \"/test/autotests/dep-require/globals-jquery/node_modules/jquery/index.js\",\n        \"globals\": [\n            \"$\",\n            \"jQuery\"\n        ],\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/globals-jquery/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/globals-jquery/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: 'jquery',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/main-custom/bar/bar.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-require/main-custom/bar/package.json",
    "content": "{\n    \"main\": \"bar.js\"\n}"
  },
  {
    "path": "test/autotests/dep-require/main-custom/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/autotest$0/bar\",\n        \"main\": \"bar\",\n        \"_sourceFile\": \"/test/autotests/dep-require/main-custom/bar/bar.js\"\n    },\n    {\n        \"type\": \"require\",\n        \"path\": \"./bar\",\n        \"from\": \"/test/autotests/dep-require/main-custom\",\n        \"resolved\": {\n            \"path\": \"/test/autotests/dep-require/main-custom/bar/bar.js\",\n            \"meta\": [\n                {\n                    \"type\": \"main\",\n                    \"dir\": \"/test/autotests/dep-require/main-custom/bar\",\n                    \"main\": \"/test/autotests/dep-require/main-custom/bar/bar.js\"\n                }\n            ],\n            \"clientPath\": \"/autotest$0/bar/bar\"\n        }\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/foo\",\n        \"file\": \"/test/autotests/dep-require/main-custom/foo.js\",\n        \"inspected\": {\n            \"requires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/main-custom/bar/bar.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"main\",\n                                \"dir\": \"/test/autotests/dep-require/main-custom/bar\",\n                                \"main\": \"/test/autotests/dep-require/main-custom/bar/bar.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/autotest$0/bar/bar\"\n                    }\n                }\n            ],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/main-custom/bar/bar.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"main\",\n                                \"dir\": \"/test/autotests/dep-require/main-custom/bar\",\n                                \"main\": \"/test/autotests/dep-require/main-custom/bar/bar.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/autotest$0/bar/bar\"\n                    }\n                }\n            ]\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/main-custom/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/autotests/dep-require/main-custom/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/main-custom/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/main-index/bar/index.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-require/main-index/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/autotest$0/bar\",\n        \"main\": \"\",\n        \"_sourceFile\": \"/test/autotests/dep-require/main-index/bar/index.js\"\n    },\n    {\n        \"type\": \"require\",\n        \"path\": \"./bar\",\n        \"from\": \"/test/autotests/dep-require/main-index\",\n        \"resolved\": {\n            \"path\": \"/test/autotests/dep-require/main-index/bar/index.js\",\n            \"meta\": [\n                {\n                    \"type\": \"main\",\n                    \"dir\": \"/test/autotests/dep-require/main-index/bar\",\n                    \"main\": \"/test/autotests/dep-require/main-index/bar/index.js\"\n                }\n            ],\n            \"clientPath\": \"/autotest$0/bar/index\"\n        }\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/foo\",\n        \"file\": \"/test/autotests/dep-require/main-index/foo.js\",\n        \"inspected\": {\n            \"requires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/main-index/bar/index.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"main\",\n                                \"dir\": \"/test/autotests/dep-require/main-index/bar\",\n                                \"main\": \"/test/autotests/dep-require/main-index/bar/index.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/autotest$0/bar/index\"\n                    }\n                }\n            ],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/main-index/bar/index.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"main\",\n                                \"dir\": \"/test/autotests/dep-require/main-index/bar\",\n                                \"main\": \"/test/autotests/dep-require/main-index/bar/index.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/autotest$0/bar/index\"\n                    }\n                }\n            ]\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/main-index/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/autotests/dep-require/main-index/module-no-dependencies/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/foo\",\n        \"file\": \"/test/fixtures/dep-require/autotest/module-no-dependencies/foo.js\",\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/main-index/module-no-dependencies/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/dep-require/main-index/module-no-dependencies/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/main-index/module-no-dependencies/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/main-index/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/main-index/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/main-require-redefined/bar/bar.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-require/main-require-redefined/bar/package.json",
    "content": "{\n    \"main\": \"bar.js\"\n}"
  },
  {
    "path": "test/autotests/dep-require/main-require-redefined/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/autotest$0/bar\",\n        \"main\": \"bar\",\n        \"_sourceFile\": \"/test/autotests/dep-require/main-require-redefined/bar/bar.js\"\n    },\n    {\n        \"type\": \"require\",\n        \"path\": \"./bar\",\n        \"from\": \"/test/autotests/dep-require/main-require-redefined\",\n        \"resolved\": {\n            \"path\": \"/test/autotests/dep-require/main-require-redefined/bar/bar.js\",\n            \"meta\": [\n                {\n                    \"type\": \"main\",\n                    \"dir\": \"/test/autotests/dep-require/main-require-redefined/bar\",\n                    \"main\": \"/test/autotests/dep-require/main-require-redefined/bar/bar.js\"\n                }\n            ],\n            \"clientPath\": \"/autotest$0/bar/bar\"\n        }\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/foo\",\n        \"file\": \"/test/autotests/dep-require/main-require-redefined/foo.js\",\n        \"inspected\": {\n            \"requires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/main-require-redefined/bar/bar.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"main\",\n                                \"dir\": \"/test/autotests/dep-require/main-require-redefined/bar\",\n                                \"main\": \"/test/autotests/dep-require/main-require-redefined/bar/bar.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/autotest$0/bar/bar\"\n                    }\n                }\n            ],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/main-require-redefined/bar/bar.js\",\n                        \"meta\": [\n                            {\n                                \"type\": \"main\",\n                                \"dir\": \"/test/autotests/dep-require/main-require-redefined/bar\",\n                                \"main\": \"/test/autotests/dep-require/main-require-redefined/bar/bar.js\"\n                            }\n                        ],\n                        \"clientPath\": \"/autotest$0/bar/bar\"\n                    }\n                }\n            ]\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/main-require-redefined/foo.js",
    "content": "require('./bar');\n(function() {\n    var require = function() {};\n    require('some-thing');\n}());"
  },
  {
    "path": "test/autotests/dep-require/main-require-redefined/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/main-require-redefined/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/remap-browser-override/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-remap\",\n        \"from\": \"/autotest$0/foo\",\n        \"to\": \"/autotest$0/foo-browser\",\n        \"fromFile\": \"/test/autotests/dep-require/remap-browser-override/foo.js\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/foo-browser\",\n        \"file\": \"/test/autotests/dep-require/remap-browser-override/foo-browser.js\",\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/remap-browser-override/foo-browser.js",
    "content": "console.log('foo-browser');"
  },
  {
    "path": "test/autotests/dep-require/remap-browser-override/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/dep-require/remap-browser-override/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"browser\": {\n        \"./foo.js\": \"./foo-browser.js\"\n    }\n}"
  },
  {
    "path": "test/autotests/dep-require/remap-browser-override/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/require-installed/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-installed\",\n        \"parentPath\": \"/autotest$0\",\n        \"childName\": \"installed-bar\",\n        \"childVersion\": \"1.2.0\",\n        \"parentDir\": \"/test/autotests/dep-require/require-installed\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/installed-bar$1.2.0\",\n        \"main\": \"\",\n        \"_sourceFile\": \"/test/autotests/dep-require/require-installed/node_modules/installed-bar/index.js\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/installed-bar$1.2.0/index\",\n        \"file\": \"/test/autotests/dep-require/require-installed/node_modules/installed-bar/index.js\",\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/require-installed/foo.js",
    "content": "require('installed-bar');"
  },
  {
    "path": "test/autotests/dep-require/require-installed/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/require-installed/test.js",
    "content": "var path = require('path');\n\nexports.createDependency = function(dirname) {\n    return {\n        path: 'installed-bar',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/require-installed-scoped/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-installed\",\n        \"parentPath\": \"/autotest$0\",\n        \"childName\": \"@foo/bar\",\n        \"childVersion\": \"1.0.0\",\n        \"parentDir\": \"/test/autotests/dep-require/require-installed-scoped\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/@foo/bar$1.0.0\",\n        \"main\": \"\",\n        \"_sourceFile\": \"/test/autotests/dep-require/require-installed-scoped/node_modules/@foo/bar/index.js\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/@foo/bar$1.0.0/index\",\n        \"file\": \"/test/autotests/dep-require/require-installed-scoped/node_modules/@foo/bar/index.js\",\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/require-installed-scoped/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/require-installed-scoped/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: '@foo/bar',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/require-search-path/app-modules/bar/index.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-require/require-search-path/app-modules/bar/package.json",
    "content": "{\n    \"name\": \"installed-bar\",\n    \"version\": \"1.2.0\"\n}"
  },
  {
    "path": "test/autotests/dep-require/require-search-path/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-search-path\",\n        \"path\": \"/require-search-path$0/app-modules/\"\n    },\n    {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/installed-bar$1.2.0\",\n        \"main\": \"\",\n        \"_sourceFile\": \"/test/autotests/dep-require/require-search-path/app-modules/bar/index.js\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/installed-bar$1.2.0/index\",\n        \"file\": \"/test/autotests/dep-require/require-search-path/app-modules/bar/index.js\",\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/require-search-path/package.json",
    "content": "{\n    \"name\": \"require-search-path\"\n}"
  },
  {
    "path": "test/autotests/dep-require/require-search-path/test.js",
    "content": "var path = require('path');\n\nexports.createDependency = function(dirname) {\n    return {\n        path: 'bar',\n        from: dirname\n    };\n};\n\nexports.searchPath = path.join(__dirname, 'app-modules');"
  },
  {
    "path": "test/autotests/dep-require/transitive/bar.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-require/transitive/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"require\",\n        \"path\": \"./bar\",\n        \"from\": \"/test/autotests/dep-require/transitive\",\n        \"resolved\": {\n            \"path\": \"/test/autotests/dep-require/transitive/bar.js\",\n            \"meta\": [],\n            \"clientPath\": \"/autotest$0/bar\"\n        }\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/foo\",\n        \"file\": \"/test/autotests/dep-require/transitive/foo.js\",\n        \"inspected\": {\n            \"requires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/transitive/bar.js\",\n                        \"meta\": [],\n                        \"clientPath\": \"/autotest$0/bar\"\n                    }\n                }\n            ],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": [\n                {\n                    \"path\": \"./bar\",\n                    \"range\": [\n                        0,\n                        16\n                    ],\n                    \"argRange\": [\n                        8,\n                        15\n                    ],\n                    \"resolved\": {\n                        \"path\": \"/test/autotests/dep-require/transitive/bar.js\",\n                        \"meta\": [],\n                        \"clientPath\": \"/autotest$0/bar\"\n                    }\n                }\n            ]\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/transitive/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/autotests/dep-require/transitive/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/transitive/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/transitive-resolved/bar.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-require/transitive-resolved/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/autotest$0/bar\",\n        \"file\": \"/test/autotests/dep-require/transitive-resolved/bar.js\",\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/transitive-resolved/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/autotests/dep-require/transitive-resolved/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/transitive-resolved/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: require.resolve('./bar.js'),\n        from: __dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-require/virtual-module/expected.json",
    "content": "[\n    {\n        \"type\": \"commonjs-runtime\"\n    },\n    {\n        \"type\": \"commonjs-ready\",\n        \"inline\": \"end\"\n    },\n    {\n        \"type\": \"commonjs-def\",\n        \"path\": \"/virtual-module/something.foo\",\n        \"file\": \"/test/autotests/dep-require/virtual-module/something.foo\",\n        \"inspected\": {\n            \"requires\": [],\n            \"foundGlobals\": {},\n            \"asyncBlocks\": [],\n            \"lastModified\": -1,\n            \"allRequires\": []\n        },\n        \"requireLastModified\": -1\n    }\n]"
  },
  {
    "path": "test/autotests/dep-require/virtual-module/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-require/virtual-module/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        virtualModule: {\n            path: __dirname + '/something.foo',\n            clientPath: '/virtual-module/something.foo',\n            read(lassoContext, callback) {\n                setTimeout(function() {\n                    callback(null, 'exports.hello = \"world\"; exports.filename = __filename;');\n                }, 10);\n            }\n        }\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/async/bar.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-transport-define/async/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { require('/lasso-loader$x.x.x/src/index'/*'lasso-loader'*/).async(\"_HASH\", function() {\n    var bar = require('/autotest$0/bar'/*'./bar'*/);\n    bar.sayHello();\n});\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/async/foo.js",
    "content": "require('lasso-loader').async(function() {\n    var bar = require('./bar');\n    bar.sayHello();\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/async/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/async/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/builtin/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { var path = require('/path-browserify$1.0.1/index'/*'path'*/);\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/builtin/foo.js",
    "content": "var path = require('path');"
  },
  {
    "path": "test/autotests/dep-transport-define/builtin/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/builtin/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/globals-foo/expected.js",
    "content": "$_mod.def(\"/foo$1.0.0/index\", function(require, exports, module, __filename, __dirname) { module.exports = function Foo() {};\n},{\"globals\":[\"FOO\"]});"
  },
  {
    "path": "test/autotests/dep-transport-define/globals-foo/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/globals-foo/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: 'foo',\n        from: dirname\n    };\n};\n\nexports.getPluginConfig = function() {\n    var globals = {};\n    var fooPath = require.resolve('foo');\n    globals[fooPath] = ['FOO'];\n\n    return {\n        globals: globals\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/globals-jquery/expected.js",
    "content": "$_mod.def(\"/jquery$1.2.0/index\", function(require, exports, module, __filename, __dirname) { module.exports = function jQuery() {};\n},{\"globals\":[\"$\",\"jQuery\"]});"
  },
  {
    "path": "test/autotests/dep-transport-define/globals-jquery/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/globals-jquery/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: 'jquery',\n        from: dirname\n    };\n};\n\nexports.getPluginConfig = function() {\n    var globals = {};\n\n    return {\n        globals: globals\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/main-custom/bar/bar.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-transport-define/main-custom/bar/package.json",
    "content": "{\n    \"main\": \"bar.js\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/main-custom/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { require('/autotest$0/bar/bar'/*'./bar'*/);\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/main-custom/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/main-custom/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/main-custom/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/main-index/bar/index.js",
    "content": ""
  },
  {
    "path": "test/autotests/dep-transport-define/main-index/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { require('/autotest$0/bar/index'/*'./bar'*/);\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/main-index/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/main-index/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/main-index/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/module-no-dependencies/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { console.log('foo');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/module-no-dependencies/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/dep-transport-define/module-no-dependencies/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/module-no-dependencies/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/remap-void/bar.js",
    "content": "console.log('server only');"
  },
  {
    "path": "test/autotests/dep-transport-define/remap-void/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { var bar = ({})/*require('./bar')*/;\nbar = ({})/*require('./bar')*/;\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/remap-void/foo.js",
    "content": "var bar = require('./bar');\nbar = require('./bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/remap-void/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"browser\": {\n        \"./bar.js\": false\n    }\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/remap-void/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/require-installed/expected.js",
    "content": "$_mod.def(\"/installed-bar$1.2.0/index\", function(require, exports, module, __filename, __dirname) { console.log('installed-bar');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/require-installed/foo.js",
    "content": "require('installed-bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/require-installed/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/require-installed/test.js",
    "content": "var path = require('path');\n\nexports.createDependency = function(dirname) {\n    return {\n        path: 'installed-bar',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/require-installed-scoped/expected.js",
    "content": "$_mod.def(\"/@foo/bar$1.0.0/index\", function(require, exports, module, __filename, __dirname) { console.log('@foo/bar');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/require-installed-scoped/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/require-installed-scoped/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: '@foo/bar',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/require-search-path/app-modules/bar/index.js",
    "content": "console.log('app-modules/bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/require-search-path/app-modules/bar/package.json",
    "content": "{\n    \"name\": \"bar\",\n    \"version\": \"1.2.0\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/require-search-path/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { var bar = require('/bar$1.2.0/index'/*'bar'*/);\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/require-search-path/foo.js",
    "content": "var bar = require('bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/require-search-path/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/require-search-path/test.js",
    "content": "var path = require('path');\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './foo'\n    };\n};\n\nexports.searchPath = path.join(__dirname, 'app-modules');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('hello');|my-transform|file=/bar.js\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify/my-transform.js",
    "content": "'use strict';\n\nvar stream = require('stream');\n\nclass MyTransform extends stream.Transform {\n    constructor(file) {\n        super();\n        this.file = file;\n        this.data = '';\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        this.push(this.data + '|my-transform|file=' + this.file);\n        callback();\n    }\n}\n\nmodule.exports = function(file) {\n    return new MyTransform(file);\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            require('./my-transform')\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify-config/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify-config/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('WORLD');|filename=/bar.js\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify-config/my-transform.js",
    "content": "'use strict';\n\nvar stream = require('stream');\n\nclass MyTransform extends stream.Transform {\n    constructor(file, opts) {\n        super();\n        this.file = file;\n        this.data = '';\n        this.replacement = opts.replacement;\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        var replacement = this.replacement;\n        this.push(this.data.replace(/hello/g, replacement) + '|filename=' + this.file);\n        callback();\n    }\n}\n\nmodule.exports = function(file, opts) {\n    return new MyTransform(file, opts);\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify-config/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-browserify-config/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            {\n                transform: require('./my-transform'),\n                config: {\n                    replacement: 'WORLD'\n                }\n            }\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-multiple/bar.js",
    "content": "console.log('hello world foo bar baz');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-multiple/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('HELLO WORLD FOO bar baz');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-multiple/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-multiple/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            require('./transform-a'),\n            {\n                transform: require('./transform-b')\n            },\n            {\n                transform: require('./transform-c'),\n                config: {\n                    replacement: 'FOO'\n                }\n            }\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-multiple/transform-a.js",
    "content": "'use strict';\n\nvar expect = require('chai').expect;\nvar stream = require('stream');\n\nclass MyTransform extends stream.Transform {\n    constructor(file) {\n        super();\n        this.file = file;\n        this.data = '';\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        this.push(this.data.replace(/hello/g, 'HELLO'));\n        callback();\n    }\n}\n\nmodule.exports = {\n    id: __filename,\n    stream: true,\n    createTransform() {\n        return function myTransform(file, lassoContext) {\n            expect(lassoContext.isMockLassoContext).to.equal(true);\n            return new MyTransform(file);\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-multiple/transform-b.js",
    "content": "'use strict';\n\nvar stream = require('stream');\n\nclass MyTransform extends stream.Transform {\n    constructor(file) {\n        super();\n        this.file = file;\n        this.data = '';\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        this.push(this.data.replace(/world/g, 'WORLD'));\n        callback();\n    }\n}\n\nmodule.exports = function(file) {\n    return new MyTransform(file);\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-multiple/transform-c.js",
    "content": "module.exports = {\n    id: __filename,\n    stream: false,\n    createTransform(transformConfig) {\n        return function myTransform(code, lassoContext) {\n            return code.replace(/foo/g, transformConfig.replacement);\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-promise/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-promise/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('HELLO');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-promise/my-transform.js",
    "content": "module.exports = {\n    id: __filename,\n    stream: false,\n    createTransform(transformConfig) {\n        return function myTransform(code, lassoContext) {\n            return new Promise(function(resolve, reject) {\n                setTimeout(function() {\n                    resolve(code.replace(/hello/g, 'HELLO'));\n                }, 10);\n            });\n\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-promise/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-promise/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            require('./my-transform')\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('WORLD');|filename=/bar.js\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream/my-transform.js",
    "content": "'use strict';\n\nvar expect = require('chai').expect;\nvar stream = require('stream');\n\nclass MyTransform extends stream.Transform {\n    constructor(file) {\n        super();\n        this.file = file;\n        this.data = '';\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        this.push(this.data.replace(/hello/g, 'WORLD') + '|filename=' + this.file);\n        callback();\n    }\n}\n\nmodule.exports = {\n    id: __filename,\n    stream: true,\n    createTransform() {\n        return function myTransform(file, lassoContext) {\n            expect(lassoContext.isMockLassoContext).to.equal(true);\n            return new MyTransform(file);\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            require('./my-transform')\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-config/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-config/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('WORLD');|filename=/bar.js\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-config/my-transform.js",
    "content": "'use strict';\n\nvar expect = require('chai').expect;\nvar stream = require('stream');\n\nclass MyTransform extends stream.Transform {\n    constructor(file, opts) {\n        super();\n        this.file = file;\n        this.data = '';\n        this.replacement = opts.replacement;\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        var replacement = this.replacement;\n        this.push(this.data.replace(/hello/g, replacement) + '|filename=' + this.file);\n        callback();\n    }\n}\n\nmodule.exports = {\n    id: __filename,\n    stream: true,\n    createTransform(transformConfig) {\n        return function myTransform(file, lassoContext) {\n            expect(lassoContext.isMockLassoContext).to.equal(true);\n            return new MyTransform(file, transformConfig);\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-config/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-config/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            {\n                transform: require('./my-transform'),\n                config: {\n                    replacement: 'WORLD'\n                }\n            }\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-no-config/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-no-config/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('WORLD');|filename=/bar.js\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-no-config/my-transform.js",
    "content": "'use strict';\n\nvar expect = require('chai').expect;\nvar stream = require('stream');\n\nclass MyTransform extends stream.Transform {\n    constructor(file) {\n        super();\n        this.file = file;\n        this.data = '';\n    }\n\n    _transform(buf, enc, callback) {\n        // Collect all of the data as it is streamed in and just concatenate to a our data string\n        // but don't actually stream out any data yet\n        this.data += buf;\n        callback();\n    }\n\n    _flush(callback) {\n        this.push(this.data.replace(/hello/g, 'WORLD') + '|filename=' + this.file);\n        callback();\n    }\n}\n\nmodule.exports = {\n    id: __filename,\n    stream: true,\n    createTransform() {\n        return function myTransform(file, lassoContext) {\n            expect(lassoContext.isMockLassoContext).to.equal(true);\n            return new MyTransform(file);\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-no-config/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-stream-no-config/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            {\n                transform: require('./my-transform')\n            }\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('HELLO');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous/my-transform.js",
    "content": "module.exports = {\n    id: __filename,\n    stream: false,\n    createTransform(transformConfig) {\n        return function myTransform(code, lassoContext) {\n            return code.replace(/hello/g, 'HELLO');\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            require('./my-transform')\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous-config/bar.js",
    "content": "console.log('hello');"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous-config/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('WORLD');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous-config/my-transform.js",
    "content": "module.exports = {\n    id: __filename,\n    stream: false,\n    createTransform(transformConfig) {\n        return function myTransform(code, lassoContext) {\n            return code.replace(/hello/g, transformConfig.replacement);\n        };\n    }\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous-config/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transform-synchronous-config/test.js",
    "content": "exports.getPluginConfig = function() {\n    return {\n        transforms: [\n            {\n                transform: require('./my-transform'),\n                config: {\n                    replacement: 'WORLD'\n                }\n            }\n        ]\n    };\n};\n\nexports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive/bar.js",
    "content": "$_mod.def(\"/foo\", function(require, exports, module, __filename, __dirname) { require('/bar'/*'./bar'*/);\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive/expected.js",
    "content": "$_mod.def(\"/autotest$0/foo\", function(require, exports, module, __filename, __dirname) { require('/autotest$0/bar'/*'./bar'*/);\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: './foo',\n        from: dirname\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive-resolved/bar.js",
    "content": "console.log('bar');"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive-resolved/expected.js",
    "content": "$_mod.def(\"/autotest$0/bar\", function(require, exports, module, __filename, __dirname) { console.log('bar');\n});"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive-resolved/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-define/transitive-resolved/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        from: dirname,\n        path: './bar'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-installed/simple/expected.js",
    "content": "$_mod.installed(\"test/fixtures/dep-require/autotest/require-installed\", \"installed-bar\", \"1.2.0\");"
  },
  {
    "path": "test/autotests/dep-transport-installed/simple/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-installed/simple/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        \"parentPath\": \"/test/fixtures/dep-require/autotest/require-installed\",\n        \"childName\": \"installed-bar\",\n        \"childVersion\": \"1.2.0\"\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-main/simple/expected.js",
    "content": "$_mod.main(\"/test/fixtures/dep-require/autotest/main-index/bar\", \"\");"
  },
  {
    "path": "test/autotests/dep-transport-main/simple/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-main/simple/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        \"type\": \"commonjs-main\",\n        \"dir\": \"/test/fixtures/dep-require/autotest/main-index/bar\",\n        \"main\": \"\"\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-ready/simple/expected.js",
    "content": "$_mod.ready();"
  },
  {
    "path": "test/autotests/dep-transport-ready/simple/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-ready/simple/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {};\n};"
  },
  {
    "path": "test/autotests/dep-transport-remap/simple/expected.js",
    "content": "$_mod.remap(\"/foo\", \"/foo-browser\");"
  },
  {
    "path": "test/autotests/dep-transport-remap/simple/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-remap/simple/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        from: '/foo',\n        to: '/foo-browser'\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-run/no-wait/expected.js",
    "content": "$_mod.run(\"/foo\",{\"wait\":false});"
  },
  {
    "path": "test/autotests/dep-transport-run/no-wait/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-run/no-wait/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: '/foo',\n        wait: false\n    };\n};"
  },
  {
    "path": "test/autotests/dep-transport-run/wait/expected.js",
    "content": "$_mod.run(\"/foo\");"
  },
  {
    "path": "test/autotests/dep-transport-run/wait/package.json",
    "content": "{\n    \"name\": \"autotest\"\n}"
  },
  {
    "path": "test/autotests/dep-transport-run/wait/test.js",
    "content": "exports.createDependency = function(dirname) {\n    return {\n        path: '/foo',\n        wait: true\n    };\n};"
  },
  {
    "path": "test/autotests/dependency-walker/flat/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/dependency-walker/flat/expected.txt",
    "content": "[package: path=\"/browser.json\"]\n  + [js: path=\"/foo.js\"]"
  },
  {
    "path": "test/autotests/dependency-walker/flat/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/dependency-walker/flat/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/dependency-walker/flat/test.js",
    "content": "\nexports.getDependencies = function(dir) {\n    return [\n        dir + '/browser.json'\n    ];\n};"
  },
  {
    "path": "test/autotests/dependency-walker/globs/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"style/*.css\",\n        \"require: require/*.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/dependency-walker/globs/expected.txt",
    "content": "[package: path=\"/browser.json\"]\n  + [css: path=\"/style/style1.css\"]\n  + [css: path=\"/style/style2.css\"]\n  [require: /require/bar.js]\n    + [commonjs-runtime]\n    + [commonjs-ready: inline=\"end\"]\n    + [commonjs-def: path=\"/autotest$1.0.0/require/bar\"]\n  [require: /require/foo.js]\n    + [commonjs-def: path=\"/autotest$1.0.0/require/foo\"]"
  },
  {
    "path": "test/autotests/dependency-walker/globs/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/dependency-walker/globs/require/bar.js",
    "content": "module.exports=\"BAR\";"
  },
  {
    "path": "test/autotests/dependency-walker/globs/require/foo.js",
    "content": "module.exports=\"FOO\";"
  },
  {
    "path": "test/autotests/dependency-walker/globs/style/style1.css",
    "content": ".style1 {}"
  },
  {
    "path": "test/autotests/dependency-walker/globs/style/style2.css",
    "content": ".style2 {}"
  },
  {
    "path": "test/autotests/dependency-walker/globs/test.js",
    "content": "\nexports.getDependencies = function(dir) {\n    return [\n        dir + '/browser.json'\n    ];\n};"
  },
  {
    "path": "test/autotests/dependency-walker/lasso-issue-136/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"if-flag\": \"foo\",\n            \"dependencies\": [\n                \"./common.js\",\n                { \"path\": \"./foo1.js\" }\n            ]\n        },\n        {\n            \"if-flag\": \"foo\",\n            \"dependencies\": [\n                \"./common.js\",\n                { \"path\": \"./foo2.js\" }\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/dependency-walker/lasso-issue-136/common.js",
    "content": "console.log('common');"
  },
  {
    "path": "test/autotests/dependency-walker/lasso-issue-136/expected.txt",
    "content": "[package: path=\"/browser.json\"]\n  [dependencies: if-flag=\"foo\", dependencies=[\"./common.js\",{\"path\":\"./foo1.js\"}]]\n    + [js: path=\"/common.js\"]\n    + [js: path=\"/foo1.js\"]\n  [dependencies: if-flag=\"foo\", dependencies=[\"./common.js\",{\"path\":\"./foo2.js\"}]]\n    + [js: path=\"/foo2.js\"]"
  },
  {
    "path": "test/autotests/dependency-walker/lasso-issue-136/foo1.js",
    "content": "console.log('foo1');"
  },
  {
    "path": "test/autotests/dependency-walker/lasso-issue-136/foo2.js",
    "content": "console.log('foo2');"
  },
  {
    "path": "test/autotests/dependency-walker/lasso-issue-136/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/dependency-walker/lasso-issue-136/test.js",
    "content": "exports.getFlags = function() {\n    return ['foo'];\n};\n\nexports.getDependencies = function(dir) {\n    return [\n        dir + '/browser.json'\n    ];\n};"
  },
  {
    "path": "test/autotests/dependency-walker/require/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./foo\"\n    ]\n}"
  },
  {
    "path": "test/autotests/dependency-walker/require/expected.txt",
    "content": "[package: path=\"/browser.json\"]\n  [require: ./foo]\n    + [commonjs-runtime]\n    + [commonjs-ready: inline=\"end\"]\n    + [commonjs-main: dir=\"/autotest$1.0.0/nested\", main=\"\"]\n    [require: ./nested]\n      + [commonjs-def: path=\"/autotest$1.0.0/nested/index\"]\n    + [commonjs-def: path=\"/autotest$1.0.0/foo\"]"
  },
  {
    "path": "test/autotests/dependency-walker/require/foo.js",
    "content": "require('./nested');"
  },
  {
    "path": "test/autotests/dependency-walker/require/nested/index.js",
    "content": "console.log('nested');"
  },
  {
    "path": "test/autotests/dependency-walker/require/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/dependency-walker/require/test.js",
    "content": "\nexports.getDependencies = function(dir) {\n    return [\n        dir + '/browser.json'\n    ];\n};"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./foo\",\n        \"./hello.js\",\n        \"./hello.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/expected.txt",
    "content": "[package: path=\"/browser.json\"]\n  [require: ./foo]\n    + [commonjs-runtime]\n    + [commonjs-ready: inline=\"end\"]\n    + [commonjs-main: dir=\"/autotest$1.0.0/nested\", main=\"\"]\n    [require: ./nested]\n      + [commonjs-def: path=\"/autotest$1.0.0/nested/index\"]\n    + [commonjs-def: path=\"/autotest$1.0.0/foo\"]\n  + [js: path=\"/hello.js\"]\n  + [css: path=\"/hello.css\"]"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/foo.js",
    "content": "require('./nested');"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/hello.css",
    "content": ".hello {\n    font-weight: bold;\n}"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/hello.js",
    "content": "console.log('Hello World');"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/nested/index.js",
    "content": "console.log('nested');"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/dependency-walker/require-mixed/test.js",
    "content": "\nexports.getDependencies = function(dir) {\n    return [\n        dir + '/browser.json'\n    ];\n};"
  },
  {
    "path": "test/autotests/dependency-walker/transitive-package/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\",\n        \"./nested/browser.json\"\n    ]\n}"
  },
  {
    "path": "test/autotests/dependency-walker/transitive-package/expected.txt",
    "content": "[package: path=\"/browser.json\"]\n  + [js: path=\"/foo.js\"]\n  [package: path=\"/nested/browser.json\"]\n    + [js: path=\"/nested/bar.js\"]"
  },
  {
    "path": "test/autotests/dependency-walker/transitive-package/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/dependency-walker/transitive-package/nested/bar.js",
    "content": "console.log('bar');"
  },
  {
    "path": "test/autotests/dependency-walker/transitive-package/nested/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./bar.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/dependency-walker/transitive-package/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/dependency-walker/transitive-package/test.js",
    "content": "\nexports.getDependencies = function(dir) {\n    return [\n        dir + '/browser.json'\n    ];\n};"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"js\", \"path\": \"./a.js\",\n            \"if-flag\": \"a\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./b.js\",\n            \"if-flag\": \"b\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./c.js\"\n        },\n        {\n            \"if-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./mobile-a.js\",\n                \"./mobile-b.js\"\n            ]\n        },\n        {\n            \"if-not-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./desktop-a.js\",\n                \"./desktop-b.js\"\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/desktop-a.js",
    "content": "desktop_a"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/desktop-b.js",
    "content": "desktop_b"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/mobile-a.js",
    "content": "mobile_a"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/mobile-b.js",
    "content": "mobile_b"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/flags/bundling-enabled/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        flags: ['a'],\n        bundlingEnabled: true,\n        bundles: [\n            {\n                name: 'foo',\n                dependencies: [\n                    './browser.json'\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var firstFile = lassoPageResult.getJavaScriptFiles()[0];\n    expect(writerTracker.getCodeForPath(firstFile)).to.equal('a=true;\\nc=true;');\n};"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"js\", \"path\": \"./a.js\",\n            \"if-flag\": \"a\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./b.js\",\n            \"if-flag\": \"b\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./c.js\"\n        },\n        {\n            \"if-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./mobile-a.js\",\n                \"./mobile-b.js\"\n            ]\n        },\n        {\n            \"if-not-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./desktop-a.js\",\n                \"./desktop-b.js\"\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/desktop-a.js",
    "content": "desktop_a"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/desktop-b.js",
    "content": "desktop_b"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/mobile-a.js",
    "content": "mobile_a"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/mobile-b.js",
    "content": "mobile_b"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/flags/if-flag-dependencies/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        flags: ['mobile'],\n        bundlingEnabled: false\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    expect(writerTracker.getOutputFilenames()).to.deep.equal([\n        // a.js only included if \"a\" flag is enabled\n        //'a.js',\n\n        /* NOTE: b.js should not be included because it requires flag \"b\" */\n        // 'a.js'\n\n        // c.js is always included (not conditional)\n        'c.js',\n        'mobile-a.js',\n        'mobile-b.js'\n    ]);\n\n    expect(writerTracker.getCodeForFilename('c.js')).to.equal('c=true;');\n    expect(writerTracker.getCodeForFilename('mobile-a.js')).to.equal('mobile_a');\n    expect(writerTracker.getCodeForFilename('mobile-b.js')).to.equal('mobile_b');\n};"
  },
  {
    "path": "test/autotests/flags/if-not-flag/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/flags/if-not-flag/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/flags/if-not-flag/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"js\", \"path\": \"./a.js\",\n            \"if-flag\": \"a\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./b.js\",\n            \"if-flag\": \"b\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./c.js\"\n        },\n        {\n            \"if-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./mobile-a.js\",\n                \"./mobile-b.js\"\n            ]\n        },\n        {\n            \"if-not-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./desktop-a.js\",\n                \"./desktop-b.js\"\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/flags/if-not-flag/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/flags/if-not-flag/desktop-a.js",
    "content": "desktop_a"
  },
  {
    "path": "test/autotests/flags/if-not-flag/desktop-b.js",
    "content": "desktop_b"
  },
  {
    "path": "test/autotests/flags/if-not-flag/mobile-a.js",
    "content": "mobile_a"
  },
  {
    "path": "test/autotests/flags/if-not-flag/mobile-b.js",
    "content": "mobile_b"
  },
  {
    "path": "test/autotests/flags/if-not-flag/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/flags/if-not-flag/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        flags: ['a'],\n        bundlingEnabled: false\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            {'type': 'js', 'path': './a.js', 'if-flag': 'a'},\n            {'type': 'js', 'path': './b.js', 'if-not-flag': 'a'}\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    expect(writerTracker.getOutputFilenames()).to.deep.equal([\n        // a.js only included if \"a\" flag is enabled\n        'a.js',\n\n        /* NOTE: b.js should not be included because it will only be included if \"a\" flag is not enabled */\n        // 'b.js'\n    ]);\n\n    expect(writerTracker.getCodeForFilename('a.js')).to.equal('a=true;');\n    expect(writerTracker.getCodeForFilename('b.js')).to.equal(undefined);\n};"
  },
  {
    "path": "test/autotests/flags/long-flags/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/flags/long-flags/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"js\", \"path\": \"./a.js\",\n            \"if-flag\": \"a\"\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/flags/long-flags/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/flags/long-flags/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        flags: [\n            'a',\n            'jldksjflksajdflsakjflskadfjkjdsafhksdjfhkfdgd',\n            'dfsgsgsgsdfgdsgfdgssdfgadfjkjdsafhksdjfhkdjsf',\n            'qwfddfdgsfdklkkfdgssdfgadfjkjdsafhkfdgdsgdsdd',\n            'uytursgsgsgsdfgdsgfdiusaiuvuefvdsbgoinkdcnoia',\n            'xnioenoiwihfuaevfsmoaeuavrhgbdjsnkmkmoieyabsb',\n            'sopoiresjhvdgasmasofniewrubyadfknjankndsfkjnk',\n            'hhabebherbsjbndkjserwoijwnbhewrfuwherfuewfknd'\n        ],\n        bundlingEnabled: false\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    // if we made it here, all is good.\n};"
  },
  {
    "path": "test/autotests/flags/simple/a.js",
    "content": "a=true;"
  },
  {
    "path": "test/autotests/flags/simple/b.js",
    "content": "b=true;"
  },
  {
    "path": "test/autotests/flags/simple/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"js\", \"path\": \"./a.js\",\n            \"if-flag\": \"a\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./b.js\",\n            \"if-flag\": \"b\"\n        },\n        {\n            \"type\": \"js\", \"path\": \"./c.js\"\n        },\n        {\n            \"if-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./mobile-a.js\",\n                \"./mobile-b.js\"\n            ]\n        },\n        {\n            \"if-not-flag\": \"mobile\",\n            \"dependencies\": [\n                \"./desktop-a.js\",\n                \"./desktop-b.js\"\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/flags/simple/c.js",
    "content": "c=true;"
  },
  {
    "path": "test/autotests/flags/simple/desktop-a.js",
    "content": "desktop_a"
  },
  {
    "path": "test/autotests/flags/simple/desktop-b.js",
    "content": "desktop_b"
  },
  {
    "path": "test/autotests/flags/simple/mobile-a.js",
    "content": "mobile_a"
  },
  {
    "path": "test/autotests/flags/simple/mobile-b.js",
    "content": "mobile_b"
  },
  {
    "path": "test/autotests/flags/simple/package.json",
    "content": "{\n    \"name\": \"test-bundling-project\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/flags/simple/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        flags: ['a'],\n        bundlingEnabled: false\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    expect(writerTracker.getOutputFilenames()).to.deep.equal([\n        // a.js only included if \"a\" flag is enabled\n        'a.js',\n\n        /* NOTE: b.js should not be included because it requires flag \"b\" */\n        // 'a.js'\n\n        // c.js is always included (not conditional)\n        'c.js',\n        'desktop-a.js',\n        'desktop-b.js'\n    ]);\n\n    expect(writerTracker.getCodeForFilename('a.js')).to.equal('a=true;');\n    expect(writerTracker.getCodeForFilename('c.js')).to.equal('c=true;');\n    expect(writerTracker.getCodeForFilename('desktop-a.js')).to.equal('desktop_a');\n    expect(writerTracker.getCodeForFilename('desktop-b.js')).to.equal('desktop_b');\n};"
  },
  {
    "path": "test/autotests/inspect/buffer/expected.json",
    "content": "{\n    \"requires\": [\n        {\n            \"path\": \"base64-js\",\n            \"range\": [\n                211,\n                231\n            ],\n            \"argRange\": [\n                219,\n                230\n            ]\n        },\n        {\n            \"path\": \"ieee754\",\n            \"range\": [\n                246,\n                264\n            ],\n            \"argRange\": [\n                254,\n                263\n            ]\n        },\n        {\n            \"path\": \"isarray\",\n            \"range\": [\n                279,\n                297\n            ],\n            \"argRange\": [\n                287,\n                296\n            ]\n        }\n    ],\n    \"foundGlobals\": {\n        \"global\": true,\n        \"undefined\": true,\n        \"Uint8Array\": true,\n        \"e\": true,\n        \"TypeError\": true,\n        \"ArrayBuffer\": true,\n        \"Symbol\": true,\n        \"Object\": true,\n        \"RangeError\": true,\n        \"Math\": true,\n        \"String\": true,\n        \"Infinity\": true,\n        \"Number\": true,\n        \"Error\": true,\n        \"parseInt\": true,\n        \"isNaN\": true,\n        \"isFinite\": true,\n        \"Array\": true\n    },\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/buffer/input.js",
    "content": "/*!\n * The buffer module from node.js, for the browser.\n *\n * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>\n * @license  MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\nBuffer.poolSize = 8192 // not used by this implementation\n\nvar rootParent = {}\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n *   === true    Use Uint8Array implementation (fastest)\n *   === false   Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n *     incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n  ? global.TYPED_ARRAY_SUPPORT\n  : typedArraySupport()\n\nfunction typedArraySupport () {\n  try {\n    var arr = new Uint8Array(1)\n    arr.foo = function () { return 42 }\n    return arr.foo() === 42 && // typed array instances can be augmented\n        typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n        arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n  } catch (e) {\n    return false\n  }\n}\n\nfunction kMaxLength () {\n  return Buffer.TYPED_ARRAY_SUPPORT\n    ? 0x7fffffff\n    : 0x3fffffff\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\nfunction Buffer (arg) {\n  if (!(this instanceof Buffer)) {\n    // Avoid going through an ArgumentsAdaptorTrampoline in the common case.\n    if (arguments.length > 1) return new Buffer(arg, arguments[1])\n    return new Buffer(arg)\n  }\n\n  if (!Buffer.TYPED_ARRAY_SUPPORT) {\n    this.length = 0\n    this.parent = undefined\n  }\n\n  // Common case.\n  if (typeof arg === 'number') {\n    return fromNumber(this, arg)\n  }\n\n  // Slightly less common case.\n  if (typeof arg === 'string') {\n    return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')\n  }\n\n  // Unusual.\n  return fromObject(this, arg)\n}\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n  arr.__proto__ = Buffer.prototype\n  return arr\n}\n\nfunction fromNumber (that, length) {\n  that = allocate(that, length < 0 ? 0 : checked(length) | 0)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) {\n    for (var i = 0; i < length; i++) {\n      that[i] = 0\n    }\n  }\n  return that\n}\n\nfunction fromString (that, string, encoding) {\n  if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'\n\n  // Assumption: byteLength() return value is always < kMaxLength.\n  var length = byteLength(string, encoding) | 0\n  that = allocate(that, length)\n\n  that.write(string, encoding)\n  return that\n}\n\nfunction fromObject (that, object) {\n  if (Buffer.isBuffer(object)) return fromBuffer(that, object)\n\n  if (isArray(object)) return fromArray(that, object)\n\n  if (object == null) {\n    throw new TypeError('must start with number, buffer, array or string')\n  }\n\n  if (typeof ArrayBuffer !== 'undefined') {\n    if (object.buffer instanceof ArrayBuffer) {\n      return fromTypedArray(that, object)\n    }\n    if (object instanceof ArrayBuffer) {\n      return fromArrayBuffer(that, object)\n    }\n  }\n\n  if (object.length) return fromArrayLike(that, object)\n\n  return fromJsonObject(that, object)\n}\n\nfunction fromBuffer (that, buffer) {\n  var length = checked(buffer.length) | 0\n  that = allocate(that, length)\n  buffer.copy(that, 0, 0, length)\n  return that\n}\n\nfunction fromArray (that, array) {\n  var length = checked(array.length) | 0\n  that = allocate(that, length)\n  for (var i = 0; i < length; i += 1) {\n    that[i] = array[i] & 255\n  }\n  return that\n}\n\n// Duplicate of fromArray() to keep fromArray() monomorphic.\nfunction fromTypedArray (that, array) {\n  var length = checked(array.length) | 0\n  that = allocate(that, length)\n  // Truncating the elements is probably not what people expect from typed\n  // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior\n  // of the old Buffer constructor.\n  for (var i = 0; i < length; i += 1) {\n    that[i] = array[i] & 255\n  }\n  return that\n}\n\nfunction fromArrayBuffer (that, array) {\n  array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = new Uint8Array(array)\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    that = fromTypedArray(that, new Uint8Array(array))\n  }\n  return that\n}\n\nfunction fromArrayLike (that, array) {\n  var length = checked(array.length) | 0\n  that = allocate(that, length)\n  for (var i = 0; i < length; i += 1) {\n    that[i] = array[i] & 255\n  }\n  return that\n}\n\n// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.\n// Returns a zero-length buffer for inputs that don't conform to the spec.\nfunction fromJsonObject (that, object) {\n  var array\n  var length = 0\n\n  if (object.type === 'Buffer' && isArray(object.data)) {\n    array = object.data\n    length = checked(array.length) | 0\n  }\n  that = allocate(that, length)\n\n  for (var i = 0; i < length; i += 1) {\n    that[i] = array[i] & 255\n  }\n  return that\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n  Buffer.prototype.__proto__ = Uint8Array.prototype\n  Buffer.__proto__ = Uint8Array\n  if (typeof Symbol !== 'undefined' && Symbol.species &&\n      Buffer[Symbol.species] === Buffer) {\n    // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n    Object.defineProperty(Buffer, Symbol.species, {\n      value: null,\n      configurable: true\n    })\n  }\n} else {\n  // pre-set for values that may exist in the future\n  Buffer.prototype.length = undefined\n  Buffer.prototype.parent = undefined\n}\n\nfunction allocate (that, length) {\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    // Return an augmented `Uint8Array` instance, for best performance\n    that = new Uint8Array(length)\n    that.__proto__ = Buffer.prototype\n  } else {\n    // Fallback: Return an object instance of the Buffer class\n    that.length = length\n  }\n\n  var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1\n  if (fromPool) that.parent = rootParent\n\n  return that\n}\n\nfunction checked (length) {\n  // Note: cannot use `length < kMaxLength` here because that fails when\n  // length is NaN (which is otherwise coerced to zero.)\n  if (length >= kMaxLength()) {\n    throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n                         'size: 0x' + kMaxLength().toString(16) + ' bytes')\n  }\n  return length | 0\n}\n\nfunction SlowBuffer (subject, encoding) {\n  if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)\n\n  var buf = new Buffer(subject, encoding)\n  delete buf.parent\n  return buf\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n  return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n    throw new TypeError('Arguments must be Buffers')\n  }\n\n  if (a === b) return 0\n\n  var x = a.length\n  var y = b.length\n\n  for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n    if (a[i] !== b[i]) {\n      x = a[i]\n      y = b[i]\n      break\n    }\n  }\n\n  if (x < y) return -1\n  if (y < x) return 1\n  return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n  switch (String(encoding).toLowerCase()) {\n    case 'hex':\n    case 'utf8':\n    case 'utf-8':\n    case 'ascii':\n    case 'binary':\n    case 'base64':\n    case 'raw':\n    case 'ucs2':\n    case 'ucs-2':\n    case 'utf16le':\n    case 'utf-16le':\n      return true\n    default:\n      return false\n  }\n}\n\nBuffer.concat = function concat (list, length) {\n  if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')\n\n  if (list.length === 0) {\n    return new Buffer(0)\n  }\n\n  var i\n  if (length === undefined) {\n    length = 0\n    for (i = 0; i < list.length; i++) {\n      length += list[i].length\n    }\n  }\n\n  var buf = new Buffer(length)\n  var pos = 0\n  for (i = 0; i < list.length; i++) {\n    var item = list[i]\n    item.copy(buf, pos)\n    pos += item.length\n  }\n  return buf\n}\n\nfunction byteLength (string, encoding) {\n  if (typeof string !== 'string') string = '' + string\n\n  var len = string.length\n  if (len === 0) return 0\n\n  // Use a for loop to avoid recursion\n  var loweredCase = false\n  for (;;) {\n    switch (encoding) {\n      case 'ascii':\n      case 'binary':\n      // Deprecated\n      case 'raw':\n      case 'raws':\n        return len\n      case 'utf8':\n      case 'utf-8':\n        return utf8ToBytes(string).length\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return len * 2\n      case 'hex':\n        return len >>> 1\n      case 'base64':\n        return base64ToBytes(string).length\n      default:\n        if (loweredCase) return utf8ToBytes(string).length // assume utf8\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\n  }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n  var loweredCase = false\n\n  start = start | 0\n  end = end === undefined || end === Infinity ? this.length : end | 0\n\n  if (!encoding) encoding = 'utf8'\n  if (start < 0) start = 0\n  if (end > this.length) end = this.length\n  if (end <= start) return ''\n\n  while (true) {\n    switch (encoding) {\n      case 'hex':\n        return hexSlice(this, start, end)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Slice(this, start, end)\n\n      case 'ascii':\n        return asciiSlice(this, start, end)\n\n      case 'binary':\n        return binarySlice(this, start, end)\n\n      case 'base64':\n        return base64Slice(this, start, end)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return utf16leSlice(this, start, end)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = (encoding + '').toLowerCase()\n        loweredCase = true\n    }\n  }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nBuffer.prototype.toString = function toString () {\n  var length = this.length | 0\n  if (length === 0) return ''\n  if (arguments.length === 0) return utf8Slice(this, 0, length)\n  return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n  if (this === b) return true\n  return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n  var str = ''\n  var max = exports.INSPECT_MAX_BYTES\n  if (this.length > 0) {\n    str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n    if (this.length > max) str += ' ... '\n  }\n  return '<Buffer ' + str + '>'\n}\n\nBuffer.prototype.compare = function compare (b) {\n  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n  return Buffer.compare(this, b)\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset) {\n  if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff\n  else if (byteOffset < -0x80000000) byteOffset = -0x80000000\n  byteOffset >>= 0\n\n  if (this.length === 0) return -1\n  if (byteOffset >= this.length) return -1\n\n  // Negative offsets start from the end of the buffer\n  if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)\n\n  if (typeof val === 'string') {\n    if (val.length === 0) return -1 // special case: looking for empty string always fails\n    return String.prototype.indexOf.call(this, val, byteOffset)\n  }\n  if (Buffer.isBuffer(val)) {\n    return arrayIndexOf(this, val, byteOffset)\n  }\n  if (typeof val === 'number') {\n    if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {\n      return Uint8Array.prototype.indexOf.call(this, val, byteOffset)\n    }\n    return arrayIndexOf(this, [ val ], byteOffset)\n  }\n\n  function arrayIndexOf (arr, val, byteOffset) {\n    var foundIndex = -1\n    for (var i = 0; byteOffset + i < arr.length; i++) {\n      if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {\n        if (foundIndex === -1) foundIndex = i\n        if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex\n      } else {\n        foundIndex = -1\n      }\n    }\n    return -1\n  }\n\n  throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction hexWrite (buf, string, offset, length) {\n  offset = Number(offset) || 0\n  var remaining = buf.length - offset\n  if (!length) {\n    length = remaining\n  } else {\n    length = Number(length)\n    if (length > remaining) {\n      length = remaining\n    }\n  }\n\n  // must be an even number of digits\n  var strLen = string.length\n  if (strLen % 2 !== 0) throw new Error('Invalid hex string')\n\n  if (length > strLen / 2) {\n    length = strLen / 2\n  }\n  for (var i = 0; i < length; i++) {\n    var parsed = parseInt(string.substr(i * 2, 2), 16)\n    if (isNaN(parsed)) throw new Error('Invalid hex string')\n    buf[offset + i] = parsed\n  }\n  return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n  return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n  return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction binaryWrite (buf, string, offset, length) {\n  return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n  return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n  return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n  // Buffer#write(string)\n  if (offset === undefined) {\n    encoding = 'utf8'\n    length = this.length\n    offset = 0\n  // Buffer#write(string, encoding)\n  } else if (length === undefined && typeof offset === 'string') {\n    encoding = offset\n    length = this.length\n    offset = 0\n  // Buffer#write(string, offset[, length][, encoding])\n  } else if (isFinite(offset)) {\n    offset = offset | 0\n    if (isFinite(length)) {\n      length = length | 0\n      if (encoding === undefined) encoding = 'utf8'\n    } else {\n      encoding = length\n      length = undefined\n    }\n  // legacy write(string, encoding, offset, length) - remove in v0.13\n  } else {\n    var swap = encoding\n    encoding = offset\n    offset = length | 0\n    length = swap\n  }\n\n  var remaining = this.length - offset\n  if (length === undefined || length > remaining) length = remaining\n\n  if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n    throw new RangeError('attempt to write outside buffer bounds')\n  }\n\n  if (!encoding) encoding = 'utf8'\n\n  var loweredCase = false\n  for (;;) {\n    switch (encoding) {\n      case 'hex':\n        return hexWrite(this, string, offset, length)\n\n      case 'utf8':\n      case 'utf-8':\n        return utf8Write(this, string, offset, length)\n\n      case 'ascii':\n        return asciiWrite(this, string, offset, length)\n\n      case 'binary':\n        return binaryWrite(this, string, offset, length)\n\n      case 'base64':\n        // Warning: maxLength not taken into account in base64Write\n        return base64Write(this, string, offset, length)\n\n      case 'ucs2':\n      case 'ucs-2':\n      case 'utf16le':\n      case 'utf-16le':\n        return ucs2Write(this, string, offset, length)\n\n      default:\n        if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n        encoding = ('' + encoding).toLowerCase()\n        loweredCase = true\n    }\n  }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n  return {\n    type: 'Buffer',\n    data: Array.prototype.slice.call(this._arr || this, 0)\n  }\n}\n\nfunction base64Slice (buf, start, end) {\n  if (start === 0 && end === buf.length) {\n    return base64.fromByteArray(buf)\n  } else {\n    return base64.fromByteArray(buf.slice(start, end))\n  }\n}\n\nfunction utf8Slice (buf, start, end) {\n  end = Math.min(buf.length, end)\n  var res = []\n\n  var i = start\n  while (i < end) {\n    var firstByte = buf[i]\n    var codePoint = null\n    var bytesPerSequence = (firstByte > 0xEF) ? 4\n      : (firstByte > 0xDF) ? 3\n      : (firstByte > 0xBF) ? 2\n      : 1\n\n    if (i + bytesPerSequence <= end) {\n      var secondByte, thirdByte, fourthByte, tempCodePoint\n\n      switch (bytesPerSequence) {\n        case 1:\n          if (firstByte < 0x80) {\n            codePoint = firstByte\n          }\n          break\n        case 2:\n          secondByte = buf[i + 1]\n          if ((secondByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n            if (tempCodePoint > 0x7F) {\n              codePoint = tempCodePoint\n            }\n          }\n          break\n        case 3:\n          secondByte = buf[i + 1]\n          thirdByte = buf[i + 2]\n          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n            if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n              codePoint = tempCodePoint\n            }\n          }\n          break\n        case 4:\n          secondByte = buf[i + 1]\n          thirdByte = buf[i + 2]\n          fourthByte = buf[i + 3]\n          if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n            tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n            if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n              codePoint = tempCodePoint\n            }\n          }\n      }\n    }\n\n    if (codePoint === null) {\n      // we did not generate a valid codePoint so insert a\n      // replacement char (U+FFFD) and advance only 1 byte\n      codePoint = 0xFFFD\n      bytesPerSequence = 1\n    } else if (codePoint > 0xFFFF) {\n      // encode to utf16 (surrogate pair dance)\n      codePoint -= 0x10000\n      res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n      codePoint = 0xDC00 | codePoint & 0x3FF\n    }\n\n    res.push(codePoint)\n    i += bytesPerSequence\n  }\n\n  return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n  var len = codePoints.length\n  if (len <= MAX_ARGUMENTS_LENGTH) {\n    return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n  }\n\n  // Decode in chunks to avoid \"call stack size exceeded\".\n  var res = ''\n  var i = 0\n  while (i < len) {\n    res += String.fromCharCode.apply(\n      String,\n      codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n    )\n  }\n  return res\n}\n\nfunction asciiSlice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; i++) {\n    ret += String.fromCharCode(buf[i] & 0x7F)\n  }\n  return ret\n}\n\nfunction binarySlice (buf, start, end) {\n  var ret = ''\n  end = Math.min(buf.length, end)\n\n  for (var i = start; i < end; i++) {\n    ret += String.fromCharCode(buf[i])\n  }\n  return ret\n}\n\nfunction hexSlice (buf, start, end) {\n  var len = buf.length\n\n  if (!start || start < 0) start = 0\n  if (!end || end < 0 || end > len) end = len\n\n  var out = ''\n  for (var i = start; i < end; i++) {\n    out += toHex(buf[i])\n  }\n  return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n  var bytes = buf.slice(start, end)\n  var res = ''\n  for (var i = 0; i < bytes.length; i += 2) {\n    res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n  }\n  return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n  var len = this.length\n  start = ~~start\n  end = end === undefined ? len : ~~end\n\n  if (start < 0) {\n    start += len\n    if (start < 0) start = 0\n  } else if (start > len) {\n    start = len\n  }\n\n  if (end < 0) {\n    end += len\n    if (end < 0) end = 0\n  } else if (end > len) {\n    end = len\n  }\n\n  if (end < start) end = start\n\n  var newBuf\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    newBuf = this.subarray(start, end)\n    newBuf.__proto__ = Buffer.prototype\n  } else {\n    var sliceLen = end - start\n    newBuf = new Buffer(sliceLen, undefined)\n    for (var i = 0; i < sliceLen; i++) {\n      newBuf[i] = this[i + start]\n    }\n  }\n\n  if (newBuf.length) newBuf.parent = this.parent || this\n\n  return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n  if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n  if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n\n  return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) {\n    checkOffset(offset, byteLength, this.length)\n  }\n\n  var val = this[offset + --byteLength]\n  var mul = 1\n  while (byteLength > 0 && (mul *= 0x100)) {\n    val += this[offset + --byteLength] * mul\n  }\n\n  return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return ((this[offset]) |\n      (this[offset + 1] << 8) |\n      (this[offset + 2] << 16)) +\n      (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] * 0x1000000) +\n    ((this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var val = this[offset]\n  var mul = 1\n  var i = 0\n  while (++i < byteLength && (mul *= 0x100)) {\n    val += this[offset + i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n  var i = byteLength\n  var mul = 1\n  var val = this[offset + --i]\n  while (i > 0 && (mul *= 0x100)) {\n    val += this[offset + --i] * mul\n  }\n  mul *= 0x80\n\n  if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n  return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 1, this.length)\n  if (!(this[offset] & 0x80)) return (this[offset])\n  return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset] | (this[offset + 1] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 2, this.length)\n  var val = this[offset + 1] | (this[offset] << 8)\n  return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset]) |\n    (this[offset + 1] << 8) |\n    (this[offset + 2] << 16) |\n    (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n\n  return (this[offset] << 24) |\n    (this[offset + 1] << 16) |\n    (this[offset + 2] << 8) |\n    (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 4, this.length)\n  return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n  if (!noAssert) checkOffset(offset, 8, this.length)\n  return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n  if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')\n  if (value > max || value < min) throw new RangeError('value is out of bounds')\n  if (offset + ext > buf.length) throw new RangeError('index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n  var mul = 1\n  var i = 0\n  this[offset] = value & 0xFF\n  while (++i < byteLength && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  byteLength = byteLength | 0\n  if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)\n\n  var i = byteLength - 1\n  var mul = 1\n  this[offset + i] = value & 0xFF\n  while (--i >= 0 && (mul *= 0x100)) {\n    this[offset + i] = (value / mul) & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {\n    buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n      (littleEndian ? i : 1 - i) * 8\n  }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n  if (value < 0) value = 0xffffffff + value + 1\n  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {\n    buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n  }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset + 3] = (value >>> 24)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 1] = (value >>> 8)\n    this[offset] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = 0\n  var mul = 1\n  var sub = value < 0 ? 1 : 0\n  this[offset] = value & 0xFF\n  while (++i < byteLength && (mul *= 0x100)) {\n    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) {\n    var limit = Math.pow(2, 8 * byteLength - 1)\n\n    checkInt(this, value, offset, byteLength, limit - 1, -limit)\n  }\n\n  var i = byteLength - 1\n  var mul = 1\n  var sub = value < 0 ? 1 : 0\n  this[offset + i] = value & 0xFF\n  while (--i >= 0 && (mul *= 0x100)) {\n    this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n  }\n\n  return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n  if (value < 0) value = 0xff + value + 1\n  this[offset] = (value & 0xff)\n  return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n  } else {\n    objectWriteUInt16(this, value, offset, true)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 8)\n    this[offset + 1] = (value & 0xff)\n  } else {\n    objectWriteUInt16(this, value, offset, false)\n  }\n  return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value & 0xff)\n    this[offset + 1] = (value >>> 8)\n    this[offset + 2] = (value >>> 16)\n    this[offset + 3] = (value >>> 24)\n  } else {\n    objectWriteUInt32(this, value, offset, true)\n  }\n  return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n  value = +value\n  offset = offset | 0\n  if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n  if (value < 0) value = 0xffffffff + value + 1\n  if (Buffer.TYPED_ARRAY_SUPPORT) {\n    this[offset] = (value >>> 24)\n    this[offset + 1] = (value >>> 16)\n    this[offset + 2] = (value >>> 8)\n    this[offset + 3] = (value & 0xff)\n  } else {\n    objectWriteUInt32(this, value, offset, false)\n  }\n  return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n  if (offset + ext > buf.length) throw new RangeError('index out of range')\n  if (offset < 0) throw new RangeError('index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n  if (!noAssert) {\n    checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n  }\n  ieee754.write(buf, value, offset, littleEndian, 23, 4)\n  return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n  return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n  if (!noAssert) {\n    checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n  }\n  ieee754.write(buf, value, offset, littleEndian, 52, 8)\n  return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n  return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n  return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n  if (!start) start = 0\n  if (!end && end !== 0) end = this.length\n  if (targetStart >= target.length) targetStart = target.length\n  if (!targetStart) targetStart = 0\n  if (end > 0 && end < start) end = start\n\n  // Copy 0 bytes; we're done\n  if (end === start) return 0\n  if (target.length === 0 || this.length === 0) return 0\n\n  // Fatal error conditions\n  if (targetStart < 0) {\n    throw new RangeError('targetStart out of bounds')\n  }\n  if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n  if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n  // Are we oob?\n  if (end > this.length) end = this.length\n  if (target.length - targetStart < end - start) {\n    end = target.length - targetStart + start\n  }\n\n  var len = end - start\n  var i\n\n  if (this === target && start < targetStart && targetStart < end) {\n    // descending copy from end\n    for (i = len - 1; i >= 0; i--) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n    // ascending copy from start\n    for (i = 0; i < len; i++) {\n      target[i + targetStart] = this[i + start]\n    }\n  } else {\n    Uint8Array.prototype.set.call(\n      target,\n      this.subarray(start, start + len),\n      targetStart\n    )\n  }\n\n  return len\n}\n\n// fill(value, start=0, end=buffer.length)\nBuffer.prototype.fill = function fill (value, start, end) {\n  if (!value) value = 0\n  if (!start) start = 0\n  if (!end) end = this.length\n\n  if (end < start) throw new RangeError('end < start')\n\n  // Fill 0 bytes; we're done\n  if (end === start) return\n  if (this.length === 0) return\n\n  if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')\n  if (end < 0 || end > this.length) throw new RangeError('end out of bounds')\n\n  var i\n  if (typeof value === 'number') {\n    for (i = start; i < end; i++) {\n      this[i] = value\n    }\n  } else {\n    var bytes = utf8ToBytes(value.toString())\n    var len = bytes.length\n    for (i = start; i < end; i++) {\n      this[i] = bytes[i % len]\n    }\n  }\n\n  return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n  // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n  str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n  // Node converts strings with length < 2 to ''\n  if (str.length < 2) return ''\n  // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n  while (str.length % 4 !== 0) {\n    str = str + '='\n  }\n  return str\n}\n\nfunction stringtrim (str) {\n  if (str.trim) return str.trim()\n  return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n  if (n < 16) return '0' + n.toString(16)\n  return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n  units = units || Infinity\n  var codePoint\n  var length = string.length\n  var leadSurrogate = null\n  var bytes = []\n\n  for (var i = 0; i < length; i++) {\n    codePoint = string.charCodeAt(i)\n\n    // is surrogate component\n    if (codePoint > 0xD7FF && codePoint < 0xE000) {\n      // last char was a lead\n      if (!leadSurrogate) {\n        // no lead yet\n        if (codePoint > 0xDBFF) {\n          // unexpected trail\n          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n          continue\n        } else if (i + 1 === length) {\n          // unpaired lead\n          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n          continue\n        }\n\n        // valid lead\n        leadSurrogate = codePoint\n\n        continue\n      }\n\n      // 2 leads in a row\n      if (codePoint < 0xDC00) {\n        if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n        leadSurrogate = codePoint\n        continue\n      }\n\n      // valid surrogate pair\n      codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n    } else if (leadSurrogate) {\n      // valid bmp char, but last char was a lead\n      if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n    }\n\n    leadSurrogate = null\n\n    // encode utf8\n    if (codePoint < 0x80) {\n      if ((units -= 1) < 0) break\n      bytes.push(codePoint)\n    } else if (codePoint < 0x800) {\n      if ((units -= 2) < 0) break\n      bytes.push(\n        codePoint >> 0x6 | 0xC0,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x10000) {\n      if ((units -= 3) < 0) break\n      bytes.push(\n        codePoint >> 0xC | 0xE0,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else if (codePoint < 0x110000) {\n      if ((units -= 4) < 0) break\n      bytes.push(\n        codePoint >> 0x12 | 0xF0,\n        codePoint >> 0xC & 0x3F | 0x80,\n        codePoint >> 0x6 & 0x3F | 0x80,\n        codePoint & 0x3F | 0x80\n      )\n    } else {\n      throw new Error('Invalid code point')\n    }\n  }\n\n  return bytes\n}\n\nfunction asciiToBytes (str) {\n  var byteArray = []\n  for (var i = 0; i < str.length; i++) {\n    // Node's code seems to be doing this and not & 0x7F..\n    byteArray.push(str.charCodeAt(i) & 0xFF)\n  }\n  return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n  var c, hi, lo\n  var byteArray = []\n  for (var i = 0; i < str.length; i++) {\n    if ((units -= 2) < 0) break\n\n    c = str.charCodeAt(i)\n    hi = c >> 8\n    lo = c % 256\n    byteArray.push(lo)\n    byteArray.push(hi)\n  }\n\n  return byteArray\n}\n\nfunction base64ToBytes (str) {\n  return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n  for (var i = 0; i < length; i++) {\n    if ((i + offset >= dst.length) || (i >= src.length)) break\n    dst[i + offset] = src[i]\n  }\n  return i\n}\n"
  },
  {
    "path": "test/autotests/inspect/complex/expected.json",
    "content": "{\n    \"requires\": [\n        {\n            \"path\": \"lasso-loader\",\n            \"range\": [\n                19,\n                42\n            ],\n            \"argRange\": [\n                27,\n                41\n            ]\n        },\n        {\n            \"path\": \"foo\",\n            \"range\": [\n                151,\n                165\n            ],\n            \"argRange\": [\n                159,\n                164\n            ]\n        },\n        {\n            \"path\": \"bar\",\n            \"range\": [\n                188,\n                202\n            ],\n            \"argRange\": [\n                196,\n                201\n            ]\n        },\n        {\n            \"path\": \"lasso-loader\",\n            \"range\": [\n                473,\n                496\n            ],\n            \"argRange\": [\n                481,\n                495\n            ]\n        }\n    ],\n    \"foundGlobals\": {},\n    \"asyncBlocks\": [\n        {\n            \"requires\": [\n                {\n                    \"path\": \"baz\",\n                    \"range\": [\n                        272,\n                        286\n                    ],\n                    \"argRange\": [\n                        280,\n                        285\n                    ]\n                }\n            ],\n            \"dependencies\": [\n                \"./browser.json\",\n                {\n                    \"type\": \"require\",\n                    \"path\": \"baz\"\n                }\n            ],\n            \"firstArgRange\": [\n                228,\n                246\n            ],\n            \"hasInlineDependencies\": true,\n            \"hasFunctionBody\": true\n        },\n        {\n            \"requires\": [\n                {\n                    \"path\": \"cat\",\n                    \"range\": [\n                        355,\n                        369\n                    ],\n                    \"argRange\": [\n                        363,\n                        368\n                    ]\n                }\n            ],\n            \"dependencies\": [\n                {\n                    \"type\": \"require\",\n                    \"path\": \"cat\"\n                }\n            ],\n            \"firstArgRange\": [\n                327,\n                380\n            ],\n            \"hasInlineDependencies\": false,\n            \"hasFunctionBody\": true\n        },\n        {\n            \"requires\": [],\n            \"dependencies\": [\n                \"require: avatar\",\n                \"require: address\"\n            ],\n            \"firstArgRange\": [\n                520,\n                617\n            ],\n            \"hasInlineDependencies\": true,\n            \"hasFunctionBody\": false\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/inspect/complex/input.js",
    "content": "var raptorLoader = require('lasso-loader');\n\nexports.test = function(input) {\n    for (var i=0; i<input.length; i++) {\n        if (true) {\n            require('foo');\n        }\n    }\n\n    require('bar');\n\n    raptorLoader.async(['./browser.json'], function(err) {\n        require('baz');\n\n        require('lasso-loader').async(function(err) {\n            require('cat');\n        });\n    });\n\n    var asyncLoaders = {\n        personProfile: function(callback) {\n            require('lasso-loader').async(\n                [\n                    'require: avatar',\n                    'require: address'\n                ], callback);\n        }\n    }\n\n    function loadModule(name, callback) {\n        asyncLoaders[name](callback);\n    }\n}"
  },
  {
    "path": "test/autotests/inspect/first-mate/expected.json",
    "content": "{\n    \"requires\": [\n        {\n            \"path\": \"path\",\n            \"range\": [\n                155,\n                170\n            ],\n            \"argRange\": [\n                163,\n                169\n            ]\n        },\n        {\n            \"path\": \"underscore-plus\",\n            \"range\": [\n                179,\n                205\n            ],\n            \"argRange\": [\n                187,\n                204\n            ]\n        },\n        {\n            \"path\": \"fs-plus\",\n            \"range\": [\n                215,\n                233\n            ],\n            \"argRange\": [\n                223,\n                232\n            ]\n        },\n        {\n            \"path\": \"oniguruma\",\n            \"range\": [\n                251,\n                271\n            ],\n            \"argRange\": [\n                259,\n                270\n            ]\n        },\n        {\n            \"path\": \"event-kit\",\n            \"range\": [\n                297,\n                317\n            ],\n            \"argRange\": [\n                305,\n                316\n            ]\n        },\n        {\n            \"path\": \"grim\",\n            \"range\": [\n                337,\n                352\n            ],\n            \"argRange\": [\n                345,\n                351\n            ]\n        },\n        {\n            \"path\": \"./injections\",\n            \"range\": [\n                370,\n                393\n            ],\n            \"argRange\": [\n                378,\n                392\n            ]\n        },\n        {\n            \"path\": \"./pattern\",\n            \"range\": [\n                408,\n                428\n            ],\n            \"argRange\": [\n                416,\n                427\n            ]\n        },\n        {\n            \"path\": \"./rule\",\n            \"range\": [\n                440,\n                457\n            ],\n            \"argRange\": [\n                448,\n                456\n            ]\n        },\n        {\n            \"path\": \"./scope-selector\",\n            \"range\": [\n                478,\n                505\n            ],\n            \"argRange\": [\n                486,\n                504\n            ]\n        },\n        {\n            \"path\": \"emissary\",\n            \"range\": [\n                11391,\n                11410\n            ],\n            \"argRange\": [\n                11399,\n                11409\n            ]\n        }\n    ],\n    \"foundGlobals\": {\n        \"console\": true,\n        \"Object\": true\n    },\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/first-mate/input.js",
    "content": "(function() {\n  var Emitter, EmitterMixin, Grammar, Grim, Injections, OnigRegExp, Pattern, Rule, ScopeSelector, TokenizeLineResult, fs, path, _;\n\n  path = require('path');\n\n  _ = require('underscore-plus');\n\n  fs = require('fs-plus');\n\n  OnigRegExp = require('oniguruma').OnigRegExp;\n\n  Emitter = require('event-kit').Emitter;\n\n  Grim = require('grim');\n\n  Injections = require('./injections');\n\n  Pattern = require('./pattern');\n\n  Rule = require('./rule');\n\n  ScopeSelector = require('./scope-selector');\n\n  module.exports = Grammar = (function() {\n    Grammar.prototype.registration = null;\n\n    function Grammar(registry, options) {\n      var firstLineMatch, injectionSelector, injections, patterns, repository;\n      this.registry = registry;\n      if (options == null) {\n        options = {};\n      }\n      this.name = options.name, this.fileTypes = options.fileTypes, this.scopeName = options.scopeName, this.foldingStopMarker = options.foldingStopMarker, this.maxTokensPerLine = options.maxTokensPerLine;\n      injections = options.injections, injectionSelector = options.injectionSelector, patterns = options.patterns, repository = options.repository, firstLineMatch = options.firstLineMatch;\n      this.emitter = new Emitter;\n      this.repository = null;\n      this.initialRule = null;\n      this.rawPatterns = patterns;\n      this.rawRepository = repository;\n      if (injectionSelector != null) {\n        this.injectionSelector = new ScopeSelector(injectionSelector);\n      } else {\n        this.injectionSelector = null;\n      }\n      if (firstLineMatch) {\n        this.firstLineRegex = new OnigRegExp(firstLineMatch);\n      } else {\n        this.firstLineRegex = null;\n      }\n      if (this.fileTypes == null) {\n        this.fileTypes = [];\n      }\n      this.includedGrammarScopes = [];\n      this.injections = new Injections(this, injections);\n    }\n\n\n    /*\n    Section: Event Subscription\n     */\n\n    Grammar.prototype.onDidUpdate = function(callback) {\n      return this.emitter.on('did-update', callback);\n    };\n\n\n    /*\n    Section: Tokenizing\n     */\n\n    Grammar.prototype.tokenizeLines = function(text) {\n      var line, lineNumber, lines, ruleStack, scopes, tags, _i, _len, _ref, _results;\n      lines = text.split('\\n');\n      ruleStack = null;\n      scopes = [];\n      _results = [];\n      for (lineNumber = _i = 0, _len = lines.length; _i < _len; lineNumber = ++_i) {\n        line = lines[lineNumber];\n        _ref = this.tokenizeLine(line, ruleStack, lineNumber === 0), tags = _ref.tags, ruleStack = _ref.ruleStack;\n        _results.push(this.registry.decodeTokens(line, tags, scopes));\n      }\n      return _results;\n    };\n\n    Grammar.prototype.tokenizeLine = function(line, ruleStack, firstLine, compatibilityMode) {\n      var contentScopeName, initialRule, initialRuleStackLength, lastRule, lastSymbol, match, nextTags, openScopeTags, penultimateRule, popStack, position, previousPosition, previousRuleStackLength, rule, scopeName, tag, tags, tagsEnd, tagsStart, tokenCount, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;\n      if (firstLine == null) {\n        firstLine = false;\n      }\n      if (compatibilityMode == null) {\n        compatibilityMode = true;\n      }\n      tags = [];\n      if (ruleStack != null) {\n        ruleStack = ruleStack.slice();\n        if (compatibilityMode) {\n          openScopeTags = [];\n          for (_i = 0, _len = ruleStack.length; _i < _len; _i++) {\n            _ref = ruleStack[_i], scopeName = _ref.scopeName, contentScopeName = _ref.contentScopeName;\n            if (scopeName) {\n              openScopeTags.push(this.registry.startIdForScope(scopeName));\n            }\n            if (contentScopeName) {\n              openScopeTags.push(this.registry.startIdForScope(contentScopeName));\n            }\n          }\n        }\n      } else {\n        if (compatibilityMode) {\n          openScopeTags = [];\n        }\n        initialRule = this.getInitialRule();\n        scopeName = initialRule.scopeName, contentScopeName = initialRule.contentScopeName;\n        ruleStack = [\n          {\n            rule: initialRule,\n            scopeName: scopeName,\n            contentScopeName: contentScopeName\n          }\n        ];\n        if (scopeName) {\n          tags.push(this.startIdForScope(initialRule.scopeName));\n        }\n        if (contentScopeName) {\n          tags.push(this.startIdForScope(initialRule.contentScopeName));\n        }\n      }\n      initialRuleStackLength = ruleStack.length;\n      position = 0;\n      tokenCount = 0;\n      while (true) {\n        previousRuleStackLength = ruleStack.length;\n        previousPosition = position;\n        if (position === line.length + 1) {\n          break;\n        }\n        if (tokenCount >= this.getMaxTokensPerLine() - 1) {\n          tags.push(line.length - position);\n          while (ruleStack.length > initialRuleStackLength) {\n            _ref1 = ruleStack.pop(), scopeName = _ref1.scopeName, contentScopeName = _ref1.contentScopeName;\n            if (contentScopeName) {\n              tags.push(this.endIdForScope(contentScopeName));\n            }\n            if (scopeName) {\n              tags.push(this.endIdForScope(scopeName));\n            }\n          }\n          break;\n        }\n        if (match = _.last(ruleStack).rule.getNextTags(ruleStack, line, position, firstLine)) {\n          nextTags = match.nextTags, tagsStart = match.tagsStart, tagsEnd = match.tagsEnd;\n          if (position < tagsStart) {\n            tags.push(tagsStart - position);\n            tokenCount++;\n          }\n          tags.push.apply(tags, nextTags);\n          for (_j = 0, _len1 = nextTags.length; _j < _len1; _j++) {\n            tag = nextTags[_j];\n            if (tag >= 0) {\n              tokenCount++;\n            }\n          }\n          position = tagsEnd;\n        } else {\n          if (position < line.length || line.length === 0) {\n            tags.push(line.length - position);\n          }\n          break;\n        }\n        if (position === previousPosition) {\n          if (ruleStack.length === previousRuleStackLength) {\n            console.error(\"Popping rule because it loops at column \" + position + \" of line '\" + line + \"'\", _.clone(ruleStack));\n            if (ruleStack.length > 1) {\n              _ref2 = ruleStack.pop(), scopeName = _ref2.scopeName, contentScopeName = _ref2.contentScopeName;\n              if (contentScopeName) {\n                tags.push(this.endIdForScope(contentScopeName));\n              }\n              if (scopeName) {\n                tags.push(this.endIdForScope(scopeName));\n              }\n            } else {\n              if (position < line.length || (line.length === 0 && tags.length === 0)) {\n                tags.push(line.length - position);\n              }\n              break;\n            }\n          } else if (ruleStack.length > previousRuleStackLength) {\n            _ref3 = ruleStack.slice(-2), (_ref4 = _ref3[0], penultimateRule = _ref4.rule), (_ref5 = _ref3[1], lastRule = _ref5.rule);\n            if ((lastRule != null) && lastRule === penultimateRule) {\n              popStack = true;\n            }\n            if (((lastRule != null ? lastRule.scopeName : void 0) != null) && penultimateRule.scopeName === lastRule.scopeName) {\n              popStack = true;\n            }\n            if (popStack) {\n              ruleStack.pop();\n              lastSymbol = _.last(tags);\n              if (lastSymbol < 0 && lastSymbol === this.startIdForScope(lastRule.scopeName)) {\n                tags.pop();\n              }\n              tags.push(line.length - position);\n              break;\n            }\n          }\n        }\n      }\n      for (_k = 0, _len2 = ruleStack.length; _k < _len2; _k++) {\n        rule = ruleStack[_k].rule;\n        rule.clearAnchorPosition();\n      }\n      if (compatibilityMode) {\n        return new TokenizeLineResult(line, openScopeTags, tags, ruleStack, this.registry);\n      } else {\n        return {\n          line: line,\n          tags: tags,\n          ruleStack: ruleStack\n        };\n      }\n    };\n\n    Grammar.prototype.activate = function() {\n      return this.registration = this.registry.addGrammar(this);\n    };\n\n    Grammar.prototype.deactivate = function() {\n      var _ref;\n      this.emitter = new Emitter;\n      if ((_ref = this.registration) != null) {\n        _ref.dispose();\n      }\n      return this.registration = null;\n    };\n\n    Grammar.prototype.clearRules = function() {\n      this.initialRule = null;\n      return this.repository = null;\n    };\n\n    Grammar.prototype.getInitialRule = function() {\n      return this.initialRule != null ? this.initialRule : this.initialRule = this.createRule({\n        scopeName: this.scopeName,\n        patterns: this.rawPatterns\n      });\n    };\n\n    Grammar.prototype.getRepository = function() {\n      return this.repository != null ? this.repository : this.repository = (function(_this) {\n        return function() {\n          var data, name, repository, _ref;\n          repository = {};\n          _ref = _this.rawRepository;\n          for (name in _ref) {\n            data = _ref[name];\n            if ((data.begin != null) || (data.match != null)) {\n              data = {\n                patterns: [data],\n                tempName: name\n              };\n            }\n            repository[name] = _this.createRule(data);\n          }\n          return repository;\n        };\n      })(this)();\n    };\n\n    Grammar.prototype.addIncludedGrammarScope = function(scope) {\n      if (!_.include(this.includedGrammarScopes, scope)) {\n        return this.includedGrammarScopes.push(scope);\n      }\n    };\n\n    Grammar.prototype.grammarUpdated = function(scopeName) {\n      if (!_.include(this.includedGrammarScopes, scopeName)) {\n        return false;\n      }\n      this.clearRules();\n      this.registry.grammarUpdated(this.scopeName);\n      if (Grim.includeDeprecatedAPIs) {\n        this.emit('grammar-updated');\n      }\n      this.emitter.emit('did-update');\n      return true;\n    };\n\n    Grammar.prototype.startIdForScope = function(scope) {\n      return this.registry.startIdForScope(scope);\n    };\n\n    Grammar.prototype.endIdForScope = function(scope) {\n      return this.registry.endIdForScope(scope);\n    };\n\n    Grammar.prototype.scopeForId = function(id) {\n      return this.registry.scopeForId(id);\n    };\n\n    Grammar.prototype.createRule = function(options) {\n      return new Rule(this, this.registry, options);\n    };\n\n    Grammar.prototype.createPattern = function(options) {\n      return new Pattern(this, this.registry, options);\n    };\n\n    Grammar.prototype.getMaxTokensPerLine = function() {\n      return this.maxTokensPerLine;\n    };\n\n    Grammar.prototype.scopesFromStack = function(stack, rule, endPatternMatch) {\n      var contentScopeName, scopeName, scopes, _i, _len, _ref;\n      scopes = [];\n      for (_i = 0, _len = stack.length; _i < _len; _i++) {\n        _ref = stack[_i], scopeName = _ref.scopeName, contentScopeName = _ref.contentScopeName;\n        if (scopeName) {\n          scopes.push(scopeName);\n        }\n        if (contentScopeName) {\n          scopes.push(contentScopeName);\n        }\n      }\n      if (endPatternMatch && (rule != null ? rule.contentScopeName : void 0) && rule === stack[stack.length - 1]) {\n        scopes.pop();\n      }\n      return scopes;\n    };\n\n    return Grammar;\n\n  })();\n\n  if (Grim.includeDeprecatedAPIs) {\n    EmitterMixin = require('emissary').Emitter;\n    EmitterMixin.includeInto(Grammar);\n    Grammar.prototype.on = function(eventName) {\n      if (eventName === 'did-update') {\n        Grim.deprecate(\"Call Grammar::onDidUpdate instead\");\n      } else {\n        Grim.deprecate(\"Call explicit event subscription methods instead\");\n      }\n      return EmitterMixin.prototype.on.apply(this, arguments);\n    };\n  }\n\n  TokenizeLineResult = (function() {\n    function TokenizeLineResult(line, openScopeTags, tags, ruleStack, registry) {\n      this.line = line;\n      this.openScopeTags = openScopeTags;\n      this.tags = tags;\n      this.ruleStack = ruleStack;\n      this.registry = registry;\n    }\n\n    Object.defineProperty(TokenizeLineResult.prototype, 'tokens', {\n      get: function() {\n        return this.registry.decodeTokens(this.line, this.tags, this.openScopeTags);\n      }\n    });\n\n    return TokenizeLineResult;\n\n  })();\n\n}).call(this);\n"
  },
  {
    "path": "test/autotests/inspect/global-late-def/expected.json",
    "content": "{\n    \"requires\": [],\n    \"foundGlobals\": {},\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/global-late-def/input.js",
    "content": "exports.Foo = Foo;\n\nfunction Foo() {\n\n}"
  },
  {
    "path": "test/autotests/inspect/globals/expected.json",
    "content": "{\n    \"requires\": [],\n    \"foundGlobals\": {\n        \"propertyValue\": true,\n        \"async\": true,\n        \"process\": true,\n        \"arrayEl\": true,\n        \"callArg\": true\n    },\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/globals/input.js",
    "content": "\nvar foo = {\n    bar: propertyValue\n};\n\nasync.series(process.nextTick);\n\nfoo = [\n    arrayEl\n];\n\nvar a = function() {\n    foo(callArg);\n}"
  },
  {
    "path": "test/autotests/inspect/lasso-loader-var/expected.json",
    "content": "{\n    \"requires\": [\n        {\n            \"path\": \"lasso-loader\",\n            \"range\": [\n                19,\n                42\n            ],\n            \"argRange\": [\n                27,\n                41\n            ]\n        }\n    ],\n    \"foundGlobals\": {},\n    \"asyncBlocks\": [\n        {\n            \"requires\": [\n                {\n                    \"path\": \"baz\",\n                    \"range\": [\n                        146,\n                        160\n                    ],\n                    \"argRange\": [\n                        154,\n                        159\n                    ]\n                }\n            ],\n            \"dependencies\": [\n                \"./browser.json\",\n                {\n                    \"type\": \"require\",\n                    \"path\": \"baz\"\n                }\n            ],\n            \"firstArgRange\": [\n                102,\n                120\n            ],\n            \"hasInlineDependencies\": true,\n            \"hasFunctionBody\": true\n        },\n        {\n            \"requires\": [\n                {\n                    \"path\": \"cat\",\n                    \"range\": [\n                        218,\n                        232\n                    ],\n                    \"argRange\": [\n                        226,\n                        231\n                    ]\n                }\n            ],\n            \"dependencies\": [\n                {\n                    \"type\": \"require\",\n                    \"path\": \"cat\"\n                }\n            ],\n            \"firstArgRange\": [\n                190,\n                243\n            ],\n            \"hasInlineDependencies\": false,\n            \"hasFunctionBody\": true\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/inspect/lasso-loader-var/input.js",
    "content": "var raptorLoader = require('lasso-loader');\n\nexports.test = function(input) {\n\n    raptorLoader.async(['./browser.json'], function(err) {\n        require('baz');\n\n        raptorLoader.async(function(err) {\n            require('cat');\n        });\n    });\n};"
  },
  {
    "path": "test/autotests/inspect/parse-error/expected.json",
    "content": "{\n    \"name\": \"SyntaxError\",\n    \"message\": \"Unexpected token ;\\n> 1 | const thing = {;\\n    |                ^\\n  2 | require('foo');\\n  3 |\\n  4 | if (require('bar')) {\"\n}"
  },
  {
    "path": "test/autotests/inspect/parse-error/input.js",
    "content": "const thing = {;\nrequire('foo');\n\nif (require('bar')) {\n    require('baz');\n}\n"
  },
  {
    "path": "test/autotests/inspect/process1/expected.json",
    "content": "{\n    \"requires\": [],\n    \"foundGlobals\": {\n        \"process\": true\n    },\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/process1/input.js",
    "content": "var p = process;\np.nextTick();"
  },
  {
    "path": "test/autotests/inspect/process2/expected.json",
    "content": "{\n    \"requires\": [],\n    \"foundGlobals\": {\n        \"process\": true\n    },\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/process2/input.js",
    "content": "exports.hello = function() {\n    process.nextTick(function() {\n\n    });\n}"
  },
  {
    "path": "test/autotests/inspect/process3/expected.json",
    "content": "{\n    \"requires\": [],\n    \"foundGlobals\": {},\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/process3/input.js",
    "content": "var process = {};\nprocess.nextTick();"
  },
  {
    "path": "test/autotests/inspect/process4/expected.json",
    "content": "{\n    \"requires\": [],\n    \"foundGlobals\": {\n        \"async\": true,\n        \"process\": true\n    },\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/process4/input.js",
    "content": "function test() {\n    async.parallel(process.nextTick);\n}"
  },
  {
    "path": "test/autotests/inspect/simple/expected.json",
    "content": "{\n    \"requires\": [\n        {\n            \"path\": \"foo\",\n            \"range\": [\n                0,\n                14\n            ],\n            \"argRange\": [\n                8,\n                13\n            ]\n        },\n        {\n            \"path\": \"bar\",\n            \"range\": [\n                21,\n                35\n            ],\n            \"argRange\": [\n                29,\n                34\n            ]\n        },\n        {\n            \"path\": \"baz\",\n            \"range\": [\n                43,\n                57\n            ],\n            \"argRange\": [\n                51,\n                56\n            ]\n        }\n    ],\n    \"foundGlobals\": {},\n    \"asyncBlocks\": []\n}"
  },
  {
    "path": "test/autotests/inspect/simple/input.js",
    "content": "require('foo');\n\nif (require('bar')) {\n    require('baz');\n}\n"
  },
  {
    "path": "test/autotests/load-prebuild/error-invalid-path/test.js",
    "content": "const path = require('path');\nconst expect = require('chai').expect;\n\nconst prebuildPath = path.join(__dirname, './page.prebuild.json');\n\nexports.check = async function (lasso) {\n    const lassoPageResult = await lasso.loadPrebuild({\n        path: prebuildPath,\n        flags: ['mobile']\n    });\n    expect(lassoPageResult.getHtmlForSlot('body')).to.equal('<script src=\\\"./test.js\\\"></script>');\n    expect(lassoPageResult.getHtmlForSlot('head')).to.equal('<link rel=\\\"stylesheet\\\" href=\\\"./style.css\\\">');\n};\n\nexports.checkError = function (err) {\n    expect(err.message).to.contain(`Error loading prebuild. No prebuild with path \"${prebuildPath}\" exists.`);\n};\n"
  },
  {
    "path": "test/autotests/load-prebuild/error-no-build/page.prebuild.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"assets\": [],\n    \"name\": \"page\",\n    \"flags\": [\"mobile\"]\n  }\n]\n"
  },
  {
    "path": "test/autotests/load-prebuild/error-no-build/test.js",
    "content": "const path = require('path');\nconst expect = require('chai').expect;\n\nconst prebuildPath = path.join(__dirname, './page.prebuild.json');\n\nexports.check = async function (lasso) {\n    const lassoPageResult = await lasso.loadPrebuild({ path: prebuildPath });\n\n    expect(lassoPageResult.getHtmlForSlot('body')).to.equal('<script src=\\\"./test.js\\\"></script>');\n    expect(lassoPageResult.getHtmlForSlot('head')).to.equal('<link rel=\\\"stylesheet\\\" href=\\\"./style.css\\\">');\n};\n\nexports.checkError = function (err) {\n    expect(err.message).to.contain(`No build could be found using flags: \"undefined\" for file at path \"${prebuildPath}\"`);\n};\n"
  },
  {
    "path": "test/autotests/load-prebuild/load-valid-prebuild/page.prebuild.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"assets\": [],\n    \"name\": \"page\"\n  }\n]\n"
  },
  {
    "path": "test/autotests/load-prebuild/load-valid-prebuild/test.js",
    "content": "const path = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function (lasso) {\n    const prebuildPath = path.join(__dirname, './page.prebuild.json');\n    const lassoPageResult = await lasso.loadPrebuild({ path: prebuildPath });\n    expect(lassoPageResult.getHtmlForSlot('body')).to.equal('<script src=\\\"./test.js\\\"></script>');\n    expect(lassoPageResult.getHtmlForSlot('head')).to.equal('<link rel=\\\"stylesheet\\\" href=\\\"./style.css\\\">');\n};\n"
  },
  {
    "path": "test/autotests/load-prebuild/load-valid-prebuild-multi-flags/page.prebuild.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"assets\": [],\n    \"name\": \"page\"\n  },\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test1.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"flags\": [\"mobile\", \"test\"],\n    \"assets\": [],\n    \"name\": \"page\"\n  },\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test2.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"flags\": [],\n    \"assets\": [],\n    \"name\": \"page\"\n  }\n]\n"
  },
  {
    "path": "test/autotests/load-prebuild/load-valid-prebuild-multi-flags/test.js",
    "content": "const path = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function (lasso) {\n    const prebuildPath = path.join(__dirname, './page.prebuild.json');\n    const lassoPageResult = await lasso.loadPrebuild({\n        path: prebuildPath,\n        flags: ['mobile', 'test']\n    });\n    expect(lassoPageResult.getHtmlForSlot('body')).to.equal('<script src=\\\"./test1.js\\\"></script>');\n    expect(lassoPageResult.getHtmlForSlot('head')).to.equal('<link rel=\\\"stylesheet\\\" href=\\\"./style.css\\\">');\n};\n"
  },
  {
    "path": "test/autotests/load-prebuild/load-valid-prebuild-multi-no-flags/page.prebuild.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"assets\": [],\n    \"name\": \"page\"\n  },\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test1.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"flags\": [\"mobile\", \"test\"],\n    \"assets\": [],\n    \"name\": \"page\"\n  },\n  {\n    \"slots\": {\n      \"body\": [{ \"contentType\": \"js\", \"content\": [{ \"code\": { \"src\": \"./test2.js\" } }] }],\n      \"head\": [{ \"contentType\": \"css\", \"content\": [{ \"code\": { \"href\": \"./style.css\"  }}] }]\n    },\n    \"flags\": [],\n    \"assets\": [],\n    \"name\": \"page\"\n  }\n]\n"
  },
  {
    "path": "test/autotests/load-prebuild/load-valid-prebuild-multi-no-flags/test.js",
    "content": "const path = require('path');\nconst expect = require('chai').expect;\n\nexports.check = async function (lasso) {\n    const prebuildPath = path.join(__dirname, './page.prebuild.json');\n    const lassoPageResult = await lasso.loadPrebuild({\n        path: prebuildPath\n    });\n    expect(lassoPageResult.getHtmlForSlot('body')).to.equal('<script src=\\\"./test.js\\\"></script>');\n    expect(lassoPageResult.getHtmlForSlot('head')).to.equal('<link rel=\\\"stylesheet\\\" href=\\\"./style.css\\\">');\n};\n"
  },
  {
    "path": "test/autotests/modules/async/foo.js",
    "content": "window.fooLoaded = true;\nexports.filename = __filename;\nexports.isFoo = true;"
  },
  {
    "path": "test/autotests/modules/async/lasso-loader-patch.js",
    "content": "var lassoLoader = require('lasso-loader');\nvar path = require('path');\nvar loaderMeta = module.__loaderMetadata;\n\nfunction _handleMissingAsync(asyncId) {\n    if (asyncId.charAt(0) === '_') {\n        return;\n    } else {\n        throw new Error('No loader metadata for ' + asyncId);\n    }\n}\n\nlassoLoader.async = function(asyncId, callback) {\n    if (!loaderMeta) {\n        return callback();\n    }\n\n    var resources;\n\n    if (Array.isArray(asyncId)) {\n        resources = {\n            js: [],\n            css: []\n        };\n        asyncId.forEach(function(asyncId) {\n            var curResources = loaderMeta[asyncId];\n            if (curResources) {\n                ['js', 'css'].forEach(function(key) {\n                    var paths = curResources[key];\n                    if (paths) {\n                        resources[key] = resources[key].concat(paths);\n                    }\n                });\n            } else {\n                _handleMissingAsync(asyncId);\n            }\n        });\n    } else if (!(resources = loaderMeta[asyncId])) {\n        _handleMissingAsync(asyncId);\n        return callback();\n    }\n\n    var job;\n    var modulesRuntime = require.runtime;\n    if (modulesRuntime) {\n        // Create a pending job in the module runtime system which will\n        // prevent any \"require-run\" modules from running if they are\n        // configured to wait until ready.\n        // When all pending jobs are completed, the \"require-run\" modules\n        // that have been queued up will be ran.\n        job = modulesRuntime.pending();\n    }\n\n    var jsUrls = resources.js;\n    if (jsUrls) {\n        jsUrls.forEach((url) => {\n            var filename = path.join($outputDir, url);\n            $loadScript(filename);\n        });\n    }\n\n    return callback();\n};"
  },
  {
    "path": "test/autotests/modules/async/main.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nexports.loadFoo = function(callback) {\n    require('lasso-loader').async(function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var foo = require('./foo');\n        callback(null, foo);\n    });\n};\n\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/async/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/async/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function (window) {\n    expect(window.fooLoaded).to.equal(undefined);\n    expect(window.main.filename).to.contain('main');\n\n    return new Promise((resolve, reject) => {\n        window.main.loadFoo(function(err) {\n            if (err) {\n                return reject(err);\n            }\n\n            resolve();\n        });\n    });\n};\n"
  },
  {
    "path": "test/autotests/modules/async-flags/foo.js",
    "content": "window.fooLoaded = true;\nexports.filename = __filename;\nexports.isFoo = true;"
  },
  {
    "path": "test/autotests/modules/async-flags/lasso-loader-patch.js",
    "content": "var lassoLoader = require('lasso-loader');\nvar path = require('path');\nvar loaderMeta = module.__loaderMetadata;\n\nfunction _handleMissingAsync(asyncId) {\n    if (asyncId.charAt(0) === '_') {\n        return;\n    } else {\n        throw new Error('No loader metadata for ' + asyncId);\n    }\n}\n\nlassoLoader.async = function(asyncId, callback) {\n    if (!loaderMeta) {\n        return callback();\n    }\n\n    var resources;\n\n    if (Array.isArray(asyncId)) {\n        resources = {\n            js: [],\n            css: []\n        };\n        asyncId.forEach(function(asyncId) {\n            var curResources = loaderMeta[asyncId];\n            if (curResources) {\n                ['js', 'css'].forEach(function(key) {\n                    var paths = curResources[key];\n                    if (paths) {\n                        resources[key] = resources[key].concat(paths);\n                    }\n                });\n            } else {\n                _handleMissingAsync(asyncId);\n            }\n        });\n    } else if (!(resources = loaderMeta[asyncId])) {\n        _handleMissingAsync(asyncId);\n        return callback();\n    }\n\n    var job;\n    var modulesRuntime = require.runtime;\n    if (modulesRuntime) {\n        // Create a pending job in the module runtime system which will\n        // prevent any \"require-run\" modules from running if they are\n        // configured to wait until ready.\n        // When all pending jobs are completed, the \"require-run\" modules\n        // that have been queued up will be ran.\n        job = modulesRuntime.pending();\n    }\n\n    var jsUrls = resources.js;\n    if (jsUrls) {\n        jsUrls.forEach((url) => {\n            var filename = path.join($outputDir, url);\n            $loadScript(filename);\n        });\n    }\n\n    return callback();\n};"
  },
  {
    "path": "test/autotests/modules/async-flags/main.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nexports.loadFoo = function(callback) {\n    require('lasso-loader').async(function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var foo = require('./foo');\n        callback(null, foo);\n    });\n};\n\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/async-flags/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/async-flags/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function (window) {\n    expect(window.fooLoaded).to.equal(undefined);\n    expect(window.main.filename).to.contain('main');\n\n    return new Promise((resolve, reject) => {\n        window.main.loadFoo(function(err) {\n            if (err) {\n                return reject(err);\n            }\n\n            resolve();\n        });\n    });\n};\n"
  },
  {
    "path": "test/autotests/modules/async-intersection/foo.js",
    "content": "window.fooLoaded = true;\nexports.filename = __filename;\nexports.isFoo = true;"
  },
  {
    "path": "test/autotests/modules/async-intersection/lasso-loader-patch.js",
    "content": "var lassoLoader = require('lasso-loader');\nvar path = require('path');\nvar loaderMeta = module.__loaderMetadata;\n\nfunction _handleMissingAsync(asyncId) {\n    if (asyncId.charAt(0) === '_') {\n        return;\n    } else {\n        throw new Error('No loader metadata for ' + asyncId);\n    }\n}\n\nlassoLoader.async = function(asyncId, callback) {\n    if (!loaderMeta) {\n        return callback();\n    }\n\n    var resources;\n\n    if (Array.isArray(asyncId)) {\n        resources = {\n            js: [],\n            css: []\n        };\n        asyncId.forEach(function(asyncId) {\n            var curResources = loaderMeta[asyncId];\n            if (curResources) {\n                ['js', 'css'].forEach(function(key) {\n                    var paths = curResources[key];\n                    if (paths) {\n                        resources[key] = resources[key].concat(paths);\n                    }\n                });\n            } else {\n                _handleMissingAsync(asyncId);\n            }\n        });\n    } else if (!(resources = loaderMeta[asyncId])) {\n        _handleMissingAsync(asyncId);\n        return callback();\n    }\n\n    var job;\n    var modulesRuntime = require.runtime;\n    if (modulesRuntime) {\n        // Create a pending job in the module runtime system which will\n        // prevent any \"require-run\" modules from running if they are\n        // configured to wait until ready.\n        // When all pending jobs are completed, the \"require-run\" modules\n        // that have been queued up will be ran.\n        job = modulesRuntime.pending();\n    }\n\n    var jsUrls = resources.js;\n    if (jsUrls) {\n        jsUrls.forEach((url) => {\n            var filename = path.join($outputDir, url);\n            $loadScript(filename);\n        });\n    }\n\n    return callback();\n};"
  },
  {
    "path": "test/autotests/modules/async-intersection/main1-helper.js",
    "content": "exports.isMain1Helper = true;"
  },
  {
    "path": "test/autotests/modules/async-intersection/main1.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nexports.load = function(callback) {\n    require('lasso-loader').async(function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var foo = require('./foo');\n        callback(null, {\n            foo: foo,\n            helper: require('./main1-helper')\n        });\n    });\n};\n\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/async-intersection/main2-helper.js",
    "content": "exports.isMain2Helper = true;"
  },
  {
    "path": "test/autotests/modules/async-intersection/main2.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nexports.load = function(callback) {\n    require('lasso-loader').async(function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var foo = require('./foo');\n        callback(null, {\n            foo: foo,\n            helper: require('./main2-helper')\n        });\n    });\n};\n\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/async-intersection/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/async-intersection/test.js",
    "content": "const expect = require('chai').expect;\n\nexports.lassoConfig = {\n    bundlingEnabled: true,\n    fingerprintsEnabled: false,\n    bundles: [\n        {\n            name: 'common',\n            dependencies: [\n                {\n                    \"intersection\": [\n                        'require-run: ' + require.resolve('./main1'),\n                        'require-run: ' + require.resolve('./main2')\n                    ]\n                }\n            ]\n        }\n    ]\n};\n\nexports.tests = [\n    {\n        lassoOptions: {\n            pageName: 'main1',\n            dependencies: [\n                'require-run: ' + require.resolve('./main1')\n            ]\n        },\n        check (window) {\n            expect(window.fooLoaded).to.equal(undefined);\n            expect(window.main.filename).to.contain('main');\n\n            return new Promise((resolve, reject) => {\n                window.main.load(function(err, loaded) {\n                    if (err) {\n                        return reject(err);\n                    }\n\n                    try {\n                        expect(window.fooLoaded).to.equal(true);\n                        expect(loaded.foo.isFoo).to.equal(true);\n                        expect(loaded.helper.isMain1Helper).to.equal(true);\n                    } catch (err) {\n                        return reject(err);\n                    }\n                    resolve();\n                });\n            });\n        }\n    },\n    {\n        lassoOptions: {\n            pageName: 'main2',\n            dependencies: [\n                'require-run: ' + require.resolve('./main2')\n            ]\n        },\n        check (window) {\n            expect(window.fooLoaded).to.equal(undefined);\n            expect(window.main.filename).to.contain('main');\n\n            return new Promise((resolve, reject) => {\n                window.main.load(function(err, loaded) {\n                    if (err) {\n                        return reject(err);\n                    }\n\n                    try {\n                        expect(window.fooLoaded).to.equal(true);\n                        expect(loaded.foo.isFoo).to.equal(true);\n                        expect(loaded.helper.isMain2Helper).to.equal(true);\n                    } catch (err) {\n                        return reject(err);\n                    }\n                    resolve();\n                });\n            });\n        }\n    }\n];\n"
  },
  {
    "path": "test/autotests/modules/async-package/bar.js",
    "content": "window.barLoaded = true;\nexports.filename = __filename;\nexports.isBar = true;"
  },
  {
    "path": "test/autotests/modules/async-package/browser.json",
    "content": "{\n    \"async\": {\n        \"foo\": [\n            \"require: ./foo\"\n        ],\n        \"bar\": [\n            \"require: ./bar\"\n        ],\n        \"something\": [\n            \"./something.js\"\n        ]\n    }\n}"
  },
  {
    "path": "test/autotests/modules/async-package/foo.js",
    "content": "window.fooLoaded = true;\nexports.filename = __filename;\nexports.isFoo = true;"
  },
  {
    "path": "test/autotests/modules/async-package/lasso-loader-patch.js",
    "content": "var lassoLoader = require('lasso-loader');\nvar path = require('path');\nvar loaderMeta = module.__loaderMetadata;\n\nfunction _handleMissingAsync(asyncId) {\n    if (asyncId.charAt(0) === '_') {\n        return;\n    } else {\n        throw new Error('No loader metadata for ' + asyncId);\n    }\n}\n\nlassoLoader.async = function(asyncId, callback) {\n    if (!loaderMeta) {\n        return callback();\n    }\n\n    var resources;\n\n    if (Array.isArray(asyncId)) {\n        resources = {\n            js: [],\n            css: []\n        };\n        asyncId.forEach(function(asyncId) {\n            var curResources = loaderMeta[asyncId];\n            if (curResources) {\n                ['js', 'css'].forEach(function(key) {\n                    var paths = curResources[key];\n                    if (paths) {\n                        resources[key] = resources[key].concat(paths);\n                    }\n                });\n            } else {\n                _handleMissingAsync(asyncId);\n            }\n        });\n    } else if (!(resources = loaderMeta[asyncId])) {\n        _handleMissingAsync(asyncId);\n        return callback();\n    }\n\n    var job;\n    var modulesRuntime = require.runtime;\n    if (modulesRuntime) {\n        // Create a pending job in the module runtime system which will\n        // prevent any \"require-run\" modules from running if they are\n        // configured to wait until ready.\n        // When all pending jobs are completed, the \"require-run\" modules\n        // that have been queued up will be ran.\n        job = modulesRuntime.pending();\n    }\n\n    var jsUrls = resources.js;\n    if (jsUrls) {\n        jsUrls.forEach((url) => {\n            var filename = path.join($outputDir, url);\n            $loadScript(filename);\n        });\n    }\n\n    return callback();\n};"
  },
  {
    "path": "test/autotests/modules/async-package/main.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nexports.loadFoo = function(callback) {\n    require('lasso-loader').async('foo', function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var foo = require('./foo');\n        callback(null, foo);\n    });\n};\n\nvar barPackageId = 'bar';\n\nexports.loadBar = function(callback) {\n    require('lasso-loader').async(barPackageId + '', function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var bar = require('./bar');\n        callback(null, bar);\n    });\n};\n\nexports.loadSomething = function(callback) {\n    require('lasso-loader').async('something', callback);\n};\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/async-package/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/async-package/something.js",
    "content": "window.somethingLoaded = true;"
  },
  {
    "path": "test/autotests/modules/async-package/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'main',\n                dependencies: [\n                    'require-run: ./main'\n                ]\n            },\n            {\n                name: 'foo',\n                dependencies: [\n                    'require: ./foo'\n                ]\n            },\n            {\n                name: 'something',\n                dependencies: [\n                    './something.js'\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = async function (window) {\n    expect(window.fooLoaded).to.equal(undefined);\n    expect(window.main.filename).to.contain('main');\n\n    return new Promise((resolve, reject) => {\n        window.main.loadFoo(function(err, foo) {\n            if (err) {\n                return reject(err);\n            }\n\n            expect(foo.isFoo).to.equal(true);\n            expect(window.fooLoaded).to.equal(true);\n            expect(window.barLoaded).to.equal(undefined);\n            expect(window.somethingLoaded).to.equal(undefined);\n\n            window.main.loadBar(function(err, bar) {\n                if (err) {\n                    return reject(err);\n                }\n\n                expect(bar.isBar).to.equal(true);\n                expect(window.fooLoaded).to.equal(true);\n                expect(window.barLoaded).to.equal(true);\n                expect(window.somethingLoaded).to.equal(undefined);\n\n                window.main.loadSomething(function(err) {\n                    if (err) {\n                        return reject(err);\n                    }\n\n                    expect(window.fooLoaded).to.equal(true);\n                    expect(window.barLoaded).to.equal(true);\n                    expect(window.somethingLoaded).to.equal(true);\n\n                    resolve();\n                });\n            });\n        });\n    });\n};\n"
  },
  {
    "path": "test/autotests/modules/async-package-css/browser.json",
    "content": "{\n    \"async\": {\n        \"something\": [\n            \"./something.css\"\n        ]\n    }\n}\n"
  },
  {
    "path": "test/autotests/modules/async-package-css/lasso-loader-patch.js",
    "content": "var lassoLoader = require('lasso-loader');\nvar path = require('path');\nvar loaderMeta = module.__loaderMetadata;\n\nfunction _handleMissingAsync(asyncId) {\n    if (asyncId.charAt(0) === '_') {\n        return;\n    } else {\n        throw new Error('No loader metadata for ' + asyncId);\n    }\n}\n\nlassoLoader.async = function(asyncId, callback) {\n    if (!loaderMeta) {\n        return callback();\n    }\n\n    var resources;\n\n    if (Array.isArray(asyncId)) {\n        resources = {\n            js: [],\n            css: []\n        };\n        asyncId.forEach(function(asyncId) {\n            var curResources = loaderMeta[asyncId];\n            if (curResources) {\n                ['js', 'css'].forEach(function(key) {\n                    var paths = curResources[key];\n                    if (paths) {\n                        resources[key] = resources[key].concat(paths);\n                    }\n                });\n            } else {\n                _handleMissingAsync(asyncId);\n            }\n        });\n    } else if (!(resources = loaderMeta[asyncId])) {\n        _handleMissingAsync(asyncId);\n        return callback();\n    }\n\n    var job;\n    var modulesRuntime = require.runtime;\n    if (modulesRuntime) {\n        // Create a pending job in the module runtime system which will\n        // prevent any \"require-run\" modules from running if they are\n        // configured to wait until ready.\n        // When all pending jobs are completed, the \"require-run\" modules\n        // that have been queued up will be ran.\n        job = modulesRuntime.pending();\n    }\n\n    var jsUrls = resources.js;\n    if (jsUrls) {\n        jsUrls.forEach((url) => {\n            var filename = path.join($outputDir, url);\n            $loadScript(filename);\n        });\n    }\n\n    return callback();\n};\n"
  },
  {
    "path": "test/autotests/modules/async-package-css/main.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nexports.loadSomething = function(callback) {\n    require('lasso-loader').async('something', callback);\n};\n\nwindow.main = module.exports;\n"
  },
  {
    "path": "test/autotests/modules/async-package-css/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/async-package-css/something.css",
    "content": ".test {}\n"
  },
  {
    "path": "test/autotests/modules/async-package-css/test.js",
    "content": "const expect = require('chai').expect;\nconst path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundles: [\n            {\n                name: 'main',\n                dependencies: [\n                    'require-run: ./main'\n                ]\n            },\n            {\n                name: 'something',\n                dependencies: [\n                    './something.css'\n                ]\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = async function (window, lassoPageResult) {\n    expect(window.fooLoaded).to.equal(undefined);\n    expect(window.main.filename).to.contain('main');\n\n    return new Promise((resolve, reject) => {\n        window.main.loadSomething(function(err) {\n            if (err) {\n                return reject(err);\n            }\n\n            expect(lassoPageResult.getCSSUrls())\n                .to.deep.equal(['./something.css']);\n\n            expect(lassoPageResult.getUrlByAsyncBundleName('something'))\n                .to.equal('./something.css');\n\n            expect(lassoPageResult.getFileByAsyncBundleName('something').endsWith('/something.css'))\n                .to.equal(true);\n\n            resolve();\n        });\n    });\n};\n"
  },
  {
    "path": "test/autotests/modules/async-raptor-loader/foo.js",
    "content": "window.fooLoaded = true;\nexports.filename = __filename;\nexports.isFoo = true;"
  },
  {
    "path": "test/autotests/modules/async-raptor-loader/lasso-loader-patch.js",
    "content": "var lassoLoader = require('lasso-loader');\nvar path = require('path');\nvar loaderMeta = module.__loaderMetadata;\n\nfunction _handleMissingAsync(asyncId) {\n    if (asyncId.charAt(0) === '_') {\n        return;\n    } else {\n        throw new Error('No loader metadata for ' + asyncId);\n    }\n}\n\nlassoLoader.async = function(asyncId, callback) {\n    if (!loaderMeta) {\n        return callback();\n    }\n\n    var resources;\n\n    if (Array.isArray(asyncId)) {\n        resources = {\n            js: [],\n            css: []\n        };\n        asyncId.forEach(function(asyncId) {\n            var curResources = loaderMeta[asyncId];\n            if (curResources) {\n                ['js', 'css'].forEach(function(key) {\n                    var paths = curResources[key];\n                    if (paths) {\n                        resources[key] = resources[key].concat(paths);\n                    }\n                });\n            } else {\n                _handleMissingAsync(asyncId);\n            }\n        });\n    } else if (!(resources = loaderMeta[asyncId])) {\n        _handleMissingAsync(asyncId);\n        return callback();\n    }\n\n    var job;\n    var modulesRuntime = require.runtime;\n    if (modulesRuntime) {\n        // Create a pending job in the module runtime system which will\n        // prevent any \"require-run\" modules from running if they are\n        // configured to wait until ready.\n        // When all pending jobs are completed, the \"require-run\" modules\n        // that have been queued up will be ran.\n        job = modulesRuntime.pending();\n    }\n\n    var jsUrls = resources.js;\n    if (jsUrls) {\n        jsUrls.forEach((url) => {\n            var filename = path.join($outputDir, url);\n            $loadScript(filename);\n        });\n    }\n\n    return callback();\n};"
  },
  {
    "path": "test/autotests/modules/async-raptor-loader/main.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nexports.loadFoo = function(callback) {\n    require('raptor-loader').async(function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var foo = require('./foo');\n        callback(null, foo);\n    });\n};\n\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/async-raptor-loader/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/async-raptor-loader/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function (window) {\n    expect(window.fooLoaded).to.equal(undefined);\n    expect(window.main.filename).to.contain('main');\n\n    return new Promise((resolve, reject) => {\n        window.main.loadFoo(function(err) {\n            if (err) {\n                return reject(err);\n            }\n\n            resolve();\n        });\n    });\n};\n"
  },
  {
    "path": "test/autotests/modules/async-unnecessary/foo.js",
    "content": "window.fooLoaded = true;\nexports.filename = __filename;\nexports.isFoo = true;"
  },
  {
    "path": "test/autotests/modules/async-unnecessary/lasso-loader-patch.js",
    "content": "var lassoLoader = require('lasso-loader');\nvar path = require('path');\nvar loaderMeta = module.__loaderMetadata;\n\nfunction _handleMissingAsync(asyncId) {\n    if (asyncId.charAt(0) === '_') {\n        return;\n    } else {\n        throw new Error('No loader metadata for ' + asyncId);\n    }\n}\n\nlassoLoader.async = function(asyncId, callback) {\n    if (!loaderMeta) {\n        return callback();\n    }\n\n    var resources;\n\n    if (Array.isArray(asyncId)) {\n        resources = {\n            js: [],\n            css: []\n        };\n        asyncId.forEach(function(asyncId) {\n            var curResources = loaderMeta[asyncId];\n            if (curResources) {\n                ['js', 'css'].forEach(function(key) {\n                    var paths = curResources[key];\n                    if (paths) {\n                        resources[key] = resources[key].concat(paths);\n                    }\n                });\n            } else {\n                _handleMissingAsync(asyncId);\n            }\n        });\n    } else if (!(resources = loaderMeta[asyncId])) {\n        _handleMissingAsync(asyncId);\n        return callback();\n    }\n\n    var job;\n    var modulesRuntime = require.runtime;\n    if (modulesRuntime) {\n        // Create a pending job in the module runtime system which will\n        // prevent any \"require-run\" modules from running if they are\n        // configured to wait until ready.\n        // When all pending jobs are completed, the \"require-run\" modules\n        // that have been queued up will be ran.\n        job = modulesRuntime.pending();\n    }\n\n    var jsUrls = resources.js;\n    if (jsUrls) {\n        jsUrls.forEach((url) => {\n            var filename = path.join($outputDir, url);\n            $loadScript(filename);\n        });\n    }\n\n    return callback();\n};"
  },
  {
    "path": "test/autotests/modules/async-unnecessary/main.js",
    "content": "exports.filename = __filename;\n\nrequire('./lasso-loader-patch');\n\nrequire('./foo');\n\nexports.loadFoo = function(callback) {\n    require('lasso-loader').async(function(err) {\n        if (err) {\n            return callback(err);\n        }\n        var foo = require('./foo');\n        callback(null, foo);\n    });\n};\n\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/async-unnecessary/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/async-unnecessary/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function (window) {\n    expect(window.fooLoaded).to.equal(true);\n    expect(window.main.filename).to.contain('main');\n\n    return new Promise((resolve, reject) => {\n        window.main.loadFoo(function(err, foo) {\n            if (err) {\n                return reject(err);\n            }\n\n            expect(foo.isFoo).to.equal(true);\n            resolve();\n        });\n    });\n};\n"
  },
  {
    "path": "test/autotests/modules/browser.json-tilde/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"~/nested/browser.json\"\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/browser.json-tilde/nested/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./nested.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/browser.json-tilde/nested/nested.js",
    "content": "window.nested = true;"
  },
  {
    "path": "test/autotests/modules/browser.json-tilde/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/browser.json-tilde/test.js",
    "content": "var expect = require('chai').expect;\nrequire('require-self-ref');\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            require.resolve('./browser.json')\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.nested).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/browserify-transform/foo-transform.js",
    "content": "'use strict';\n\nvar Transform = require('stream').Transform;\n\nclass MyTransform extends Transform {\n    constructor(options) {\n        super(options);\n        this.string = '';\n    }\n\n    _transform(data, encoding, callback) {\n        this.string += data;\n        callback();\n    }\n\n    _flush(callback) {\n        var string = this.string.replace(/foo/g, 'bar');\n        this.push(string);\n        callback();\n    }\n}\n\nmodule.exports = function(file, opts) {\n    return new MyTransform();\n};"
  },
  {
    "path": "test/autotests/modules/browserify-transform/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/browserify-transform/main.js",
    "content": "exports.filename = __filename;\nexports.foo = 'foo';\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/browserify-transform/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/browserify-transform/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        require: {\n            transforms: [\n                require('./foo-transform')\n            ]\n        }\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.bar).to.equal('bar');\n};"
  },
  {
    "path": "test/autotests/modules/browserify-transforms/bar-transform.js",
    "content": "'use strict';\n\nvar Transform = require('stream').Transform;\n\nclass MyTransform extends Transform {\n    constructor(options) {\n        super(options);\n        this.string = '';\n    }\n\n    _transform(data, encoding, callback) {\n        this.string += data;\n        callback();\n    }\n\n    _flush(callback) {\n        var string = this.string.replace(/bar/g, 'BAR');\n        this.push(string);\n        callback();\n    }\n}\n\nmodule.exports = function(file, opts) {\n    return new MyTransform();\n};"
  },
  {
    "path": "test/autotests/modules/browserify-transforms/foo-transform.js",
    "content": "'use strict';\n\nvar Transform = require('stream').Transform;\n\nclass MyTransform extends Transform {\n    constructor(options) {\n        super(options);\n        this.string = '';\n    }\n\n    _transform(data, encoding, callback) {\n        this.string += data;\n        callback();\n    }\n\n    _flush(callback) {\n        var string = this.string.replace(/foo/g, 'bar');\n        this.push(string);\n        callback();\n    }\n}\n\nmodule.exports = function(file, opts) {\n    return new MyTransform();\n};"
  },
  {
    "path": "test/autotests/modules/browserify-transforms/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/browserify-transforms/main.js",
    "content": "exports.filename = __filename;\nexports.foo = 'foo';\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/browserify-transforms/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/browserify-transforms/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        require: {\n            transforms: [\n                require('./foo-transform'),\n                require('./bar-transform')\n            ]\n        }\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.BAR).to.equal('BAR');\n};"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/bar/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./hello\"\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/bar/hello.js",
    "content": "exports.hello = 'bar';"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo/browser.json\",\n        \"./bar/browser.json\",\n        \"require-run: ./main\"\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/foo/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./hello\"\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/foo/hello.js",
    "content": "exports.hello = 'foo';"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/main.js",
    "content": "var fooPath = './foo/hello';\nvar barPath = './bar/hello';\n\nexports.foo = require(fooPath);\nexports.bar = require(barPath);\n\nwindow.main = exports;"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/duplicate-name-browser-json/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            require.resolve('./browser.json')\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.foo.hello).to.contain('foo');\n    expect(window.main.bar.hello).to.contain('bar');\n};"
  },
  {
    "path": "test/autotests/modules/mask-define-vanilla-js/define-global.js",
    "content": "window.define = function() {\n\n};"
  },
  {
    "path": "test/autotests/modules/mask-define-vanilla-js/library.js",
    "content": "if (typeof define === 'undefined') {\n    window.defineFound = false;\n} else {\n    window.defineFound = true;\n}"
  },
  {
    "path": "test/autotests/modules/mask-define-vanilla-js/main.js",
    "content": "exports.filename = __filename;\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/mask-define-vanilla-js/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/mask-define-vanilla-js/test.js",
    "content": "var expect = require('chai').expect;\nvar path = require('path');\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            {\n                \"path\": path.join(__dirname, 'define-global.js'),\n                \"mask-define\": true\n            },\n            {\n                \"path\": path.join(__dirname, 'library.js'),\n                \"mask-define\": true\n            },\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.defineFound).to.equal(false);\n};"
  },
  {
    "path": "test/autotests/modules/missing-module/a.js",
    "content": "require('./b');"
  },
  {
    "path": "test/autotests/modules/missing-module/b.js",
    "content": "require('./c');"
  },
  {
    "path": "test/autotests/modules/missing-module/main.js",
    "content": "require('./a');"
  },
  {
    "path": "test/autotests/modules/missing-module/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/missing-module/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.checkError = function(e) {\n    var errorString = e.toString();\n    expect(errorString).to.contain('Failed to walk dependency [require: ./b]');\n    expect(errorString).to.contain('Dependency chain: [require: ./main] → [require: ./a] → [require: ./b]');\n    expect(errorString).to.contain('Error: Module not found: ./c (from \"test/autotests/modules/missing-module\" and referenced in \"test/autotests/modules/missing-module/b.js\")');\n};\n"
  },
  {
    "path": "test/autotests/modules/no-conflict/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/no-conflict/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/no-conflict/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/no-conflict/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        noConflict: 'myapp'\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.filename).to.contain('foo');\n    expect(window.main.foo.FOO).to.equal(true);\n    expect(window.$_mod).to.equal(undefined);\n    expect(typeof window.$_mod_myapp).to.equal('object');\n};"
  },
  {
    "path": "test/autotests/modules/registerRequireExtension-getDependencies/extra.js",
    "content": "window.EXTRA = true;"
  },
  {
    "path": "test/autotests/modules/registerRequireExtension-getDependencies/hello.foo",
    "content": "hello"
  },
  {
    "path": "test/autotests/modules/registerRequireExtension-getDependencies/main.js",
    "content": "exports.filename = __filename;\n\nexports.hello = require('./hello.foo');\nexports.world = require('./world.foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/registerRequireExtension-getDependencies/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/registerRequireExtension-getDependencies/test.js",
    "content": "var expect = require('chai').expect;\nvar fs = require('fs');\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        plugins: [\n            function myPlugin(lasso, pluginConfig) {\n                lasso.dependencies.registerRequireExtension(\n                    'foo',\n                    {\n                        async getDependencies (lassoContext) {\n                            return [ require.resolve('./extra.js') ];\n                        },\n\n                        async read (path, lassoContext) {\n                            var src = fs.readFileSync(path, { encoding: 'utf8' });\n                            return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;';\n                        }\n                    });\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n\n    expect(window.main.hello.FOO).to.equal('hello');\n    expect(window.main.hello.filename).to.contain('hello.foo');\n\n    expect(window.main.world.FOO).to.equal('world');\n    expect(window.main.world.filename).to.contain('world.foo');\n    expect(window.EXTRA).to.equal(true);\n};\n"
  },
  {
    "path": "test/autotests/modules/registerRequireExtension-getDependencies/world.foo",
    "content": "world"
  },
  {
    "path": "test/autotests/modules/registerRequireType/hello.foo",
    "content": "hello"
  },
  {
    "path": "test/autotests/modules/registerRequireType/main.js",
    "content": "exports.filename = __filename;\n\nvar helloPath = './hello.foo';\nexports.hello = require(helloPath);\nexports.world = require('./world.foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/registerRequireType/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/registerRequireType/test.js",
    "content": "var expect = require('chai').expect;\nvar fs = require('fs');\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        plugins: [\n            function myPlugin(lasso, pluginConfig) {\n                lasso.dependencies.registerRequireType(\n                    'foo',\n                    {\n                        properties: {\n                            'path': 'string'\n                        },\n\n                        async init (lassoContext) {\n                            if (!this.path) {\n                                throw new Error('\"path\" is required for a Marko dependency');\n                            }\n\n                            this.path = this.resolvePath(this.path);\n                        },\n\n                        read (lassoContext) {\n                            var src = fs.readFileSync(this.path, { encoding: 'utf8' });\n                            return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;';\n                        }\n                    });\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main',\n            \"./hello.foo\"\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n\n    expect(window.main.hello.FOO).to.equal('hello');\n    expect(window.main.hello.filename).to.contain('hello.foo');\n\n    expect(window.main.world.FOO).to.equal('world');\n    expect(window.main.world.filename).to.contain('world.foo');\n};\n"
  },
  {
    "path": "test/autotests/modules/registerRequireType/world.foo",
    "content": "world"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-callback/extra.js",
    "content": "window.EXTRA = true;"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-callback/hello.foo",
    "content": "hello"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-callback/main.js",
    "content": "exports.filename = __filename;\n\nvar helloPath = './hello.foo';\nexports.hello = require(helloPath);\nexports.world = require('./world.foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-callback/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-callback/test.js",
    "content": "var expect = require('chai').expect;\nvar fs = require('fs');\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        plugins: [\n            function myPlugin(lasso, pluginConfig) {\n                lasso.dependencies.registerRequireType(\n                    'foo',\n                    {\n                        properties: {\n                            'path': 'string'\n                        },\n\n                        async init (lassoContext) {\n                            if (!this.path) {\n                                throw new Error('\"path\" is required for a Marko dependency');\n                            }\n\n                            this.path = this.resolvePath(this.path);\n                        },\n\n                        async getDependencies (lassoContext) {\n                            return [require.resolve('./extra.js')];\n                        },\n\n                        read (lassoContext) {\n                            var src = fs.readFileSync(this.path, { encoding: 'utf8' });\n                            return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;';\n                        }\n                    });\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main',\n            \"./hello.foo\"\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n\n    expect(window.main.hello.FOO).to.equal('hello');\n    expect(window.main.hello.filename).to.contain('hello.foo');\n\n    expect(window.main.world.FOO).to.equal('world');\n    expect(window.main.world.filename).to.contain('world.foo');\n    expect(window.EXTRA).to.equal(true);\n};\n"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-callback/world.foo",
    "content": "world"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-promise/extra.js",
    "content": "window.EXTRA = true;"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-promise/hello.foo",
    "content": "hello"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-promise/main.js",
    "content": "exports.filename = __filename;\n\nvar helloPath = './hello.foo';\nexports.hello = require(helloPath);\nexports.world = require('./world.foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-promise/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-promise/test.js",
    "content": "var expect = require('chai').expect;\nvar fs = require('fs');\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        plugins: [\n            function myPlugin(lasso, pluginConfig) {\n                lasso.dependencies.registerRequireType(\n                    'foo',\n                    {\n                        properties: {\n                            'path': 'string'\n                        },\n\n                        async init (lassoContext) {\n                            if (!this.path) {\n                                throw new Error('\"path\" is required for a Marko dependency');\n                            }\n\n                            this.path = this.resolvePath(this.path);\n                        },\n\n                        async getDependencies (lassoContext) {\n                            return [ require.resolve('./extra.js') ];\n                        },\n\n                        read (lassoContext) {\n                            var src = fs.readFileSync(this.path, { encoding: 'utf8' });\n                            return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;';\n                        }\n                    });\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main',\n            \"./hello.foo\"\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n\n    expect(window.main.hello.FOO).to.equal('hello');\n    expect(window.main.hello.filename).to.contain('hello.foo');\n\n    expect(window.main.world.FOO).to.equal('world');\n    expect(window.main.world.filename).to.contain('world.foo');\n    expect(window.EXTRA).to.equal(true);\n};\n"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-promise/world.foo",
    "content": "world"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-value/extra.js",
    "content": "window.EXTRA = true;"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-value/hello.foo",
    "content": "hello"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-value/main.js",
    "content": "exports.filename = __filename;\n\nvar helloPath = './hello.foo';\nexports.hello = require(helloPath);\nexports.world = require('./world.foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-value/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-value/test.js",
    "content": "'use strict';\n\nvar expect = require('chai').expect;\nvar fs = require('fs');\n\nexports.getLassoConfig = function(dir) {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        plugins: [\n            function myPlugin(lasso, pluginConfig) {\n                lasso.dependencies.registerRequireType(\n                    'foo',\n                    {\n                        properties: {\n                            'path': 'string'\n                        },\n\n                        async init (lassoContext) {\n                            if (!this.path) {\n                                throw new Error('\"path\" is required for a Marko dependency');\n                            }\n\n                            this.path = this.resolvePath(this.path);\n                            this.foo = true;\n                        },\n\n                        async getDependencies (lassoContext) {\n                            expect(this.foo).to.equal(true);\n                            return [ require.resolve('./extra.js') ];\n                        },\n\n                        read (lassoContext) {\n                            var src = fs.readFileSync(this.path, { encoding: 'utf8' });\n                            return 'exports.FOO = ' + JSON.stringify(src) + '; exports.filename = __filename;';\n                        }\n                    });\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            './hello.foo',\n            'require-run: ./main',\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n\n    expect(window.main.hello.FOO).to.equal('hello');\n    expect(window.main.hello.filename).to.contain('hello.foo');\n\n    expect(window.main.world.FOO).to.equal('world');\n    expect(window.main.world.filename).to.contain('world.foo');\n    expect(window.EXTRA).to.equal(true);\n};\n"
  },
  {
    "path": "test/autotests/modules/registerRequireType-getDependencies-value/world.foo",
    "content": "world"
  },
  {
    "path": "test/autotests/modules/require-builtin-core/main.js",
    "content": "exports.assert = require('assert');\nexports.buffer = require('buffer');\nexports.events = require('events');\nexports.path = require('path');\nexports.stream = require('stream');\nexports.util = require('util');\n\nwindow.main = exports;"
  },
  {
    "path": "test/autotests/modules/require-builtin-core/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-builtin-core/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.assert.ok).to.be.a('function');\n};"
  },
  {
    "path": "test/autotests/modules/require-css/foo.css",
    "content": ".foo {\n    \n}"
  },
  {
    "path": "test/autotests/modules/require-css/main.js",
    "content": "require('./foo.css');\n\nexports.filename = __filename;\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-css/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-css/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n};"
  },
  {
    "path": "test/autotests/modules/require-custom-ext/hello.foo",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-custom-ext/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./hello');\nexports.foo2 = require('./hello.foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-custom-ext/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-custom-ext/require-foo-plugin.js",
    "content": "const fs = require('fs');\n\nmodule.exports = exports = function(lasso, config) {\n    lasso.dependencies.registerRequireExtension(\n        'foo',\n        {\n            async read (path, lassoContext) {\n                let src = await fs.promises.readFile(path, 'utf8');\n                src = src.replace(/FOO/g, 'BAR');\n                return src;\n            },\n\n            async lastModified (path, lassoContext) {\n                return lassoContext.getFileLastModified(path);\n            }\n        });\n};\n\nmodule.exports.counter = 0;\n"
  },
  {
    "path": "test/autotests/modules/require-custom-ext/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        plugins: [\n            require('./require-foo-plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\n\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.filename).to.contain('foo');\n    expect(window.main.foo.BAR).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-custom-ext-no-plugin/hello.foo",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-custom-ext-no-plugin/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./hello');\nexports.foo2 = require('./hello.foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-custom-ext-no-plugin/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-custom-ext-no-plugin/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        require: {\n            extensions: ['.js', '.foo']\n        }\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\n\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo).to.equal(window.main.foo2);\n    expect(window.main.foo.filename).to.contain('hello.foo');\n\n};"
  },
  {
    "path": "test/autotests/modules/require-custom-type/foo.json",
    "content": "{\n    \"hello\": \"world\"\n}"
  },
  {
    "path": "test/autotests/modules/require-custom-type/main.js",
    "content": "require('foo: ./foo.json');\n\nexports.filename = __filename;\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-custom-type/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-custom-type/test.js",
    "content": "var expect = require('chai').expect;\n\nfunction fooPlugins(lasso, config) {\n    lasso.dependencies.registerJavaScriptType('foo', {\n        properties: {\n            'path': 'string'\n        },\n\n        async init (context) {\n            if (!this.path) {\n                throw new Error('\"path\" is required');\n            }\n\n            this.path = this.resolvePath(this.path);\n        },\n\n        // Read the resource:\n        read (context) {\n            return 'var foo = true;';\n        }\n    });\n}\n\nexports.getLassoConfig = function() {\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        plugins: [\n            fooPlugins\n        ]\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n};\n"
  },
  {
    "path": "test/autotests/modules/require-globals/main.js",
    "content": "require('foo');\nexports.filename = __filename;\nexports.foo = window.foo;\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-globals/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-globals/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function(dir) {\n    var globals = {};\n    globals[require.resolve('foo')] = 'foo';\n\n    return {\n        bundlingEnabled: false,\n        fingerprintsEnabled: false,\n        require: {\n             globals\n        }\n    };\n};\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.foo.FOO).to.equal(true);\n    expect(window.main.foo.FOO).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-installed/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-installed/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-installed/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.filename).to.contain('foo');\n    expect(window.main.foo.FOO).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-installed-scoped-package/main.js",
    "content": "exports.filename = __filename;\nexports.bar = require('@foo/bar');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-installed-scoped-package/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-installed-scoped-package/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.bar.filename).to.contain('@foo/bar');\n    expect(window.main.bar.SCOPED_BAR).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-json/foo.json",
    "content": "{\n    \"FOO\": true\n}"
  },
  {
    "path": "test/autotests/modules/require-json/main.js",
    "content": "exports.filename = __filename;\nexports.foo1 = require('./foo');\nexports.foo2 = require('./foo.json');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-json/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-json/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo1.FOO).to.equal(true);\n    expect(window.main.foo2.FOO).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-relative/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-relative/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-relative/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-relative/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.filename).to.contain('foo');\n    expect(window.main.foo.FOO).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/bar-desktop.js",
    "content": "exports.isDesktop = true;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/bar.js",
    "content": "exports.isDesktop = false;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/browser.json",
    "content": "{\n    \"requireRemap\": [\n        {\n            \"from\": \"./foo.js\",\n            \"to\": \"./foo-mobile.js\",\n            \"if-flag\": \"mobile\"\n        },\n        {\n            \"from\": \"./bar.js\",\n            \"to\": \"./bar-desktop.js\",\n            \"if-flag\": \"desktop\"\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/foo-mobile.js",
    "content": "exports.isMobile = true;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/foo.js",
    "content": "exports.isMobile = false;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\nexports.bar = require('./bar');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-flag/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ],\n        flags: ['mobile']\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.isMobile).to.equal(true);\n    expect(window.main.bar.isDesktop).to.equal(false);\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/bar-desktop.js",
    "content": "exports.isDesktop = true;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/bar.js",
    "content": "exports.isDesktop = false;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/browser.json",
    "content": "{\n    \"requireRemap\": [\n        {\n            \"from\": \"./foo.js\",\n            \"to\": \"./foo-mobile.js\",\n            \"if-flag\": \"mobile\"\n        },\n        {\n            \"from\": \"./bar.js\",\n            \"to\": \"./bar-desktop.js\",\n            \"if-flag\": \"desktop\"\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/foo-mobile.js",
    "content": "exports.isMobile = true;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/foo.js",
    "content": "exports.isMobile = false;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\nexports.bar = require('./bar');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-flag-caching/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.tests = [\n    {\n        lassoOptions: {\n            dependencies: [\n                'require-run: ./main'\n            ],\n            flags: ['mobile']\n        },\n        check: function(window) {\n            expect(window.main.filename).to.contain('main');\n            expect(window.main.foo.isMobile).to.equal(true);\n            expect(window.main.bar.isDesktop).to.equal(false);\n        }\n    },\n    {\n        lassoOptions: {\n            dependencies: [\n                'require-run: ./main'\n            ],\n            flags: ['desktop']\n        },\n        check: function(window) {\n            expect(window.main.filename).to.contain('main');\n            expect(window.main.foo.isMobile).to.equal(false);\n            expect(window.main.bar.isDesktop).to.equal(true);\n        }\n    }\n];"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-installed/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-installed/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-installed/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\",\n    \"browser\": {\n        \"./foo.js\": \"foo-installed\"\n    }\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-installed/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.filename).to.contain('foo-installed');\n    expect(window.main.foo.FOO_INSTALLED).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-local/foo-browser.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO_BROWSER: true\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-local/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-local/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-local/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\",\n    \"browser\": {\n        \"foo.js\": \"./foo-browser\"\n    }\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-local-to-local/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.filename).to.contain('foo-browser');\n    expect(window.main.foo.FOO_BROWSER).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-void-installed/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('foo-installed');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-remap-void-installed/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\",\n    \"browser\": {\n        \"foo-installed\": false\n    }\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-void-installed/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(Object.keys(window.main.foo).length).to.equal(0);\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-void-relative/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-void-relative/foo2.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-remap-void-relative/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\nexports.foo2 = require('./foo2');\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-remap-void-relative/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\",\n    \"browser\": {\n        \"foo.js\": false,\n        \"./foo2\": false\n    }\n}"
  },
  {
    "path": "test/autotests/modules/require-remap-void-relative/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(Object.keys(window.main.foo).length).to.equal(0);\n    expect(Object.keys(window.main.foo2).length).to.equal(0);\n};"
  },
  {
    "path": "test/autotests/modules/require-resolve/foo.js",
    "content": "module.exports = {\n    filename: __filename,\n    FOO: true\n};"
  },
  {
    "path": "test/autotests/modules/require-resolve/main.js",
    "content": "exports.filename = __filename;\nexports.fooPath = require.resolve('./foo');\nexports.foo1 = require('./foo');\nexports.foo2 = require(require.resolve('./foo'));\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-resolve/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-resolve/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.fooPath).to.contain('foo');\n    expect(window.main.foo1).to.equal(window.main.foo2);\n};"
  },
  {
    "path": "test/autotests/modules/require-virtual-module/main.js",
    "content": "exports.filename = __filename;\n\nvar virtualModulePath = '/virtual-module/something.foo';\nexports.foo = require(virtualModulePath);\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/require-virtual-module/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/require-virtual-module/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main',\n            {\n                'type': 'require',\n                virtualModule: {\n                    path: __dirname + '/something.foo',\n                    clientPath: '/virtual-module/something.foo',\n                    read (lassoContext) {\n                        return 'exports.hello = \"world\"; exports.filename = __filename;';\n                    }\n                }\n            }\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.hello).to.equal('world');\n    expect(window.main.foo.filename).to.equal('/virtual-module/something.foo');\n};\n"
  },
  {
    "path": "test/autotests/modules/requireRemap-not-conditional/browser.json",
    "content": "{\n    \"requireRemap\": [\n        {\n            \"from\": \"./foo.js\",\n            \"to\": \"./foo-browser.js\"\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/requireRemap-not-conditional/foo-browser.js",
    "content": "exports.isBrowser = true;"
  },
  {
    "path": "test/autotests/modules/requireRemap-not-conditional/foo.js",
    "content": "exports.isBrowser = false;"
  },
  {
    "path": "test/autotests/modules/requireRemap-not-conditional/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/requireRemap-not-conditional/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/requireRemap-not-conditional/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ],\n        flags: ['mobile']\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.isBrowser).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/requireRemap-plus-package-browser/browser.json",
    "content": "{\n    \"requireRemap\": [\n        {\n            \"from\": \"./foo.js\",\n            \"to\": \"./foo-browser-lasso.js\"\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/modules/requireRemap-plus-package-browser/foo-browser-lasso.js",
    "content": "exports.isBrowserLasso = true;"
  },
  {
    "path": "test/autotests/modules/requireRemap-plus-package-browser/foo-browser.js",
    "content": "exports.isBrowser = true;"
  },
  {
    "path": "test/autotests/modules/requireRemap-plus-package-browser/foo.js",
    "content": "exports.isBrowser = false;"
  },
  {
    "path": "test/autotests/modules/requireRemap-plus-package-browser/main.js",
    "content": "exports.filename = __filename;\nexports.foo = require('./foo');\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/requireRemap-plus-package-browser/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\",\n    \"browser\": {\n        \"./foo.js\": \"./foo-browser.js\"\n    }\n}"
  },
  {
    "path": "test/autotests/modules/requireRemap-plus-package-browser/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ],\n        flags: ['mobile']\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n    expect(window.main.foo.isBrowserLasso).to.equal(true);\n};"
  },
  {
    "path": "test/autotests/modules/simple/main.js",
    "content": "exports.filename = __filename;\n\nwindow.main = module.exports;"
  },
  {
    "path": "test/autotests/modules/simple/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"1.0.0\"\n}"
  },
  {
    "path": "test/autotests/modules/simple/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoOptions = function(dir) {\n    return {\n        dependencies: [\n            'require-run: ./main'\n        ]\n    };\n};\n\nexports.check = function(window) {\n    expect(window.main.filename).to.contain('main');\n};"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-callback/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"foo-js\",\n            \"path\": \"./foo.js\"\n        },\n        {\n            \"type\": \"foo-css\",\n            \"path\": \"./foo.css\"\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-callback/foo.css",
    "content": "hello world"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-callback/foo.js",
    "content": "hello world"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-callback/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-callback/plugin.js",
    "content": "const fs = require('fs');\n\nmodule.exports = exports = function(lasso, config) {\n    lasso.dependencies.registerJavaScriptType(\n        'foo-js',\n        {\n            properties: {\n                'path': 'string'\n            },\n\n            async init () {\n                if (!this.path) {\n                    throw new Error('\"path\" is required for a less dependency');\n                }\n\n                this.path = this.resolvePath(this.path);\n            },\n\n            async read (lassoContext) {\n                module.exports.jsCounter++;\n                const src = await fs.promises.readFile(this.path, 'utf8');\n                return src.toUpperCase();\n            },\n\n            getSourceFile: function() {\n                return this.path;\n            },\n\n            async lastModified (lassoContext) {\n                return -1;\n            }\n        });\n\n    lasso.dependencies.registerStyleSheetType(\n        'foo-css',\n        {\n            properties: {\n                'path': 'string'\n            },\n\n            async init () {\n                if (!this.path) {\n                    throw new Error('\"path\" is required for a less dependency');\n                }\n\n                this.path = this.resolvePath(this.path);\n            },\n\n            async read (lassoContext) {\n                module.exports.cssCounter++;\n                let src = await fs.promises.readFile(this.path, 'utf8');\n                src = src.split('').reverse().join('');\n                return src;\n            },\n\n            getSourceFile: function() {\n                return this.path;\n            },\n\n            async lastModified (lassoContext) {\n                return -1;\n            }\n        });\n};\n\nmodule.exports.jsCounter = 0;\nmodule.exports.cssCounter = 0;\n"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-callback/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var plugin = require('./plugin');\n\n    var jsCode = writerTracker.getCodeForPath(lassoPageResult.getJavaScriptFiles()[0]);\n    expect(jsCode).to.equal('HELLO WORLD');\n\n    var cssCode = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    expect(cssCode).to.equal('dlrow olleh');\n\n    expect(plugin.cssCounter).to.equal(1);\n    expect(plugin.jsCounter).to.equal(1);\n};"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-promise/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"foo-js\",\n            \"path\": \"./foo.js\"\n        },\n        {\n            \"type\": \"foo-css\",\n            \"path\": \"./foo.css\"\n        }\n    ]\n}"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-promise/foo.css",
    "content": "hello world"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-promise/foo.js",
    "content": "hello world"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-promise/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-promise/plugin.js",
    "content": "const fs = require('fs');\n\nmodule.exports = exports = function(lasso, config) {\n    lasso.dependencies.registerJavaScriptType(\n        'foo-js',\n        {\n            properties: {\n                'path': 'string'\n            },\n\n            async init () {\n                if (!this.path) {\n                    throw new Error('\"path\" is required for a less dependency');\n                }\n\n                this.path = this.resolvePath(this.path);\n            },\n\n            async read (lassoContext) {\n                module.exports.jsCounter++;\n                const src = await fs.promises.readFile(this.path, 'utf8');\n                return src.toUpperCase();\n            },\n\n            getSourceFile: function() {\n                return this.path;\n            },\n\n            async lastModified (lassoContext) {\n                return -1;\n            }\n        });\n\n    lasso.dependencies.registerStyleSheetType(\n        'foo-css',\n        {\n            properties: {\n                'path': 'string'\n            },\n\n            async init () {\n                if (!this.path) {\n                    throw new Error('\"path\" is required for a less dependency');\n                }\n\n                this.path = this.resolvePath(this.path);\n            },\n\n            async read (lassoContext) {\n                module.exports.cssCounter++;\n                let src = await fs.promises.readFile(this.path, 'utf8');\n                src = src.split('').reverse().join('');\n                return src;\n            },\n\n            getSourceFile: function() {\n                return this.path;\n            },\n\n            async lastModified (lassoContext) {\n                return -1;\n            }\n        });\n};\n\nmodule.exports.jsCounter = 0;\nmodule.exports.cssCounter = 0;\n"
  },
  {
    "path": "test/autotests/plugins/custom-dependency-type-promise/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var plugin = require('./plugin');\n\n    var jsCode = writerTracker.getCodeForPath(lassoPageResult.getJavaScriptFiles()[0]);\n    expect(jsCode).to.equal('HELLO WORLD');\n\n    var cssCode = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    expect(cssCode).to.equal('dlrow olleh');\n\n    expect(plugin.cssCounter).to.equal(1);\n    expect(plugin.jsCounter).to.equal(1);\n};"
  },
  {
    "path": "test/autotests/plugins/events/async-foo.js",
    "content": "console.log('async-foo');"
  },
  {
    "path": "test/autotests/plugins/events/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./foo\"\n    ],\n\n    \"async\": {\n        \"foo\": [\n            \"./async-foo.js\"\n        ]\n    }\n}"
  },
  {
    "path": "test/autotests/plugins/events/expected-events.json",
    "content": "[\n    \"beforeBuildPage\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-runtime]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-ready: inline=\\\"end\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-builtin: name=\\\"lasso-loader\\\", target=\\\"/lasso-loader$x.x.x/src/index\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[loader-metadata]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-installed: parentPath=\\\"/lasso-loader$x.x.x\\\", childName=\\\"raptor-util\\\", childVersion=\\\"x.x.x\\\", parentDir=\\\"/node_modules/lasso-loader\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-def: path=\\\"/raptor-util$x.x.x/extend\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-def: path=\\\"/lasso-loader$x.x.x/src/resource-loader\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-installed: parentPath=\\\"/lasso-loader$x.x.x\\\", childName=\\\"events\\\", childVersion=\\\"x.x.x\\\", parentDir=\\\"/node_modules/lasso-loader\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-main: dir=\\\"/events$x.x.x\\\", main=\\\"events\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-def: path=\\\"/events$x.x.x/events\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-def: path=\\\"/lasso-loader$x.x.x/src/index\\\"]\",\n    \"beforeAddDependencyToSyncPageBundle:[commonjs-def: path=\\\"/autotest$x.x.x/foo\\\"]\",\n    \"beforeAddDependencyToAsyncPageBundle:[js: path=\\\"/test/autotests/plugins/events/async-foo.js\\\"]\"\n]"
  },
  {
    "path": "test/autotests/plugins/events/foo.js",
    "content": "console.log('foo');\n\nrequire('lasso-loader').async('foo', function() {\n});"
  },
  {
    "path": "test/autotests/plugins/events/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/events/plugin.js",
    "content": "'use strict';\n\nvar events = [];\nmodule.exports = exports = function(lasso, config) {\n    lasso.on('beforeBuildPage', (event) => {\n        var context = event.context;\n        events.push('beforeBuildPage');\n\n        context.on('beforeAddDependencyToSyncPageBundle', (event) => {\n            var dependency = event.dependency;\n            events.push('beforeAddDependencyToSyncPageBundle:' + dependency);\n        });\n\n        context.on('beforeAddDependencyToAsyncPageBundle', (event) => {\n            var dependency = event.dependency;\n            events.push('beforeAddDependencyToAsyncPageBundle:' + dependency);\n        });\n    });\n};\n\nexports.events = events;"
  },
  {
    "path": "test/autotests/plugins/events/test.js",
    "content": "exports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker, helpers) {\n    var events = require('./plugin').events;\n    helpers.compare(helpers.normalizeOutput(events, { replaceVersions: true }), '-events.json');\n};"
  },
  {
    "path": "test/autotests/plugins/global-dependency-prop/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/global-dependency-prop/plugin.js",
    "content": "module.exports = exports = function(lasso, config) {\n    lasso.dependencies.registerRequireExtension(\n                'foo',\n                {\n                    read: function(filename, lassoContext) {\n                        return 'module.exports=\"FOO\"';\n                    }\n                });\n};"
  },
  {
    "path": "test/autotests/plugins/global-dependency-prop/something.foo",
    "content": ""
  },
  {
    "path": "test/autotests/plugins/global-dependency-prop/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            'require: ./something.foo'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var jsCode = writerTracker.getCodeForPath(lassoPageResult.getJavaScriptFiles()[0]);\n    expect(jsCode).to.contain('module.exports=\"FOO\"');\n};"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/bar.js",
    "content": "console.log('bar');"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/baz.js",
    "content": "console.log('baz');"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"path\": \"./foo.js\",\n            \"slot\": \"my-inline-slot\"\n        },\n        {\n            \"path\": \"./bar.js\",\n            \"slot\": \"my-inline-slot\"\n        },\n        \"./baz.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/expected-my-inline-slot.html",
    "content": "<script>console.log('foo');\nconsole.log('bar');</script>"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/foo.js",
    "content": "console.log('foo');"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/plugin.js",
    "content": "'use strict';\n\nvar events = [];\nmodule.exports = exports = function(lasso, config) {\n    lasso.on('beforeBuildPage', (event) => {\n        var context = event.context;\n\n        context.on('beforeAddDependencyToSyncPageBundle', (event) => {\n            var dependency = event.dependency;\n\n            if (event.slot === 'my-inline-slot') {\n                dependency.inline = true;\n            }\n        });\n    });\n};\n\nexports.events = events;"
  },
  {
    "path": "test/autotests/plugins/inline-all-for-slot/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker, helpers) {\n    var myInlineSlotHtml = lassoPageResult.getSlotHtml('my-inline-slot');\n    helpers.compare(myInlineSlotHtml, '-my-inline-slot.html');\n\n    var jsCode = writerTracker.getCodeForPath(lassoPageResult.getJavaScriptFiles()[0]);\n    expect(jsCode).to.equal(\"console.log('baz');\");\n};"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-bundle-written/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./foo\"\n    ]\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-bundle-written/expected-events.json",
    "content": "[\n  \"plugins-lasso-context-event-bundle-written\",\n  \"plugins-lasso-context-event-bundle-written\"\n]\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-bundle-written/foo.js",
    "content": "console.log('foo');\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-bundle-written/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-bundle-written/plugin.js",
    "content": "'use strict';\n\nvar events = [];\n\nmodule.exports = exports = function(lasso, config) {\n    lasso.on('beforeBuildPage', (event) => {\n        var context = event.context;\n\n        context.on('bundleWritten', (event) => {\n            events.push(event.bundle.name);\n        });\n    });\n};\n\nexports.events = events;\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-bundle-written/test.js",
    "content": "exports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker, helpers) {\n    var events = require('./plugin').events;\n    helpers.compare(helpers.normalizeOutput(events, { replaceVersions: true }), '-events.json');\n};"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-resource-written/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./fonts/fonts.css\"\n    ]\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-resource-written/expected-events.json",
    "content": "[\n  {\n      \"url\": \"plugins-lasso-context-event-resource-written/autotest$x.x.x/fonts/Aleo-Regular.woff\",\n      \"outputFile\": true,\n      \"sourceFile\": true\n  }\n]\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-resource-written/fonts/fonts.css",
    "content": "@font-face { src: url('Aleo-Regular.woff'); }"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-resource-written/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-resource-written/plugin.js",
    "content": "'use strict';\n\nvar events = [];\n\nmodule.exports = exports = function(lasso, config) {\n    lasso.on('beforeBuildPage', (event) => {\n        var context = event.context;\n\n        context.on('resourceWritten', event => {\n            const correctSourceFile = event.sourceFile.endsWith('/test/autotests/plugins/lasso-context-event-resource-written/fonts/Aleo-Regular.woff');\n            const correctOutputFile = event.outputFile.endsWith('/test/build/plugins-lasso-context-event-resource-written/plugins-lasso-context-event-resource-written/autotest$0.0.0/fonts/Aleo-Regular.woff');\n\n            events.push({\n                url: event.url,\n                sourceFile: correctSourceFile,\n                outputFile: correctOutputFile\n            });\n        });\n    });\n};\n\nexports.events = events;\n"
  },
  {
    "path": "test/autotests/plugins/lasso-context-event-resource-written/test.js",
    "content": "exports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker, helpers) {\n    var events = require('./plugin').events;\n    helpers.compare(helpers.normalizeOutput(events, { replaceVersions: true }), '-events.json');\n};"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-bundle-written/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"require: ./foo\"\n    ]\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-bundle-written/expected-events.json",
    "content": "[\n  \"plugins-lasso-writer-event-bundle-written\",\n  \"plugins-lasso-writer-event-bundle-written\"\n]\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-bundle-written/foo.js",
    "content": "console.log('foo');\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-bundle-written/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-bundle-written/plugin.js",
    "content": "'use strict';\n\nvar events = [];\n\nmodule.exports = exports = function(lasso, config) {\n    lasso.on('beforeBuildPage', (event) => {\n        var context = event.context;\n\n        context.writer.on('bundleWritten', (event) => {\n            events.push(event.bundle.name);\n        });\n    });\n};\n\nexports.events = events;\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-bundle-written/test.js",
    "content": "exports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker, helpers) {\n    var events = require('./plugin').events;\n    helpers.compare(helpers.normalizeOutput(events, { replaceVersions: true }), '-events.json');\n};"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-resource-written/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./fonts/fonts.css\"\n    ]\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-resource-written/expected-events.json",
    "content": "[\n  {\n      \"url\": \"plugins-lasso-writer-event-resource-written/autotest$x.x.x/fonts/Aleo-Regular.woff\",\n      \"outputFile\": true,\n      \"sourceFile\": true\n  }\n]\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-resource-written/fonts/fonts.css",
    "content": "@font-face { src: url('Aleo-Regular.woff'); }"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-resource-written/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-resource-written/plugin.js",
    "content": "'use strict';\n\nvar events = [];\n\nmodule.exports = exports = function(lasso, config) {\n    lasso.on('beforeBuildPage', (event) => {\n        var context = event.context;\n\n        context.writer.on('resourceWritten', event => {\n            const correctSourceFile = event.sourceFile.endsWith('/test/autotests/plugins/lasso-writer-event-resource-written/fonts/Aleo-Regular.woff');\n            const correctOutputFile = event.outputFile.endsWith('/test/build/plugins-lasso-writer-event-resource-written/plugins-lasso-writer-event-resource-written/autotest$0.0.0/fonts/Aleo-Regular.woff');\n\n            events.push({\n                url: event.url,\n                sourceFile: correctSourceFile,\n                outputFile: correctOutputFile\n            });\n        });\n    });\n};\n\nexports.events = events;\n"
  },
  {
    "path": "test/autotests/plugins/lasso-writer-event-resource-written/test.js",
    "content": "exports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker, helpers) {\n    var events = require('./plugin').events;\n    helpers.compare(helpers.normalizeOutput(events, { replaceVersions: true }), '-events.json');\n};"
  },
  {
    "path": "test/autotests/plugins/registerRequireExtension/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/registerRequireExtension/plugin.js",
    "content": "module.exports = exports = function(lasso, config) {\n    lasso.dependencies.registerRequireExtension(\n                'foo',\n                {\n                    read: function(filename, lassoContext) {\n                        return 'module.exports=\"FOO\"';\n                    }\n                });\n};"
  },
  {
    "path": "test/autotests/plugins/registerRequireExtension/something.foo",
    "content": ""
  },
  {
    "path": "test/autotests/plugins/registerRequireExtension/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            'require: ./something.foo'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var jsCode = writerTracker.getCodeForPath(lassoPageResult.getJavaScriptFiles()[0]);\n    expect(jsCode).to.contain('module.exports=\"FOO\"');\n};"
  },
  {
    "path": "test/autotests/plugins/registerRequireType/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./something.foo\"\n    ]\n}"
  },
  {
    "path": "test/autotests/plugins/registerRequireType/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/registerRequireType/plugin.js",
    "content": "module.exports = exports = function(lasso, config) {\n    lasso.dependencies.registerRequireType(\n        'foo',\n        {\n            properties: {\n                'path': 'string'\n            },\n\n            async init (lassoContext) {\n                if (!this.path) {\n                    throw new Error('\"path\" is required for a Marko dependency');\n                }\n\n                this.path = this.resolvePath(this.path);\n            },\n\n            object: true, // We are exporting a simple JavaScript object\n\n            read (lassoContext) {\n                return new Promise((resolve) => {\n                    setTimeout(function() {\n                        resolve(JSON.stringify({foo: 'bar'}));\n                    });\n                });\n            },\n\n            async getLastModified (lassoContext) {\n                return lassoContext.getFileLastModified(this.path);\n            }\n        });\n};\n"
  },
  {
    "path": "test/autotests/plugins/registerRequireType/something.foo",
    "content": ""
  },
  {
    "path": "test/autotests/plugins/registerRequireType/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            require('./plugin')\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var jsCode = writerTracker.getCodeForPath(lassoPageResult.getJavaScriptFiles()[0]);\n    expect(jsCode).to.contain('$_mod.def(\"/autotest$0.0.0/something.foo\", {\"foo\":\"bar\"})');\n};"
  },
  {
    "path": "test/autotests/plugins/write-bundle/browser.json",
    "content": "{\n    \"dependencies\": [\n        {\n            \"type\": \"js\",\n            \"path\": \"./foo.js\"\n        }\n    ]\n}\n"
  },
  {
    "path": "test/autotests/plugins/write-bundle/foo.js",
    "content": "var a = 5;\n"
  },
  {
    "path": "test/autotests/plugins/write-bundle/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/plugins/write-bundle/plugin.js",
    "content": "module.exports = function(lasso, config) {\n    lasso.config.writer = {\n        async init (lassoContext) {\n            module.exports.counter.push('init');\n            await Promise.resolve();\n        },\n\n        async writeBundle (reader, lassoContext) {\n            const bundle = lassoContext.bundle;\n            bundle.url = 'test.com';\n            module.exports.counter.push('writeBundle');\n        },\n\n        async writeResource (reader, lassoContext) {\n            module.exports.counter.push('writeResource');\n            return { url: 'test.com' };\n        }\n    };\n};\n\nmodule.exports.counter = [];\n"
  },
  {
    "path": "test/autotests/plugins/write-bundle/test.js",
    "content": "var expect = require('chai').expect;\nconst plugin = require('./plugin');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [plugin]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    expect(plugin.counter).to.deep.equal(['init', 'writeBundle']);\n    expect(lassoPageResult.getJavaScriptFiles().length).to.equal(0);\n    expect(lassoPageResult.getJavaScriptUrls()).to.deep.equal(['test.com']);\n};\n"
  },
  {
    "path": "test/autotests/prebuild-page/invalid-prebuild-config/test.js",
    "content": "const expect = require('chai').expect;\n\nexports.prebuildConfig = true;\n\nexports.checkError = function (err) {\n    expect(err.message).to.equal('\"pageConfig\" should either be an array or object passed to \"lasso.prebuildPage(...)\"');\n};\n"
  },
  {
    "path": "test/autotests/prebuild-page/multi-prebuild/a.js",
    "content": "var a = true;\n"
  },
  {
    "path": "test/autotests/prebuild-page/multi-prebuild/b.js",
    "content": "var b = true;\n"
  },
  {
    "path": "test/autotests/prebuild-page/multi-prebuild/page.prebuild.expected.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [\n        {\n          \"contentType\": \"js\",\n          \"content\": [\n            {\n              \"inline\": false,\n              \"code\": {\n                \"src\": \"/static/page/lasso/test/autotests/prebuild-page/multi-prebuild/a.js\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    \"assets\": [],\n    \"name\": \"page\"\n  }\n]"
  },
  {
    "path": "test/autotests/prebuild-page/multi-prebuild/page1.prebuild.expected.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [\n        {\n          \"contentType\": \"js\",\n          \"content\": [\n            {\n              \"inline\": false,\n              \"code\": {\n                \"src\": \"/static/page1/lasso/test/autotests/prebuild-page/multi-prebuild/b.js\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    \"assets\": [],\n    \"name\": \"page1\"\n  }\n]"
  },
  {
    "path": "test/autotests/prebuild-page/multi-prebuild/test.js",
    "content": "const nodePath = require('path');\n\nexports.prebuildConfig = [\n    {\n        pageName: 'page',\n        dependencies: [nodePath.join(__dirname, 'a.js')],\n        pageDir: __dirname\n    },\n    {\n        pageName: 'page1',\n        dependencies: [nodePath.join(__dirname, 'b.js')],\n        pageDir: __dirname\n    }\n];\n"
  },
  {
    "path": "test/autotests/prebuild-page/prebuild-resource/test-page.prebuild.expected.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [\n        {\n          \"contentType\": \"js\",\n          \"content\": [\n            {\n              \"inline\": false,\n              \"code\": {\n                \"src\": \"/static/test-page/lasso/src/index.js\"\n              }\n            },\n            {\n              \"inline\": false,\n              \"code\": {\n                \"src\": \"/static/test-page/lasso/test/autotests/prebuild-page/prebuild-resource/ebay.png.js\"\n              }\n            }\n          ]\n        },\n        {\n          \"contentType\": \"js\",\n          \"content\": [\n            {\n              \"inline\": true,\n              \"code\": \"$_mod.ready();\",\n              \"merge\": true\n            }\n          ]\n        }\n      ]\n    },\n    \"assets\": [\n      {\n        \"url\": \"/static/test-page/lasso/test/autotests/prebuild-page/prebuild-resource/ebay.png\",\n        \"outputFile\": \"\",\n        \"sourceFile\": \"\"\n      }\n    ],\n    \"name\": \"test-page\"\n  }\n]"
  },
  {
    "path": "test/autotests/prebuild-page/prebuild-resource/test.js",
    "content": "const nodePath = require('path');\n\nexports.prebuildConfig = {\n    pageName: 'test-page',\n    dependencies: [ nodePath.join(__dirname, 'ebay.png') ],\n    pageDir: __dirname\n};\n"
  },
  {
    "path": "test/autotests/prebuild-page/valid-prebuild/a.js",
    "content": "var a = true;\n"
  },
  {
    "path": "test/autotests/prebuild-page/valid-prebuild/test-page-1.prebuild.expected.json",
    "content": "[\n  {\n    \"slots\": {\n      \"body\": [\n        {\n          \"contentType\": \"js\",\n          \"content\": [\n            {\n              \"inline\": false,\n              \"code\": {\n                \"src\": \"/static/test-page-1/lasso/test/autotests/prebuild-page/valid-prebuild/a.js\"\n              }\n            }\n          ]\n        }\n      ]\n    },\n    \"assets\": [],\n    \"name\": \"test-page-1\"\n  }\n]"
  },
  {
    "path": "test/autotests/prebuild-page/valid-prebuild/test.js",
    "content": "const nodePath = require('path');\n\nexports.prebuildConfig = {\n    pageName: 'test-page-1',\n    dependencies: [nodePath.join(__dirname, 'a.js')],\n    pageDir: __dirname\n};\n"
  },
  {
    "path": "test/autotests/require-no-op/enable/test.js",
    "content": "'use strict';\nvar expect = require('chai').expect;\n\nexports.check = function(nodeRequireNoOp) {\n    nodeRequireNoOp.enable('.xfoo');\n    nodeRequireNoOp.enable('xbar');\n    nodeRequireNoOp.enable(['yfoo', '.ybar']);\n\n    var test = require('./test.xfoo');\n    expect(Object.keys(test).length).to.equal(0);\n    require('./test.xbar');\n    require('./test.yfoo');\n    require('./test.yfoo');\n};"
  },
  {
    "path": "test/autotests/require-no-op/enable/test.xbar",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable/test.xfoo",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable/test.ybar",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable/test.yfoo",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-ignore-null-extension/test.js",
    "content": "'use strict';\nvar expect = require('chai').expect;\n\nexports.check = function(nodeRequireNoOp) {\n    nodeRequireNoOp.enable('.xfoo');\n    nodeRequireNoOp.enable('xbar');\n    nodeRequireNoOp.enable(null);\n    nodeRequireNoOp.enable(['yfoo', null, '.ybar']);\n\n    var test = require('./test.xfoo');\n    expect(Object.keys(test).length).to.equal(0);\n    require('./test.xbar');\n    require('./test.yfoo');\n    require('./test.yfoo');\n};\n"
  },
  {
    "path": "test/autotests/require-no-op/enable-ignore-null-extension/test.xbar",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-ignore-null-extension/test.xfoo",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-ignore-null-extension/test.ybar",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-ignore-null-extension/test.yfoo",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-throw-invalid-extension-type/test.js",
    "content": "'use strict';\nvar expect = require('chai').expect;\n\nexports.check = function(nodeRequireNoOp) {\n    nodeRequireNoOp.enable(true);\n};\n\nexports.checkError = function (e) {\n    expect(e.message).to.equal('Expected extension to be a string. Actual: true');\n};\n"
  },
  {
    "path": "test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xbar",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-throw-invalid-extension-type/test.xfoo",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-throw-invalid-extension-type/test.ybar",
    "content": ""
  },
  {
    "path": "test/autotests/require-no-op/enable-throw-invalid-extension-type/test.yfoo",
    "content": ""
  },
  {
    "path": "test/autotests/resource-transforms/filter/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/resource-transforms/filter/test.js",
    "content": "var expect = require('chai').expect;\nvar nodePath = require('path');\nvar fs = require('fs');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true,\n        plugins: [\n            function myPlugin(myLasso, pluginConfig) {\n                myLasso.addTransform({\n                    async filter (lassoContext) {\n                        var path = lassoContext.path;\n                        if (!path) return false;\n                        return /\\.bar$/.test(path);\n                    },\n\n                    name: 'testTransformer',\n\n                    stream: true,\n\n                    transform: function(stream, contentType, lassoContext, callback) {\n                        var through = require('through');\n                        return stream.pipe(through(\n                            function write(chunk) {\n                                this.push(chunk);\n                            },\n                            function end(chunk) {\n                                this.push(new Buffer('-TRANSFORMED', 'utf8'));\n                                this.push(null);\n                            }\n                        ));\n                    }\n                });\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {};\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            path: nodePath.join(__dirname, 'transform.bar'),\n            options: {},\n            check(result) {\n                var outputFile = result.outputFile;\n                expect(fs.readFileSync(outputFile, {encoding: 'utf8'})).to.equal('hello-TRANSFORMED');\n            }\n        },\n        {\n            path: nodePath.join(__dirname, 'transform.foo'),\n            options: {},\n            check(result) {\n                var outputFile = result.outputFile;\n                expect(fs.readFileSync(outputFile, {encoding: 'utf8'})).to.equal('world');\n            }\n        },\n\n    ];\n};\n"
  },
  {
    "path": "test/autotests/resource-transforms/filter/transform.bar",
    "content": "hello"
  },
  {
    "path": "test/autotests/resource-transforms/filter/transform.foo",
    "content": "world"
  },
  {
    "path": "test/autotests/resource-transforms/stream/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/resource-transforms/stream/test.js",
    "content": "var expect = require('chai').expect;\nvar nodePath = require('path');\nvar fs = require('fs');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true,\n        plugins: [\n            function myPlugin(myLasso, pluginConfig) {\n                myLasso.addTransform({\n                    contentType: ['foo', 'bar'],\n\n                    name: 'testTransformer',\n\n                    stream: true,\n\n                    transform: function(stream, lassoContext, callback) {\n                        var contentType = lassoContext.contentType;\n\n                        var deferredStream = lassoContext.deferredStream(function() {\n                            var chunks = [];\n                            stream\n                                .on('data', function(chunk) {\n                                    chunks.push(chunk);\n                                })\n                                .on('error', function(err) {\n                                    return callback(err);\n                                })\n                                .on('end', function() {\n                                    var buffer = Buffer.concat(chunks); // Create a buffer from all the received chunks\n                                    var str = buffer.toString('utf8');\n\n                                    // results[lassoContext.path] = str;\n\n                                    if (contentType === 'foo') {\n                                        deferredStream.push(str + '-FOO');\n                                    } else if (contentType === 'bar') {\n                                        deferredStream.push(str + '-BAR');\n                                    } else {\n                                        throw new Error('Unexpected content type: ', contentType);\n                                    }\n\n                                    deferredStream.push(null);\n                                });\n                        });\n\n                        return deferredStream;\n                    }\n                });\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {};\n};\n\nexports.getInputs = function() {\n    return [\n        {\n            path: nodePath.join(__dirname, 'transform.bar'),\n            options: {},\n            check(result) {\n                var outputFile = result.outputFile;\n                expect(fs.readFileSync(outputFile, {encoding: 'utf8'})).to.equal('hello-BAR');\n            }\n        },\n        {\n            path: nodePath.join(__dirname, 'transform.foo'),\n            options: {},\n            check(result) {\n                var outputFile = result.outputFile;\n                expect(fs.readFileSync(outputFile, {encoding: 'utf8'})).to.equal('world-FOO');\n            }\n        },\n\n    ];\n};\n"
  },
  {
    "path": "test/autotests/resource-transforms/stream/transform.bar",
    "content": "hello"
  },
  {
    "path": "test/autotests/resource-transforms/stream/transform.foo",
    "content": "world"
  },
  {
    "path": "test/autotests/transforms/minify-js/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.js\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/minify-js/foo.js",
    "content": "(function(console) {\n    var name = 'John' + ' ' + 'Doe';\n\n    function hello(name) {\n        console.log(name);\n    }\n\n    hello(name);\n}(console));"
  },
  {
    "path": "test/autotests/transforms/minify-js/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/minify-js/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true,\n        minifyJS: true\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var jsCode = writerTracker.getCodeForPath(lassoPageResult.getJavaScriptFiles()[0]);\n    expect(jsCode).to.not.contain('hello');\n    expect(jsCode).to.not.contain('name');\n    expect(jsCode).to.contain('console');\n};"
  },
  {
    "path": "test/autotests/transforms/output-transforms/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"transformsA.js\",\n        \"transformsA.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/output-transforms/css-transform1.js",
    "content": "var through = require('through');\n\nexports.stream = true;\n\nexports.transform = function(inStream, context) {\n    var contentType = context.contentType;\n\n    if (contentType === 'css') {\n        return inStream.pipe(through(null,\n            function end () { //optional\n                this.queue('-CSSTransform1');\n                this.queue(null);\n            }));\n    }\n    else {\n        return inStream;\n    }\n};\n\nexports.name = module.id;"
  },
  {
    "path": "test/autotests/transforms/output-transforms/css-transform2.js",
    "content": "exports.stream = false;\n\nexports.transform = function(code, context) {\n    var contentType = context.contentType;\n\n    if (contentType === 'css') {\n        return code.toUpperCase() + '-CSSTransform2';\n    } else {\n        return code;\n    }\n};\n\nexports.name = module.id;"
  },
  {
    "path": "test/autotests/transforms/output-transforms/js-transform1-async.js",
    "content": "var through = require('through');\n\nexports.stream = true;\n\nexports.transform = function(inStream, context) {\n    var contentType = context.contentType;\n    \n    if (!inStream) {\n        throw new Error('inStream expected');\n    }\n\n    if (contentType === 'js') {\n        var code = '';\n\n        return inStream.pipe(through(function write(data) {\n                code += data;\n            },\n            function end () {\n                setTimeout(function() {\n                    this.queue(code + '-JavaScriptTransform1Async');\n                    this.queue(null);\n                }.bind(this), 100);\n            }));\n    }\n    else {\n        return inStream;\n    }\n};\n\nexports.name = module.id;"
  },
  {
    "path": "test/autotests/transforms/output-transforms/js-transform2-async.js",
    "content": "'use strict';\n\nvar ok = require('assert').ok;\n\nexports.stream = false;\n\nexports.contentType = 'js';\n\nexports.transform = function(code, context) {\n    var contentType = context.contentType;\n    ok(contentType === 'js', '\"js\" content type expected');\n\n    return new Promise((resolve, reject) => {\n        setTimeout(function() {\n            resolve(code + '-JavaScriptTransform2Async');\n        }, 100);\n    });\n};\n\nexports.name = module.id;"
  },
  {
    "path": "test/autotests/transforms/output-transforms/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/output-transforms/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true,\n        plugins: [\n            {\n                plugin: function(theLasso, config) {\n                    theLasso.addTransform(require('./css-transform1.js'));\n                    theLasso.addTransform(require('./css-transform2.js'));\n                    theLasso.addTransform(require('./js-transform1-async.js'));\n                    theLasso.addTransform(require('./js-transform2-async.js'));\n                }\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    expect(writerTracker.getOutputFilenames()).to.deep.equal( [\n        'transforms-output-transforms.css',\n        'transforms-output-transforms.js'\n    ] );\n    expect(writerTracker.getCodeForFilename('transforms-output-transforms.js')).to.equal('transformsA_js-JavaScriptTransform1Async-JavaScriptTransform2Async');\n    expect(writerTracker.getCodeForFilename('transforms-output-transforms.css')).to.equal('TRANSFORMSA_CSS-CSSTRANSFORM1-CSSTransform2');\n};"
  },
  {
    "path": "test/autotests/transforms/output-transforms/transformsA.css",
    "content": "transformsA_css"
  },
  {
    "path": "test/autotests/transforms/output-transforms/transformsA.js",
    "content": "transformsA_js"
  },
  {
    "path": "test/autotests/transforms/resolve-font-urls/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./fonts/fonts.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/resolve-font-urls/fonts/fonts.css",
    "content": "@font-face { src: url('Aleo-Regular.woff'); }"
  },
  {
    "path": "test/autotests/transforms/resolve-font-urls/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/resolve-font-urls/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var expected = \"@font-face { src: url('Aleo-Regular-6be64eb6.woff'); }\";\n    var actual = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    // console.log(actual);\n    expect(actual).to.equal(expected);\n};"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-resolver/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-resolver/foo.css",
    "content": ".test-1 {background-image: url(SOME_DIR/MYCOMPANY-logo.png);}\n.test-2 {background-image: url(\"SOME_DIR/MYCOMPANY-logo.png\");}\n.test-3 {background-image: url('SOME_DIR/MYCOMPANY-logo.png');}\n.test-4 {background-image: url('SOME_DIR/MYCOMPANY-logo.png?base64');}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-resolver/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-resolver/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true,\n        resolveCssUrls: {\n            async urlResolver (url, lassoContext) {\n                url = url.replace('SOME_DIR', __dirname);\n                url = url.replace('MYCOMPANY', 'ebay');\n                return url;\n            }\n        }\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var expected = \".test-1 {background-image: url('ebay-logo-d481eb85.png');}\\n.test-2 {background-image: url('ebay-logo-d481eb85.png');}\\n.test-3 {background-image: url('ebay-logo-d481eb85.png');}\\n.test-4 {background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE8AAAAeCAYAAABt5kPUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGNzdGMTE3NDA3MjA2ODExODhDNkIzODA1MTg5Nzc0NiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRTg2MEMyMzZFNzIxMUUyQjZGMEE2ODM0MDRENkNFNiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRTg2MEMyMjZFNzIxMUUyQjZGMEE2ODM0MDRENkNFNiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODAxMTc0MDcyMDY4MTE5OTRDOTI2RkUxMEEyMEJFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkY3N0YxMTc0MDcyMDY4MTE4OEM2QjM4MDUxODk3NzQ2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Yff30gAAE/BJREFUeNrsWgdwHdW5/s+Wu7u3q3fJspqLLMuVYINt3AgQwjPFYCCN+ogpLyRgCKQHAo/H8OAFhgAOxQQCDt3E2Bg74IK7ZMuyZCFbVpescnvZet5/9kpuhJbMvJkwb2d2tPferd/5/6+cFTHDESCiAPrBZjD7+oBqOpjHjoE5MACEFwAoBbZwGekgDh2D95QJ8HthGsjUAAKpheCGYYJ3b0fibwmd5nIERPx6A67L4KRF1SlU5jhgdrkTMj0C9IcN0A0K00oUEHkCPicP51S5QBIIuPg48Byet3OVfQ/UiADoIaBmDAjnAOCdQNVjAIIXvx8CIuUCWDoQORe2awPQFjsEeDjgkXifBM4uuwPSXaVg4j5w/L45SOpBSGgBe3t04QgPCT0AezqfxedS7d84wYLAUR+0bckHt1eG1tZWEOArLCrl4JtGK+wX8+CteC64iXESeJQLxoxCVaNZI6hmn3KwScGp8AicC9wyB5YF//IL91V2ZjVocRzc7DkM1WQINBwhrLKRFcf3xIdTV1zcLgEunOKzgUOg4euwcF/1AB148BlxuNnVCg5sNevL4IBVdn6NB4rSBLtNvy7LVwaPYP0lsH2neeKwNHMYt/kvQJvCTOS4ylwJ1K8RcJ8LHmFExiMwAg9EEGxRIewzx9sUrJkAV+aFoMRpgGaRv38SBKsgU4SFEzw2xzEBEFEMHCMrjy1NyAlK+OKRI6lbJkjVTDQ4MbWyz0ghx0/2f7R8SjCIQ0SgRFQyLY1Go8X4Nx2o5eKiUdOKxUK839/NeT1dpiiZaQ4KF/sG4L9juSAR+imCJNjWy85IA7+Tg56g4R2ImGM1w8hCBXQqDi6uGdCriOSw7OASo6r+aaKlKWA4CewNI1xI9WGUVuLHvwrwLg3MRBDB7CO8sxN4WTeZvAKhKQVlQ41qyQmfw+T0lOGzFRovRXBQCIoi27ZoAp/QoDwWkMCKCQdKOH48qyoETW9sWpDcum252d19NtqWDGR3QmlKGklqnyTn9x+QamueETPTn7+owpVcbwpwsFc9rV0tmD/JA1V5jsJnPgqsaOxJXhLTrDzKxILa/Y9FTCyXxB0NJczn51a6/ifTLQTo6Q+GFYY2xWsNbbneCuy8mmoDVWhJFJtsT/ZKRFSJI6NFSJ/1TH76zNf3q70PmVogEwE0TEuTA/G236Q7x240QT+NhpjoiadYFQEHKqAdre0N1f8nY2zTUuUxOdO3e8xpdx1q2XpOfkEur6pqXLAvLOENqmp69NkXntEbDy6hoz4Cb9BuVyHl96iOF1ZV2Uwkpse7u6dr9ftvybnthisvO6N6/89f6z4xdrjh9QrJbJ940YrVfc8OB/Q0+3uejN6xbV3w9FzENMe+sSP4q43N0RtvW5h5zaKJ7nW2qLCH4SW8r77pRusjq6kaGPOpFmYrq0xbtTSJJnon6V2vPTo23PCDAjmD1qv9UySsGt2MQ33ni9rYjHkbUxenI0VtIX24kUpcp5zagR7yo8MP3RWMty0SeRceH4N8z4wXnJXzoHn80ODWbVtkrL4wsQJBMEMhX+Dun72t7ambQ1xoPjUNhMKCFqGs7GUEb5tjSu2QfviIYg0PT7IGBy/RDjYvYFXI9nNkZ/UIv71vwXVNBe1v7RpuN030ebh4ndwAMUEIhfU0t1ccnlysvJbvEz6qLZL7mvpUX+ewPqOpV7302LBeBiKxhUUUifb0NYWXXzHD9yanDwKvduWpO5ZspdGOUpswcVCJq2Q3cZWu4pxj6jhvTcIc3OgDU51mRVuW0Wh7LdtPwP2GRG/yRYciayMiZ6GpXzL5qXNLM+atZ2B+Jo9xMgxEmya/smfZdjTUskl1yPZM+Pjs8jvPzvFXmI07huGee39qA8/fe8stEHniD/+V2PDBZZzXyyoQHNOmrnZf+/3zxNKS98E0Dztqa3rx+w4hP2+3cu6iFzi3O6w3NZ/LKtIMBDyewe6K3qlz31zXoi3Hs7rZ4GKacKkJUynOk3f++zkZi8+ucK3yO/n9U4udR3DcmypypA2LJ3pWRlSrpKNfq2EAWjrlt7bE586f6FudLx4JmS0P3mn2b7uIUR4THy5nzjpH5Z0LEIuPiZTdQfy1PZDsbeP8tVuFwiuepdqxGTR6tNxCAH1WUohzkt7O8RxrL2w9TA3D+eNyL3xhlIb+3sIjTXzY+sDDvaG6qQJWPgN9TvmdNxf6pzezM7W19sLmzZtTaqs1NFYmNmz8AQICNJkER82knRmPP/odPj09ru1rAO1gEyTWbwBtbx1oBxrBCobAe+vyR5Tzzn2c7U9cLlD31J87vuXjC0GW4ycnivICueW15SXfqi6Q25DX0KpYkMSVWZaoaoFX5mLPXVN49Xm1njcAPzMAB4J63gNrB++JJC0k5LjKp1Vu5HzVa7i0ce/zuRf8EiE0wIiihiUAwo0AiS6wjq3HLhjUhMJl9yJ3W/gjwxqmyAUNHimrgwEg8Ap0BrYvwHW+iNufVXX9kQO1nxxbt1TE1tXNBBT6Z3w8IW/JGsWRjgY/KxUERvfXdu5aQqMxF3GmTijPnfP75IYP1MjK58Boa7cTgrpjFx7EYVFRUHfuAv3wYRDHj3uJvLeeVRrmRQoZ+3dcpmRNg8RxY0zhe7PTHszyCAPsuGDcBAbIyE+giBxU5TrAg4njpnMyfvdeY/TbuBsPDgKbDob+7f0ZY+89P/PS+xR/x32WHZWRf5F/rPABHBjMtyQTL60hThpYoYNgDt0OfP6SZiL6u6g2VIyKC+l6ODAlZ+Erm3vfeNCB/Ghgrt3V/sxdRf4zNhK7mSmcbJSYaNR1rrpNM6KiA3mQKeq04mt/x/MOSzNi6PXxGKIfNwYCVtNZzMuxbziP29T27e9Wt32cSw1DIpJ0mjLhbtE4oLAYjqlT41h1QbQzfosXwNXdNlP2xuQE81yWCR6vECzPcaxr6VNt0PP9AgxFDfvCLPhne3j4pF+DZvzdwXO7xuVKO5u6kmcC/hZKGNl7u6CqWJ408A0fHq8nEbQGVOpENVUHS1BxMyDe5iGcJNF4h4Atg14iScyul7FDOR+MKKcRbfdMLsp9qsFddUMk2lzGKq59ePOio8ObzyvLXLBWM6NYG4JtRQRehp5Q3fRD/e9cxarOwDbP89a+Lwm+dw4f22QDLAgcODNjqK8OSKpJ5NbBoRLbgiDKaE245JZtbxPkjNOBO1Gr6H8wVej19bgtKDBSkWI8ksMlse54rx3H0l384e5ho7tjULfH1Y65IyUv4uWC2MbAVkhVYZZX2NdE4czROHegWy25eryxBWLN843eD25HQZgDZtJzWrGMToMAkE/7fWQOwR0+GKzJv/jRD5t/+RjjM8Z39V0v3jomY+5aVg4EeUzkFFtx93W9dKuKVSehAhNMUTUFVzzmU/Lt9h0V+IpyHmbPmwLr1mwBASvHBmBEu7FyOdfxz5+d0Rhwp7olQwdiIhj8KPGScAK9nn7yJAAe1xXQAVsZtJOimtPBQbqTD6T6gdkPAsMx3Tk29oefq+1//JU1ek1r5C8vonMVYmhikyB6NKqHkAdjVsoPc0VsfEbzkxn4GCZWrXiyxT/tmmPhfbWs+tqGPvxm2+CmC8qyFr5rUbQEKAy9wb21h/rXLHXY1iQBZZkL/zox7+I16BGBiifuVUJbt2zZ5bBx/XbkZIdDBz1lHLHawvj5t9bQUBy3PxtBtALMpoyOPmdpZm9eqTshuX6GhOYe2cub7xdx1xSzMKfBRKJjWMOWoJDm5NkcYIpnUSj6wkba8XhFnLAs99Wlzr4/nh0nI8gRQUe1XcUpeW8CpxzBXh6kWiApjLnORB9omb0bDS5nlouGG/cgmKV2JbKKTPaBUwvoNUXfffj9Az9aZRsXrL69nc/9pDRj7rus8lgC2X70iTtVPSyxCuQw8s0svfEhh+CB020NRTItr6iCpVdcjKCnp/fp4fB4e+IT/aHr0ovfULfvaNX21iOYLD+eiqGtsE4nyGfNspWWR36LUgEeS7/UHx9QfgJJzc1GfDBilDkEKPA7xW5qiwpAY08Mwkn0+Aja7HI3ZLl5G0gBzfPLO0O1x8uT06DaemU+VhpnA8r2qfzxT/jsxY9ZWEkU1Ra0EO4axlGRsc58wJdeBXzmvDS98U7fyaVOmBkf2gIVZTf/ubFz1Q97w/Vn2sob3DHv6PCWxRPzlqzvDu2deqj/3UsZ1zFLk++buhZv+W+HBzb+3dQtKxJUTMHHFErHbAfDsEfJCoVkfJJ5/t/8AlxXXm6DZKcLBiDyIsu80lmzIf2Rh8B3z12K6/JLs5Urr8jK/84l6QsrHB6qG9YoB4VDhr9r2Fg8s1SBkgwHxrcktqJpT2PFNQvahzS7GnO8AnQP69Mbu5MzmViAxUG2Mx6r8ParujWSbUVnmAiu1VaojqkA7sOsr4nFhRkcK0souQ7Eqnvwt9gMTCLpp0wQsKId/IixiTGl6Hv3s4FkSmtZBuzuWLnCwHPt6Vh5i45cx47jMarVFl51v4IDIglsVtv9qZXqIkwYPw4E9Gt/SW7ecgeeTWA8lvjrez9SFi98XT5nzjBRZMBUgUoXAQ6B5HJyQCwvA0wcELrvgUcSH2y6lshy1GkklLHfvvEmIs2K0fiIWUGQVm4ZvnvJNO9a5Lm+uEZtsEbFg3FhIG5BMQL7/LbAvZaKqDGmUAksnKy+WuiNz0xEYWKKJkwReJeT2DeO1BjvRChCwPkm29aFc5Xj9iQwelb/R6pQToBHWfeGG0CPtuC15qwpSjtjE3q9c1iVoRGeu+7gil8f6l97EWtX1qLlmQvfrcg+d4thal8418NJs76xV543509WDL0TSrDRdnRC8J5frNYPNueyxMH5fMD5Uf3xL5+eBlYgAJHHn/xx4r31N2LORbUe9Atez5G6jImbaFI/4T4RvNauZMVFj7W/VdeRqHAjMCKLTogcW9lnNM6+657r+tO6fZGLbOAwomVnCh13XFByN5WK2+0gwLjLUBUabrgpVUb8iGey7EkDrEisvm5Z23/bE9bg1gWnTLLRlMiQeBD4YB3wgheml1z/a7QlNJUyKL+v+6W7DSuZxvbFTGvNLv/Rg24pB1xSJq5Zn7sKrBUxMazQWw9PNj5prSWKwpLEfLO7p06orHiK83o2oucLkFhc1CKRKr3x4PfNox2LRr0h2hxLWr78HiWtqp/bfVS2Rm4ao1iPyhPlUEdi5v0BbXd1ofIiKuo6t0wGseLcb+8Lz97fmfx+36BWDA7Ojl+EJ9oDl2XfVlsm9Rv8dU/D4A/Pt0HCgTDan/sxCews5tJmPAlGpAfMBKWJbg8mi5lWYPdNVrS3msi+IeLwBdH7laU8kQc47yTkvThIaKxVzKklaWf+DfPt6y3H1l7ClJWzyZ6AbiUBBWS1yLs3dwb2fKkZRsLenrGpKHXrtqzIUyuf1ZsPXWDPXI7MWNicx6eAYqpMR+01iwMZ6QMZV19+7Uc157/z5H4oXLNruCmpodoiwZfmSn+cN9H90ut7wn8OBfXMlEcceafBTmGOXGPEgvi8Qt/tizKv/u6stA+KfCZylAZq3fUrzK5XH7AtCjfyPMSeyzLYfB0qh8jMHLslTvaHUHkvNAO7LrH6PrzNLlJXQZNQcftk1FfdQC8XyJiFY+5EZa8/Y03DrVuw+gSWKmw/QC26cNx9Z2W4yrYxg/xlFv4XP2VEa2BmDcQdlZV/5vNyt9KkKuN32QiCk1oW5jNttMrwJuUEn59XL02pfdh54bduFGpq6o+ADyxBcvVH9HEZXqHN7xU6a4uV9zH4r67MkVa5nHw8rNOCuE6x72nqxQdWE1YazfGLrVNLlUeWzvBfO61EafTIAmS6MO1YMQQ4uZXzVmNwVbOQ6/LRJ0g2UtRiUyw8a2kipfVwaZOfEUpv/C7nGddAE+05hFg+omS3ECXvIO+b/Fe8aZNwPJjOQjbvh+ev7B6OH5nUH2mYyIyzjtGrKveCl2eW3PAo84GKmPalVmJGorZvw1gGNBwGCwkfjTOYwaDfGhgqtwYH8oRJE71G6xGNc7kGkAPbhKKCTmqYFidjCikqhsi4GoiYPLy2K2i/GTPxASuyJZYaYPfROHgVHi2KJaPCVh05po0tzXK4WvrVWJpTaKstkptVgyaZ10OgobpAgaosC3gzDEbXy1itHlsArODePJroGg+cmA1ShkCDdRHOXdVNlKJm4J1RgsEdI1rKxjBetNsdRc4/PfUeFo1wCIHiMY4l9EDWOw3LtwfjHWM5HACek5JXzXz9zBxPdT3y3z84DT/amriiSQ5ymRm7mUTKs84ElVULjh77TJnxRZNMUWBYNzGHktDZew2aAg9/163UjDHrziQKARZassAn7sMQsm9epdt+Ac7eZ3D29JXF8u1nGPLUjBwqbS8o+b1ELsB2LEXK60HDlZt6l8HaDJNCamJUZ2Q0IijoPpDnVAQohsIi4N0yq1HX9cItg9GWsRIOjIZcODZrwes+pag+ovb9c+8wTk4RwOIWtjQzxsga+AA09bIFvvpbMHtcRkBlsY2BzOyjRU9xFp+zMED0FFAmVgdF2rOYP/3suTmCALJfVTkHWIUJeO+RZG/BgZ6/3MDakymuJHgTZZnzH+gO7jnlvwn+OfD+xReClchmS2JoOZIINMdeIyBn7+p4+o6o2pfDlFbDFp+Uu/T5MRlzGnQj/s+/PfvXX5jYYKuKXoh6qzGwOFJA4t/B6CcTDvWtuZ4nDrvKZNGfQN/3hAd9nSGq/w8e4wDVX4vrNPtfQHibA3lgbdrU9+aVlqWbiujvxjThrs6/ZGWOt7qBTXT+I8v/CjAAJOOJ0FaTyhsAAAAASUVORK5CYII=');}\";\n    var actual = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    // console.log(actual);\n    expect(actual).to.equal(expected);\n};\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-type/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-type/foo.css",
    "content": ".foo {background-image: url(ebay-logo.png);}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-type/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-custom-type/test.js",
    "content": "const fs = require('fs');\nconst expect = require('chai').expect;\nconst path = require('path');\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        urlPrefix: '/static',\n        bundlingEnabled: true,\n        plugins: [\n            {\n                plugin: function(theLasso) {\n                    theLasso.dependencies.registerStyleSheetType('foo', {\n                        properties: {\n                            'path': 'string'\n                        },\n\n                        async init (lassoContext) {\n                            this.path = this.resolvePath(this.path);\n                        },\n\n                        async read (lassoContext) {\n                            const css = await fs.promises.readFile(this.path, 'utf8');\n                            return css;\n                        },\n\n                        getSourceFile: function() {\n                            return this.path;\n                        },\n\n                        async getLastModified (lassoContext) {\n                            return -1;\n                        }\n                    });\n                }\n            }\n        ]\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            {\n                type: 'foo',\n                path: path.join(__dirname, 'foo.css')\n            }\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var expected = '.foo {background-image: url(\\'ebay-logo-d481eb85.png\\');}';\n    var actual = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    // console.log(actual);\n    expect(actual).to.equal(expected);\n};\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-fingerprints/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-fingerprints/foo.css",
    "content": ".foo {\n    url-relative:url(ebay.png);\n    url-dot-relative:url(./ebay.png);\n    installed:url(installed/ebay.png);\n    installed-require-prefix:url(require: installed/ebay.png);\n    installed-require-prefix:url('http://foo.void/ebay.png');\n    absolute:url(/ebay.png);\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-fingerprints/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-fingerprints/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var cssCode = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    expect(cssCode).to.contain('url-relative:url(\\'ebay-1cace448.png\\')');\n    expect(cssCode).to.contain('installed:url(\\'ebay-1cace448.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'ebay-1cace448.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'http://foo.void/ebay.png\\')');\n    expect(cssCode).to.contain('absolute:url(\\'ebay-1cace448.png\\')');\n};"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-bundling/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-bundling/foo.css",
    "content": ".foo {\n    url-relative:url(ebay.png);\n    url-dot-relative:url(./ebay.png);\n    installed:url(installed/ebay.png);\n    installed-require-prefix:url(require: installed/ebay.png);\n    installed-require-prefix:url('http://foo.void/ebay.png');\n    absolute:url(/ebay.png);\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-bundling/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-bundling/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: false\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var cssCode = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    expect(cssCode).to.contain('url-relative:url(\\'ebay.png\\')');\n    expect(cssCode).to.contain('url-dot-relative:url(\\'ebay.png\\')');\n    expect(cssCode).to.contain('installed:url(\\'../installed$1.0.0/ebay.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'../installed$1.0.0/ebay.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'http://foo.void/ebay.png\\')');\n    expect(cssCode).to.contain('absolute:url(\\'ebay.png\\')');\n};"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-fingerprints/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-fingerprints/foo.css",
    "content": ".foo {\n    url-relative:url(ebay.png);\n    url-dot-relative:url(./ebay.png);\n    installed:url(installed/ebay.png);\n    installed-require-prefix:url(require: installed/ebay.png);\n    installed-require-prefix:url('http://foo.void/ebay.png');\n    absolute:url(/ebay.png);\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-fingerprints/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-fingerprints/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: false,\n        bundlingEnabled: true\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var cssCode = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    expect(cssCode).to.contain('url-relative:url(\\'transforms-transform-css-urls-no-fingerprints/autotest$0.0.0/ebay.png\\')');\n    expect(cssCode).to.contain('url-dot-relative:url(\\'transforms-transform-css-urls-no-fingerprints/autotest$0.0.0/ebay.png\\')');\n    expect(cssCode).to.contain('installed:url(\\'transforms-transform-css-urls-no-fingerprints/installed$1.0.0/ebay.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'transforms-transform-css-urls-no-fingerprints/installed$1.0.0/ebay.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'http://foo.void/ebay.png\\')');\n    expect(cssCode).to.contain('absolute:url(\\'transforms-transform-css-urls-no-fingerprints/autotest$0.0.0/ebay.png\\')');\n};"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-relative/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.css\"\n    ]\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-relative/foo.css",
    "content": ".foo {\n    url-relative:url(ebay.png);\n    url-dot-relative:url(./ebay.png);\n    installed:url(installed/ebay.png);\n    installed-require-prefix:url(require: installed/ebay.png);\n    installed-require-prefix:url('http://foo.void/ebay.png');\n    absolute:url(/ebay.png);\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-relative/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-no-relative/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true,\n        urlPrefix: 'https://cdn.example.net/build',\n        relativeUrlsEnabled: false\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var cssCode = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    expect(cssCode).to.contain('url-relative:url(\\'https://cdn.example.net/build/ebay-1cace448.png\\')');\n    expect(cssCode).to.contain('installed:url(\\'https://cdn.example.net/build/ebay-1cace448.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'https://cdn.example.net/build/ebay-1cace448.png\\')');\n    expect(cssCode).to.contain('installed-require-prefix:url(\\'http://foo.void/ebay.png\\')');\n    expect(cssCode).to.contain('absolute:url(\\'https://cdn.example.net/build/ebay-1cace448.png\\')');\n};\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-require/browser.json",
    "content": "{\n    \"dependencies\": [\n        \"./foo.css\"\n    ]\n}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-require/foo.css",
    "content": ".test-1 {background-image: url(require:assets/ebay-logo.png);}\n.test-2 {background-image: url(\"require:assets/ebay-logo.png\");}\n.test-3 {background-image: url('require:assets/ebay-logo.png');}\n.test-4 {background-image: url('require:assets/ebay-logo.png?base64');}"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-require/package.json",
    "content": "{\n    \"name\": \"autotest\",\n    \"version\": \"0.0.0\"\n}\n"
  },
  {
    "path": "test/autotests/transforms/transform-css-urls-require/test.js",
    "content": "var expect = require('chai').expect;\n\nexports.getLassoConfig = function() {\n    return {\n        fingerprintsEnabled: true,\n        bundlingEnabled: true\n    };\n};\n\nexports.getLassoOptions = function() {\n    return {\n        dependencies: [\n            './browser.json'\n        ]\n    };\n};\n\nexports.check = function(lassoPageResult, writerTracker) {\n    var expected = \".test-1 {background-image: url('ebay-logo-d481eb85.png');}\\n.test-2 {background-image: url('ebay-logo-d481eb85.png');}\\n.test-3 {background-image: url('ebay-logo-d481eb85.png');}\\n.test-4 {background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAE8AAAAeCAYAAABt5kPUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpGNzdGMTE3NDA3MjA2ODExODhDNkIzODA1MTg5Nzc0NiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRTg2MEMyMzZFNzIxMUUyQjZGMEE2ODM0MDRENkNFNiIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRTg2MEMyMjZFNzIxMUUyQjZGMEE2ODM0MDRENkNFNiIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAyODAxMTc0MDcyMDY4MTE5OTRDOTI2RkUxMEEyMEJFIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkY3N0YxMTc0MDcyMDY4MTE4OEM2QjM4MDUxODk3NzQ2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Yff30gAAE/BJREFUeNrsWgdwHdW5/s+Wu7u3q3fJspqLLMuVYINt3AgQwjPFYCCN+ogpLyRgCKQHAo/H8OAFhgAOxQQCDt3E2Bg74IK7ZMuyZCFbVpescnvZet5/9kpuhJbMvJkwb2d2tPferd/5/6+cFTHDESCiAPrBZjD7+oBqOpjHjoE5MACEFwAoBbZwGekgDh2D95QJ8HthGsjUAAKpheCGYYJ3b0fibwmd5nIERPx6A67L4KRF1SlU5jhgdrkTMj0C9IcN0A0K00oUEHkCPicP51S5QBIIuPg48Byet3OVfQ/UiADoIaBmDAjnAOCdQNVjAIIXvx8CIuUCWDoQORe2awPQFjsEeDjgkXifBM4uuwPSXaVg4j5w/L45SOpBSGgBe3t04QgPCT0AezqfxedS7d84wYLAUR+0bckHt1eG1tZWEOArLCrl4JtGK+wX8+CteC64iXESeJQLxoxCVaNZI6hmn3KwScGp8AicC9wyB5YF//IL91V2ZjVocRzc7DkM1WQINBwhrLKRFcf3xIdTV1zcLgEunOKzgUOg4euwcF/1AB148BlxuNnVCg5sNevL4IBVdn6NB4rSBLtNvy7LVwaPYP0lsH2neeKwNHMYt/kvQJvCTOS4ylwJ1K8RcJ8LHmFExiMwAg9EEGxRIewzx9sUrJkAV+aFoMRpgGaRv38SBKsgU4SFEzw2xzEBEFEMHCMrjy1NyAlK+OKRI6lbJkjVTDQ4MbWyz0ghx0/2f7R8SjCIQ0SgRFQyLY1Go8X4Nx2o5eKiUdOKxUK839/NeT1dpiiZaQ4KF/sG4L9juSAR+imCJNjWy85IA7+Tg56g4R2ImGM1w8hCBXQqDi6uGdCriOSw7OASo6r+aaKlKWA4CewNI1xI9WGUVuLHvwrwLg3MRBDB7CO8sxN4WTeZvAKhKQVlQ41qyQmfw+T0lOGzFRovRXBQCIoi27ZoAp/QoDwWkMCKCQdKOH48qyoETW9sWpDcum252d19NtqWDGR3QmlKGklqnyTn9x+QamueETPTn7+owpVcbwpwsFc9rV0tmD/JA1V5jsJnPgqsaOxJXhLTrDzKxILa/Y9FTCyXxB0NJczn51a6/ifTLQTo6Q+GFYY2xWsNbbneCuy8mmoDVWhJFJtsT/ZKRFSJI6NFSJ/1TH76zNf3q70PmVogEwE0TEuTA/G236Q7x240QT+NhpjoiadYFQEHKqAdre0N1f8nY2zTUuUxOdO3e8xpdx1q2XpOfkEur6pqXLAvLOENqmp69NkXntEbDy6hoz4Cb9BuVyHl96iOF1ZV2Uwkpse7u6dr9ftvybnthisvO6N6/89f6z4xdrjh9QrJbJ940YrVfc8OB/Q0+3uejN6xbV3w9FzENMe+sSP4q43N0RtvW5h5zaKJ7nW2qLCH4SW8r77pRusjq6kaGPOpFmYrq0xbtTSJJnon6V2vPTo23PCDAjmD1qv9UySsGt2MQ33ni9rYjHkbUxenI0VtIX24kUpcp5zagR7yo8MP3RWMty0SeRceH4N8z4wXnJXzoHn80ODWbVtkrL4wsQJBMEMhX+Dun72t7ambQ1xoPjUNhMKCFqGs7GUEb5tjSu2QfviIYg0PT7IGBy/RDjYvYFXI9nNkZ/UIv71vwXVNBe1v7RpuN030ebh4ndwAMUEIhfU0t1ccnlysvJbvEz6qLZL7mvpUX+ewPqOpV7302LBeBiKxhUUUifb0NYWXXzHD9yanDwKvduWpO5ZspdGOUpswcVCJq2Q3cZWu4pxj6jhvTcIc3OgDU51mRVuW0Wh7LdtPwP2GRG/yRYciayMiZ6GpXzL5qXNLM+atZ2B+Jo9xMgxEmya/smfZdjTUskl1yPZM+Pjs8jvPzvFXmI07huGee39qA8/fe8stEHniD/+V2PDBZZzXyyoQHNOmrnZf+/3zxNKS98E0Dztqa3rx+w4hP2+3cu6iFzi3O6w3NZ/LKtIMBDyewe6K3qlz31zXoi3Hs7rZ4GKacKkJUynOk3f++zkZi8+ucK3yO/n9U4udR3DcmypypA2LJ3pWRlSrpKNfq2EAWjrlt7bE586f6FudLx4JmS0P3mn2b7uIUR4THy5nzjpH5Z0LEIuPiZTdQfy1PZDsbeP8tVuFwiuepdqxGTR6tNxCAH1WUohzkt7O8RxrL2w9TA3D+eNyL3xhlIb+3sIjTXzY+sDDvaG6qQJWPgN9TvmdNxf6pzezM7W19sLmzZtTaqs1NFYmNmz8AQICNJkER82knRmPP/odPj09ru1rAO1gEyTWbwBtbx1oBxrBCobAe+vyR5Tzzn2c7U9cLlD31J87vuXjC0GW4ycnivICueW15SXfqi6Q25DX0KpYkMSVWZaoaoFX5mLPXVN49Xm1njcAPzMAB4J63gNrB++JJC0k5LjKp1Vu5HzVa7i0ce/zuRf8EiE0wIiihiUAwo0AiS6wjq3HLhjUhMJl9yJ3W/gjwxqmyAUNHimrgwEg8Ap0BrYvwHW+iNufVXX9kQO1nxxbt1TE1tXNBBT6Z3w8IW/JGsWRjgY/KxUERvfXdu5aQqMxF3GmTijPnfP75IYP1MjK58Boa7cTgrpjFx7EYVFRUHfuAv3wYRDHj3uJvLeeVRrmRQoZ+3dcpmRNg8RxY0zhe7PTHszyCAPsuGDcBAbIyE+giBxU5TrAg4njpnMyfvdeY/TbuBsPDgKbDob+7f0ZY+89P/PS+xR/x32WHZWRf5F/rPABHBjMtyQTL60hThpYoYNgDt0OfP6SZiL6u6g2VIyKC+l6ODAlZ+Erm3vfeNCB/Ghgrt3V/sxdRf4zNhK7mSmcbJSYaNR1rrpNM6KiA3mQKeq04mt/x/MOSzNi6PXxGKIfNwYCVtNZzMuxbziP29T27e9Wt32cSw1DIpJ0mjLhbtE4oLAYjqlT41h1QbQzfosXwNXdNlP2xuQE81yWCR6vECzPcaxr6VNt0PP9AgxFDfvCLPhne3j4pF+DZvzdwXO7xuVKO5u6kmcC/hZKGNl7u6CqWJ408A0fHq8nEbQGVOpENVUHS1BxMyDe5iGcJNF4h4Atg14iScyul7FDOR+MKKcRbfdMLsp9qsFddUMk2lzGKq59ePOio8ObzyvLXLBWM6NYG4JtRQRehp5Q3fRD/e9cxarOwDbP89a+Lwm+dw4f22QDLAgcODNjqK8OSKpJ5NbBoRLbgiDKaE245JZtbxPkjNOBO1Gr6H8wVej19bgtKDBSkWI8ksMlse54rx3H0l384e5ho7tjULfH1Y65IyUv4uWC2MbAVkhVYZZX2NdE4czROHegWy25eryxBWLN843eD25HQZgDZtJzWrGMToMAkE/7fWQOwR0+GKzJv/jRD5t/+RjjM8Z39V0v3jomY+5aVg4EeUzkFFtx93W9dKuKVSehAhNMUTUFVzzmU/Lt9h0V+IpyHmbPmwLr1mwBASvHBmBEu7FyOdfxz5+d0Rhwp7olQwdiIhj8KPGScAK9nn7yJAAe1xXQAVsZtJOimtPBQbqTD6T6gdkPAsMx3Tk29oefq+1//JU1ek1r5C8vonMVYmhikyB6NKqHkAdjVsoPc0VsfEbzkxn4GCZWrXiyxT/tmmPhfbWs+tqGPvxm2+CmC8qyFr5rUbQEKAy9wb21h/rXLHXY1iQBZZkL/zox7+I16BGBiifuVUJbt2zZ5bBx/XbkZIdDBz1lHLHawvj5t9bQUBy3PxtBtALMpoyOPmdpZm9eqTshuX6GhOYe2cub7xdx1xSzMKfBRKJjWMOWoJDm5NkcYIpnUSj6wkba8XhFnLAs99Wlzr4/nh0nI8gRQUe1XcUpeW8CpxzBXh6kWiApjLnORB9omb0bDS5nlouGG/cgmKV2JbKKTPaBUwvoNUXfffj9Az9aZRsXrL69nc/9pDRj7rus8lgC2X70iTtVPSyxCuQw8s0svfEhh+CB020NRTItr6iCpVdcjKCnp/fp4fB4e+IT/aHr0ovfULfvaNX21iOYLD+eiqGtsE4nyGfNspWWR36LUgEeS7/UHx9QfgJJzc1GfDBilDkEKPA7xW5qiwpAY08Mwkn0+Aja7HI3ZLl5G0gBzfPLO0O1x8uT06DaemU+VhpnA8r2qfzxT/jsxY9ZWEkU1Ra0EO4axlGRsc58wJdeBXzmvDS98U7fyaVOmBkf2gIVZTf/ubFz1Q97w/Vn2sob3DHv6PCWxRPzlqzvDu2deqj/3UsZ1zFLk++buhZv+W+HBzb+3dQtKxJUTMHHFErHbAfDsEfJCoVkfJJ5/t/8AlxXXm6DZKcLBiDyIsu80lmzIf2Rh8B3z12K6/JLs5Urr8jK/84l6QsrHB6qG9YoB4VDhr9r2Fg8s1SBkgwHxrcktqJpT2PFNQvahzS7GnO8AnQP69Mbu5MzmViAxUG2Mx6r8ParujWSbUVnmAiu1VaojqkA7sOsr4nFhRkcK0souQ7Eqnvwt9gMTCLpp0wQsKId/IixiTGl6Hv3s4FkSmtZBuzuWLnCwHPt6Vh5i45cx47jMarVFl51v4IDIglsVtv9qZXqIkwYPw4E9Gt/SW7ecgeeTWA8lvjrez9SFi98XT5nzjBRZMBUgUoXAQ6B5HJyQCwvA0wcELrvgUcSH2y6lshy1GkklLHfvvEmIs2K0fiIWUGQVm4ZvnvJNO9a5Lm+uEZtsEbFg3FhIG5BMQL7/LbAvZaKqDGmUAksnKy+WuiNz0xEYWKKJkwReJeT2DeO1BjvRChCwPkm29aFc5Xj9iQwelb/R6pQToBHWfeGG0CPtuC15qwpSjtjE3q9c1iVoRGeu+7gil8f6l97EWtX1qLlmQvfrcg+d4thal8418NJs76xV543509WDL0TSrDRdnRC8J5frNYPNueyxMH5fMD5Uf3xL5+eBlYgAJHHn/xx4r31N2LORbUe9Atez5G6jImbaFI/4T4RvNauZMVFj7W/VdeRqHAjMCKLTogcW9lnNM6+657r+tO6fZGLbOAwomVnCh13XFByN5WK2+0gwLjLUBUabrgpVUb8iGey7EkDrEisvm5Z23/bE9bg1gWnTLLRlMiQeBD4YB3wgheml1z/a7QlNJUyKL+v+6W7DSuZxvbFTGvNLv/Rg24pB1xSJq5Zn7sKrBUxMazQWw9PNj5prSWKwpLEfLO7p06orHiK83o2oucLkFhc1CKRKr3x4PfNox2LRr0h2hxLWr78HiWtqp/bfVS2Rm4ao1iPyhPlUEdi5v0BbXd1ofIiKuo6t0wGseLcb+8Lz97fmfx+36BWDA7Ojl+EJ9oDl2XfVlsm9Rv8dU/D4A/Pt0HCgTDan/sxCews5tJmPAlGpAfMBKWJbg8mi5lWYPdNVrS3msi+IeLwBdH7laU8kQc47yTkvThIaKxVzKklaWf+DfPt6y3H1l7ClJWzyZ6AbiUBBWS1yLs3dwb2fKkZRsLenrGpKHXrtqzIUyuf1ZsPXWDPXI7MWNicx6eAYqpMR+01iwMZ6QMZV19+7Uc157/z5H4oXLNruCmpodoiwZfmSn+cN9H90ut7wn8OBfXMlEcceafBTmGOXGPEgvi8Qt/tizKv/u6stA+KfCZylAZq3fUrzK5XH7AtCjfyPMSeyzLYfB0qh8jMHLslTvaHUHkvNAO7LrH6PrzNLlJXQZNQcftk1FfdQC8XyJiFY+5EZa8/Y03DrVuw+gSWKmw/QC26cNx9Z2W4yrYxg/xlFv4XP2VEa2BmDcQdlZV/5vNyt9KkKuN32QiCk1oW5jNttMrwJuUEn59XL02pfdh54bduFGpq6o+ADyxBcvVH9HEZXqHN7xU6a4uV9zH4r67MkVa5nHw8rNOCuE6x72nqxQdWE1YazfGLrVNLlUeWzvBfO61EafTIAmS6MO1YMQQ4uZXzVmNwVbOQ6/LRJ0g2UtRiUyw8a2kipfVwaZOfEUpv/C7nGddAE+05hFg+omS3ECXvIO+b/Fe8aZNwPJjOQjbvh+ev7B6OH5nUH2mYyIyzjtGrKveCl2eW3PAo84GKmPalVmJGorZvw1gGNBwGCwkfjTOYwaDfGhgqtwYH8oRJE71G6xGNc7kGkAPbhKKCTmqYFidjCikqhsi4GoiYPLy2K2i/GTPxASuyJZYaYPfROHgVHi2KJaPCVh05po0tzXK4WvrVWJpTaKstkptVgyaZ10OgobpAgaosC3gzDEbXy1itHlsArODePJroGg+cmA1ShkCDdRHOXdVNlKJm4J1RgsEdI1rKxjBetNsdRc4/PfUeFo1wCIHiMY4l9EDWOw3LtwfjHWM5HACek5JXzXz9zBxPdT3y3z84DT/amriiSQ5ymRm7mUTKs84ElVULjh77TJnxRZNMUWBYNzGHktDZew2aAg9/163UjDHrziQKARZassAn7sMQsm9epdt+Ac7eZ3D29JXF8u1nGPLUjBwqbS8o+b1ELsB2LEXK60HDlZt6l8HaDJNCamJUZ2Q0IijoPpDnVAQohsIi4N0yq1HX9cItg9GWsRIOjIZcODZrwes+pag+ovb9c+8wTk4RwOIWtjQzxsga+AA09bIFvvpbMHtcRkBlsY2BzOyjRU9xFp+zMED0FFAmVgdF2rOYP/3suTmCALJfVTkHWIUJeO+RZG/BgZ6/3MDakymuJHgTZZnzH+gO7jnlvwn+OfD+xReClchmS2JoOZIINMdeIyBn7+p4+o6o2pfDlFbDFp+Uu/T5MRlzGnQj/s+/PfvXX5jYYKuKXoh6qzGwOFJA4t/B6CcTDvWtuZ4nDrvKZNGfQN/3hAd9nSGq/w8e4wDVX4vrNPtfQHibA3lgbdrU9+aVlqWbiujvxjThrs6/ZGWOt7qBTXT+I8v/CjAAJOOJ0FaTyhsAAAAASUVORK5CYII=');}\";\n    var actual = writerTracker.getCodeForPath(lassoPageResult.getCSSFiles()[0]);\n    // console.log(actual);\n    expect(actual).to.equal(expected);\n};"
  },
  {
    "path": "test/autotests/util/caching-replay-stream/.gitignore",
    "content": "/build"
  },
  {
    "path": "test/autotests/util/caching-replay-stream/hello.txt",
    "content": "Hello World!!\n"
  },
  {
    "path": "test/autotests/util/caching-replay-stream/test.js",
    "content": "var expect = require('chai').expect;\nvar fs = require('fs');\nvar nodePath = require('path');\n\nexports.check = function (util) {\n    var cachingStream = util.createCachingStream();\n\n    var outputDir = nodePath.join(__dirname, 'build');\n\n    require('../../../util').rmdirRecursive(outputDir);\n\n    fs.mkdirSync(outputDir);\n\n    var inFile = nodePath.join(__dirname, 'hello.txt');\n    var outFile1 = nodePath.join(outputDir, 'hello-1.txt');\n    var outFile2 = nodePath.join(outputDir, 'hello-2.txt');\n\n    var readStream = fs.createReadStream(inFile);\n    var outStream = fs.createWriteStream(outFile1);\n\n    return new Promise((resolve, reject) => {\n        outStream.on('close', function() {\n            outStream = fs.createWriteStream(outFile2);\n            outStream.on('close', function() {\n                var inTxt = fs.readFileSync(inFile, {encoding: 'utf8'});\n                var outFile1Txt = fs.readFileSync(outFile1, {encoding: 'utf8'});\n                var outFile2Txt = fs.readFileSync(outFile2, {encoding: 'utf8'});\n                expect(inTxt).to.equal(outFile1Txt);\n                expect(inTxt).to.equal(outFile2Txt);\n                resolve();\n            });\n\n            cachingStream.createReplayStream().pipe(outStream);\n        });\n\n        readStream.pipe(cachingStream).pipe(outStream);\n    });\n};\n"
  },
  {
    "path": "test/builtins-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nvar chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nvar expect = require('chai').expect;\nvar createLassoContext = require('./mock/create-lasso-context');\n\ndescribe('lasso-require/builtins' , function() {\n    it('should correctly resolve default builtins', function() {\n        var fromDir = __dirname;\n        var lassoContext = createLassoContext();\n\n        expect(lassoContext.resolve('assert', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('buffer', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('events', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('path', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('process', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('stream', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('util', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('lasso-loader', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('raptor-loader', fromDir) != null).to.equal(true);\n        expect(lassoContext.resolve('string_decoder', fromDir) != null).to.equal(true);\n    });\n\n    it('should allow custom builtins', function() {\n        var fromDir = __dirname;\n        var lassoContext = createLassoContext({\n            resolver: {\n                builtins: {\n                    foo: require.resolve('./fixtures/builtin-foo')\n                }\n            }\n        });\n\n        expect(lassoContext.resolve('foo', fromDir) != null).to.equal(true);\n        expect(() => lassoContext.resolve('bar', fromDir)).to.throw();\n    });\n\n    it('should allow custom builtins (legacy)', function() {\n        var fromDir = __dirname;\n        var lassoContext = createLassoContext({\n            require: {\n                builtins: {\n                    foo: require.resolve('./fixtures/builtin-foo')\n                }\n            }\n        });\n\n        expect(lassoContext.resolve('foo', fromDir) != null).to.equal(true);\n        expect(() => lassoContext.resolve('bar', fromDir)).to.throw();\n    });\n\n    //\n    // it('should allow additional builtins', function() {\n    //\n    //     var builtins = require('../lib/builtins').getBuiltins({\n    //         foo: require.resolve('./fixtures/foo-shim')\n    //     });\n    //     expect(builtins.buffer).to.contain('node_modules/buffer-browserify');\n    //     expect(builtins.events).to.contain('node_modules/events');\n    //     expect(builtins.foo).to.contain('foo-shim.js');\n    //\n    //     // console.log('builtins:', builtins);\n    // });\n});\n"
  },
  {
    "path": "test/bundling-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst WriterTracker = require('./util/WriterTracker');\nconst rmdirRecursive = require('./util').rmdirRecursive;\nconst buildDir = nodePath.join(__dirname, 'build');\nconst lasso = require('lasso');\nconst Readable = require('stream').Readable;\nconst urlReader = require('lasso/util/url-reader');\n\nurlReader.createUrlReadStream = function(url) {\n    var readable = new Readable();\n    readable.push('EXTERNAL:' + url);\n    readable.push(null);\n    return readable;\n};\n\ndescribe('lasso/bundling' , function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/bundling'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var testName = nodePath.basename(dir);\n            var pageName = 'bundling-' + testName;\n\n            var lassoConfig = main.getLassoConfig && main.getLassoConfig();\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            if (!lassoConfig.outputDir) {\n                lassoConfig.outputDir = nodePath.join(buildDir, pageName);\n            }\n\n            rmdirRecursive(lassoConfig.outputDir);\n\n            var myLasso = lasso.create(lassoConfig, dir);\n\n            var inputs;\n\n            if (main.getInputs) {\n                inputs = main.getInputs();\n            } else {\n                let lassoOptions = main.getLassoOptions(dir) || {};\n                let check = main.check;\n\n                inputs = [\n                    {\n                        lassoOptions,\n                        check\n                    }\n                ];\n            }\n\n            for (const input of inputs) {\n                var writerTracker = WriterTracker.create(myLasso.writer);\n\n                var lassoOptions = input.lassoOptions;\n                var check = input.check;\n                var checkError = input.checkError;\n\n                if (!lassoOptions.pageName) {\n                    lassoOptions.pageName = pageName;\n                }\n\n                if (!lassoOptions.from) {\n                    lassoOptions.from = dir;\n                }\n\n                let lassoPageResult;\n                try {\n                    lassoPageResult = await myLasso.lassoPage(lassoOptions);\n                } catch (err) {\n                    if (checkError) {\n                        checkError(err);\n                    } else {\n                        throw err;\n                    }\n                }\n\n                if (checkError) {\n                    throw new Error('Error expected');\n                }\n\n                check(lassoPageResult, writerTracker, helpers);\n                await lasso.flushAllCaches();\n            }\n        });\n});\n"
  },
  {
    "path": "test/dep-require-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nconst createLassoContext = require('./mock/create-lasso-context');\nconst normalizeOutput = require('./util/normalizeOutput');\nconst moduleSearchPath = require('./util/module-search-path');\n\nconst rootDir = nodePath.join(__dirname, '..');\n\ndescribe('lasso-require/dependency-require' , function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dep-require'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {};\n\n            pluginConfig.rootDir = dir;\n\n            var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig);\n\n            var patchedSearchPath;\n            if (main.searchPath) {\n                patchedSearchPath = moduleSearchPath.patchSearchPath(main.searchPath);\n            }\n\n            var dependencyDef = main.createDependency(dir);\n            var dependency = dependencyFactory.depRequire(dependencyDef, dir);\n\n            var lassoContext = createLassoContext();\n            dependency.init(lassoContext);\n\n            try {\n                let dependencies = await dependency.getDependencies(lassoContext);\n                dependencies = normalizeOutput(dependencies, rootDir);\n\n                if (patchedSearchPath) {\n                    patchedSearchPath.restore();\n                }\n\n                helpers.compare(dependencies, '.json');\n            } catch (err) {\n                if (patchedSearchPath) {\n                    patchedSearchPath.restore();\n                }\n                throw err;\n            }\n        });\n});\n"
  },
  {
    "path": "test/dep-transport-define-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nconst createLassoContext = require('./mock/create-lasso-context');\nconst moduleSearchPath = require('./util/module-search-path');\nconst normalizeOutput = require('./util/normalizeOutput');\n\ndescribe('lasso-require/dep-transport-define' , function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dep-transport-define'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var dependencyProps = main.createDependency(dir);\n\n            var patchedSearchPath;\n            if (main.searchPath) {\n                patchedSearchPath = moduleSearchPath.patchSearchPath(main.searchPath);\n            }\n\n            var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {};\n            pluginConfig.rootDir = dir;\n\n            var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig);\n\n            var dependency = dependencyFactory.depRequire(dependencyProps);\n\n            var lassoContext = createLassoContext();\n\n            dependency.init(lassoContext);\n\n            let dependencies = await dependency.getDependencies(lassoContext);\n\n            if (dependencies.dependencies) {\n                dependencies = dependencies.dependencies;\n            }\n\n            let src;\n\n            try {\n                for (var i=0; i<dependencies.length; i++) {\n                    var d = dependencies[i];\n                    if (d.type === 'commonjs-def') {\n                        var defDependency = dependencyFactory.depTransportDefine(d);\n                        src = await defDependency.read(lassoContext);\n                        break;\n                    }\n                }\n\n                if (!src) {\n                    throw new Error('commonjs-def dependency not found');\n                }\n\n                if (patchedSearchPath) {\n                    patchedSearchPath.restore();\n                }\n\n                src = normalizeOutput(src, dir);\n                helpers.compare(src, '.js');\n            } catch (err) {\n                if (patchedSearchPath) {\n                    patchedSearchPath.restore();\n                }\n                throw err;\n            }\n        });\n});\n"
  },
  {
    "path": "test/dep-transport-installed-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nconst MockLassoContext = require('./mock/MockLassoContext');\n\ndescribe('lasso-require/dep-transport-installed' , function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dep-transport-installed'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var dependencyProps = main.createDependency(dir);\n\n            var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {};\n            pluginConfig.rootDir = dir;\n\n            var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig);\n            var dependency = dependencyFactory.depTransportInstalled(dependencyProps);\n            var lassoContext = new MockLassoContext();\n\n            dependency.init(lassoContext);\n\n            const src = await dependency.read(lassoContext);\n            helpers.compare(src, '.js');\n        });\n});\n"
  },
  {
    "path": "test/dep-transport-main-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nconst MockLassoContext = require('./mock/MockLassoContext');\n\ndescribe('lasso-require/dep-transport-main', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dep-transport-main'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var dependencyProps = main.createDependency(dir);\n            var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {};\n\n            pluginConfig.rootDir = dir;\n\n            var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig);\n            var dependency = dependencyFactory.depTransportMain(dependencyProps);\n            var lassoContext = new MockLassoContext();\n\n            dependency.init(lassoContext);\n\n            const src = await dependency.read(lassoContext);\n            helpers.compare(src, '.js');\n        });\n});\n"
  },
  {
    "path": "test/dep-transport-ready-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nconst MockLassoContext = require('./mock/MockLassoContext');\n\ndescribe('lasso-require/dep-transport-ready', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dep-transport-ready'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var dependencyProps = main.createDependency(dir);\n\n            var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {};\n            pluginConfig.rootDir = dir;\n\n            var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig);\n\n            var dependency = dependencyFactory.depTransportReady(dependencyProps);\n\n            var lassoContext = new MockLassoContext();\n\n            dependency.init(lassoContext);\n\n            const src = await dependency.read(lassoContext);\n            helpers.compare(src, '.js');\n        });\n});\n"
  },
  {
    "path": "test/dep-transport-remap-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nconst MockLassoContext = require('./mock/MockLassoContext');\n\ndescribe('lasso-require/dep-transport-remap', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dep-transport-remap'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var dependencyProps = main.createDependency(dir);\n            var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {};\n\n            pluginConfig.rootDir = dir;\n\n            var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig);\n            var dependency = dependencyFactory.depTransportRemap(dependencyProps);\n            var lassoContext = new MockLassoContext();\n\n            dependency.init(lassoContext);\n\n            const src = await dependency.read(lassoContext);\n            helpers.compare(src, '.js');\n        });\n});\n"
  },
  {
    "path": "test/dep-transport-run-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nrequire('chai').should();\nconst MockLassoContext = require('./mock/MockLassoContext');\n\ndescribe('lasso-require/dep-transport-run' , function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dep-transport-run'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var dependencyProps = main.createDependency(dir);\n            var pluginConfig = main.getPluginConfig ? main.getPluginConfig() : {};\n\n            pluginConfig.rootDir = dir;\n\n            var dependencyFactory = require('./mock/dependency-factory').create(pluginConfig);\n            var dependency = dependencyFactory.depTransportRun(dependencyProps);\n            var lassoContext = new MockLassoContext();\n\n            dependency.init(lassoContext);\n\n            const src = await dependency.read(lassoContext);\n            helpers.compare(src, '.js');\n        });\n});\n"
  },
  {
    "path": "test/dependency-walker-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\nconst ok = require('assert').ok;\nconst normalizeOutput = require('./util/normalizeOutput');\n\nconst DependencyTree = require('lasso/DependencyTree');\nconst lasso = require('lasso');\n\ndescribe('lasso/dependency-walker', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/dependency-walker'),\n        async function (dir, helpers) {\n            var dependencyWalker = require('lasso/dependency-walker');\n            var LassoManifest = require('lasso/LassoManifest');\n\n            var tree = new DependencyTree();\n\n            var main = require(nodePath.join(dir, 'test.js'));\n\n            var dependencies = main.getDependencies(dir);\n            var dependencyRegistry = lasso.getDefaultLasso().getDependencyRegistry();\n            ok(dependencyRegistry);\n\n            var flags;\n            if (main.getFlags) {\n                flags = main.getFlags(dir);\n            }\n\n            var lassoContext = lasso.getDefaultLasso().createLassoContext({\n                flags: flags\n            });\n\n            var lassoManifest = new LassoManifest({\n                manifest: {\n                    dependencies\n                },\n                dependencyRegistry: dependencyRegistry,\n                dirname: dir\n            });\n\n            var walkOptions = {};\n            walkOptions.lassoManifest = lassoManifest;\n            walkOptions.lassoContext = lassoContext;\n            walkOptions.on = {\n                dependency: function(dependency, lassoContext) {\n                    tree.add(dependency, lassoContext.parentDependency);\n                }\n            };\n\n            await dependencyWalker.walk(walkOptions);\n\n            var output = tree.toString();\n            output = normalizeOutput(output, dir);\n\n            helpers.compare(output, '.txt');\n        });\n});\n"
  },
  {
    "path": "test/fixtures/builtin-foo.js",
    "content": ""
  },
  {
    "path": "test/fixtures/file.json",
    "content": "[{\n    \"hello\": \"world\"\n}]\n"
  },
  {
    "path": "test/fixtures/foo-shim.js",
    "content": ""
  },
  {
    "path": "test/fixtures/inspect-cache/bar.js",
    "content": ""
  },
  {
    "path": "test/fixtures/inspect-cache/foo.js",
    "content": "require('./bar');"
  },
  {
    "path": "test/flags-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst WriterTracker = require('./util/WriterTracker');\nconst rmdirRecursive = require('./util').rmdirRecursive;\nconst buildDir = nodePath.join(__dirname, 'build');\n\nconst lasso = require('lasso');\n\ndescribe('lasso/flags' , function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/flags'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var testName = nodePath.basename(dir);\n            var pageName = 'flags-' + testName;\n\n            var lassoConfig = main.getLassoConfig && main.getLassoConfig();\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            if (!lassoConfig.outputDir) {\n                lassoConfig.outputDir = nodePath.join(buildDir, pageName);\n            }\n\n            rmdirRecursive(lassoConfig.outputDir);\n\n            var myLasso = lasso.create(lassoConfig, dir);\n            var lassoOptions = main.getLassoOptions(dir);\n\n            lassoOptions.pageName = pageName;\n            lassoOptions.from = dir;\n\n            var writerTracker = WriterTracker.create(myLasso.writer);\n\n            const lassoPageResult = await myLasso.lassoPage(lassoOptions);\n            main.check(lassoPageResult, writerTracker);\n            await lasso.flushAllCaches();\n        });\n});\n"
  },
  {
    "path": "test/inspect-cache-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nchai.config.includeStack = true;\nconst expect = require('chai').expect;\nconst fs = require('fs');\nconst inspectCache = require('lasso/require/inspect-cache');\nconst buildPluginConfig = require('lasso/require/build-plugin-config');\nconst MockLassoContext = require('./mock/MockLassoContext');\n\ndescribe('lasso-require/util/inspect', function() {\n    it('should read from cache with matching last modified', async () => {\n        var pluginConfig = {\n            builtins: {\n                foo: require.resolve('./fixtures/builtin-foo')\n            }\n        };\n        pluginConfig.rootDir = __dirname;\n        var mockPluginConfig = buildPluginConfig(pluginConfig);\n        var lassoContext = new MockLassoContext();\n        lassoContext.mockEnableCachingForCache('lasso-require/inspect');\n\n        var path = nodePath.join(__dirname, 'fixtures/inspect-cache/foo.js');\n        var readCount = 0;\n\n        function createReadStream() {\n            expect(arguments.length).to.equal(0);\n            readCount++;\n            return fs.createReadStream(path, { encoding: 'utf8' });\n        }\n\n        function getLastModified() {\n            return Promise.resolve(10);\n        }\n\n        let inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig);\n        expect(readCount).to.equal(1);\n        expect(inspectResult.fromCache).to.equal(undefined);\n\n        // Inspect the same file... should come from the cache\n        inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig);\n        expect(inspectResult.fromCache).to.equal(true);\n        expect(readCount).to.equal(1);\n    });\n\n    it('should still read from cache without getLastModified', async () => {\n        var pluginConfig = {\n            builtins: {\n                foo: require.resolve('./fixtures/builtin-foo')\n            }\n        };\n        pluginConfig.rootDir = __dirname;\n        var mockPluginConfig = buildPluginConfig(pluginConfig);\n        var lassoContext = new MockLassoContext();\n        lassoContext.mockEnableCachingForCache('lasso-require/inspect');\n\n        var path = nodePath.join(__dirname, 'fixtures/inspect-cache/foo.js');\n        var readCount = 0;\n\n        function createReadStream() {\n            expect(arguments.length).to.equal(0);\n            readCount++;\n            return fs.createReadStream(path, { encoding: 'utf8' });\n        }\n\n        // TODO: Change should this be removed in this test?\n        function getLastModified() {\n            return Promise.resolve(-1);\n        }\n\n        let inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig);\n        expect(readCount).to.equal(1);\n        expect(inspectResult.fromCache).to.equal(undefined);\n\n        // Inspect the same file... should come from the cache\n        inspectResult = await inspectCache.inspectCached(path, {createReadStream, getLastModified}, lassoContext, mockPluginConfig);\n        expect(inspectResult.fromCache).to.equal(true);\n        expect(readCount).to.equal(2);\n    });\n});\n"
  },
  {
    "path": "test/inspect-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nconst chai = require('chai');\nconst stripAnsi = require('strip-ansi');\nchai.config.includeStack = true;\nconst fs = require('fs');\nconst inspect = require('lasso/require/util/inspect');\n\ndescribe('lasso-require/util/inspect', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/inspect'),\n        async function (dir, helpers) {\n            const inputPath = nodePath.join(dir, 'input.js');\n            const inputSrc = fs.readFileSync(inputPath, { encoding: 'utf8' });\n            try {\n                const inspected = inspect(inputSrc, { filename: inputPath, allowShortcircuit: false });\n                helpers.compare(inspected, '.json');\n            } catch (err) {\n                var message = stripAnsi(err.message);\n                message = message.slice(message.indexOf(\"): \") + 3);\n                helpers.compare({\n                    name: err.name,\n                    message: message\n                }, '.json');\n            }\n        });\n});\n"
  },
  {
    "path": "test/lasso-image-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst chai = require('chai');\nchai.Assertion.includeStack = true;\nrequire('chai').should();\nconst expect = require('chai').expect;\nconst nodePath = require('path');\nconst fs = require('fs');\n\nconst lassoImagePlugin = require('lasso/plugins/lasso-image'); // Load this module just to make sure it works\nconst lasso = require('lasso');\n\ndescribe('lasso-image', function () {\n    it('should allow for reading image info on the server', function(done) {\n        const imgPath = require.resolve('./fixtures/ebay.png');\n\n        lassoImagePlugin.getImageInfo(imgPath, function (err, imageInfo) {\n            if (err) return done(err);\n            expect(imageInfo).to.deep.equal({\n                url: '/static/ebay-73498128.png',\n                width: 174,\n                height: 30\n            });\n            done();\n        });\n    });\n\n    it('should compile an image into a JavaScript module', async function() {\n        var myLasso = lasso.create({\n            fileWriter: {\n                fingerprintsEnabled: false,\n                outputDir: nodePath.join(__dirname, 'static')\n            },\n            bundlingEnabled: true,\n            plugins: [\n                {\n                    plugin: lassoImagePlugin,\n                    config: {\n\n                    }\n                }\n            ]\n        });\n\n        await myLasso.lassoPage({\n            name: 'testPage',\n            dependencies: [\n                'require: ./fixtures/ebay.png'\n            ],\n            from: module\n        });\n\n        var output = fs.readFileSync(nodePath.join(__dirname, '/static/testPage.js'), {encoding: 'utf8'});\n        expect(output).to.contain('174');\n        expect(output).to.contain('30');\n        expect(output).to.contain('/static');\n        expect(output).to.contain('ebay.png');\n        return lasso.flushAllCaches();\n    });\n\n    it('should compile an image into a JavaScript module when not using require', async function() {\n        var myLasso = lasso.create({\n            fileWriter: {\n                fingerprintsEnabled: false,\n                outputDir: nodePath.join(__dirname, 'static')\n            },\n            bundlingEnabled: true,\n            plugins: [\n                {\n                    plugin: lassoImagePlugin,\n                    config: {}\n                }\n            ]\n        });\n\n        await myLasso.lassoPage({\n            name: 'testPage2',\n            dependencies: [\n                './fixtures/ebay.png'\n            ],\n            from: module\n        });\n\n        var output = fs.readFileSync(nodePath.join(__dirname, '/static/testPage.js'), {encoding: 'utf8'});\n        expect(output).to.contain('174');\n        expect(output).to.contain('30');\n        expect(output).to.contain('/static');\n        expect(output).to.contain('ebay.png');\n        return lasso.flushAllCaches();\n    });\n\n    it('should compile an image into a JavaScript module and retain lasso context', async function() {\n        var myLasso = lasso.create({\n            fileWriter: {\n                fingerprintsEnabled: false,\n                outputDir: nodePath.join(__dirname, 'static')\n            },\n            bundlingEnabled: true,\n            plugins: [\n                {\n                    plugin: lassoImagePlugin,\n                    config: {\n\n                    }\n                }\n            ]\n        });\n        var originalWriter = myLasso.writer;\n        class Writer {\n            async writeResource (reader, lassoContext) {\n                var requestContext = lassoContext.data.renderContext.stream;\n                var protocol = requestContext.secure ? 'https:' : 'http:';\n\n                return {\n                    url: protocol + '//static.example.com/ebay.png'\n                };\n            }\n            writeBundles() {\n                return originalWriter.writeBundles.apply(originalWriter, arguments);\n            }\n        }\n\n        myLasso.writer = new Writer();\n        myLasso.on('buildCacheKey', function(eventArgs) {\n            var lassoContext = eventArgs.context;\n            var requestContext = lassoContext.data.renderContext.stream;\n\n            var cacheKey = eventArgs.cacheKey;\n\n            if (requestContext.secure) {\n                cacheKey.add('secure');\n            }\n        });\n\n        var mockRenderContext = {\n            stream: {\n                secure: true\n            }\n        };\n\n        await myLasso.lassoPage({\n            name: 'testPage',\n            dependencies: [\n                'require: ./fixtures/ebay.png'\n            ],\n            from: module,\n            data: { renderContext: mockRenderContext }\n        });\n\n        var output = fs.readFileSync(nodePath.join(__dirname, '/static/testPage.js'), {encoding: 'utf8'});\n        expect(output).to.contain('174');\n        expect(output).to.contain('30');\n        expect(output).to.contain('https://static.example.com/ebay.png');\n        return lasso.flushAllCaches();\n    });\n\n    it('should allow passing the renderContext', function(done) {\n        class Writer {\n            async writeResource (reader, lassoContext) {\n                var requestContext = lassoContext.data.renderContext.stream;\n                var protocol = requestContext.secure ? 'https:' : 'http:';\n\n                return {\n                    url: protocol + '//static.example.com/ebay.png'\n                };\n            }\n        }\n\n        var myLasso = lasso.create();\n        myLasso.writer = new Writer();\n        myLasso.on('buildCacheKey', function(eventArgs) {\n            var lassoContext = eventArgs.context;\n            var requestContext = lassoContext.data.renderContext.stream;\n\n            var cacheKey = eventArgs.cacheKey;\n\n            if (requestContext.secure) {\n                cacheKey.add('secure');\n            }\n        });\n\n        var mockRenderContext = {\n            stream: {\n                secure: true\n            }\n        };\n\n        lassoImagePlugin.getImageInfo(require.resolve('./fixtures/ebay.png'), {\n            lasso: myLasso,\n            renderContext: mockRenderContext\n        }, function (err, imageInfo) {\n            if (err) return done(err);\n            expect(imageInfo).to.deep.equal({\n                url: 'https://static.example.com/ebay.png',\n                width: 174,\n                height: 30\n            });\n            done();\n        });\n    });\n});\n"
  },
  {
    "path": "test/load-prebuild-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst lasso = require('lasso');\n\ndescribe('lasso/flags', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/load-prebuild'),\n        async function (dir, helpers) {\n            const main = require(nodePath.join(dir, 'test.js'));\n            let lassoConfig = main.getLassoConfig && main.getLassoConfig();\n\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            const myLasso = lasso.create(lassoConfig, dir);\n\n            try {\n                await main.check(myLasso);\n            } catch (err) {\n                if (main.checkError) {\n                    return main.checkError(err);\n                } else {\n                    throw err;\n                }\n            }\n\n            if (main.checkError) {\n                throw new Error('Error expected');\n            }\n\n            await lasso.flushAllCaches();\n        });\n});\n"
  },
  {
    "path": "test/mock/LassoManifest.js",
    "content": "var ok = require('assert').ok;\nvar nodePath = require('path');\nvar condition = require('./condition');\nvar lassoResolveFrom = require('lasso-resolve-from');\n\nfunction resolveBrowserPath(dir, path) {\n    var resolved;\n\n    if (path.charAt(0) === '.') {\n        resolved = lassoResolveFrom(dir, path);\n    } else {\n        resolved = lassoResolveFrom(dir, './' + path);\n        if (!resolved) {\n            resolved = lassoResolveFrom(dir, path);\n        }\n    }\n\n    return resolved ? resolved.path : undefined;\n}\n\nfunction LassoManifest(options) {\n    if (options.manifest) {\n        Object.assign(this, options.manifest);\n    }\n\n\n    if (options.dirname) {\n        this.dirname = options.dirname;\n    }\n\n    if (options.filename) {\n        this.filename = options.filename;\n    }\n\n    var dirname = this.dirname;\n\n    ok(dirname, '\"dirname\" is required');\n    ok(typeof dirname === 'string', '\"dirname\" must be a string');\n\n    var requireRemap = this.requireRemap;\n    if (requireRemap && Array.isArray(requireRemap)) {\n        this.requireRemap = requireRemap.map((requireRemap) => {\n            var from = resolveBrowserPath(dirname, requireRemap.from);\n            var to = resolveBrowserPath(dirname, requireRemap.to);\n\n            return {\n                from: from,\n                to: to,\n                condition: condition.fromObject(requireRemap)\n            };\n        });\n    }\n}\n\nLassoManifest.prototype = {\n    __LassoManifest: true,\n\n    getUniqueId: function() {\n        return this._uniqueId;\n    },\n\n    resolve: function(relPath) {\n        return nodePath.resolve(this.dirname, relPath);\n    },\n\n    getRequireRemap: function(lassoContext) {\n\n        if (this.requireRemap && Array.isArray(this.requireRemap)) {\n            var filteredRemaps = {};\n            var flags = lassoContext.flags;\n\n            this.requireRemap.forEach(function(remap) {\n                if (remap.condition && !remap.condition(flags)) {\n                    return;\n                }\n\n                filteredRemaps[remap.from] = remap.to;\n            });\n\n            return filteredRemaps;\n\n        } else {\n            return {};\n        }\n    }\n};\n\nLassoManifest.isLassoManifest = function(o) {\n    return o && o.__LassoManifest;\n};\n\nmodule.exports = LassoManifest;"
  },
  {
    "path": "test/mock/MockDependency.js",
    "content": "'use strict';\n\nclass MockDependency{\n    getParentManifestDir() {\n        return this.__dirname;\n    }\n\n    getParentManifestPath() {\n        return this.__filename;\n    }\n}\n\nmodule.exports = MockDependency;"
  },
  {
    "path": "test/mock/MockLassoContext.js",
    "content": "'use strict';\nrequire('../util/test-init');\n\nvar fs = require('fs');\nvar nodePath = require('path');\nvar lassoCachingFS = require('lasso-caching-fs');\n\nvar Readable = require('stream').Readable;\nvar util = require('util');\nvar fingerprintStream = require('./fingerprint-stream');\nvar MockMemoryCache = require('./MockMemoryCache');\nvar MockRequireHandler = require('./MockRequireHandler');\nvar LassoManifest = require('./LassoManifest');\nvar manifestLoader = require('./manifest-loader');\nvar resolve = require('lasso/resolve');\nvar getClientPath = require('lasso-modules-client/transport').getClientPath;\n\nfunction noop() {}\n\nfunction DeferredStream(startFn, options) {\n    var self = this;\n\n    Readable.call(this, options);\n\n    // When _read is called, we need to start pushing data\n    self._read = function() {\n        self._read = noop;\n        var stream = startFn.call(self);\n        if (stream) {\n            stream\n                .on('data', function(data) {\n                    self.push(data);\n                })\n                .on('end', function() {\n                    self.push(null);\n                })\n                .on('error', function(err) {\n                    self.emit('error', err);\n                })\n                .resume();\n        }\n    };\n\n    return self;\n}\n\nutil.inherits(DeferredStream, Readable);\n\nmodule.exports = DeferredStream;\n\nvar MOCK_CACHE = {\n    get: function(key, options) {\n        return new Promise((resolve, reject) => {\n            if (options.builder) {\n                resolve(options.builder());\n            } else {\n                resolve();\n            }\n        });\n    },\n\n    getSync: function() {\n        return;\n    },\n\n    put: function(key, value, options) {\n\n    },\n\n    putSync: function(key, value, options) {\n\n    }\n};\n\nclass MockLassoContext {\n    constructor() {\n        this.data = {};\n        this.phaseData = {};\n        var requireExtensions = {\n            js: {\n                object: false,\n                createReadStream: function(path, lassoContext) {\n                    return function() {\n                        return fs.createReadStream(path, {encoding: 'utf8'});\n                    };\n                }\n            },\n            json: {\n                object: true,\n                createReadStream: function(path, lassoContext) {\n                    return function() {\n                        return fs.createReadStream(path, {encoding: 'utf8'});\n                    };\n                }\n            }\n        };\n\n        this.dependencyRegistry = {\n            getRequireHandler: function(path, lassoContext) {\n                var ext = nodePath.extname(path).substring(1);\n                var requireExt = requireExtensions[ext];\n                return {\n                    object: requireExt.object === true,\n\n                    async init () {\n                        return Promise.resolve();\n                    },\n\n                    async getDependencies() {\n                        return [];\n                    },\n\n                    createReadStream: requireExt.createReadStream(path, lassoContext),\n\n                    getLastModified: function() {\n                        return Promise.resolve(-1);\n                    }\n                };\n            },\n\n            createRequireHandler: function(path, lassoContext, userOptions) {\n                return new MockRequireHandler(userOptions, lassoContext, path);\n            },\n\n            getRequireExtensionNames() {\n                return Object.keys(requireExtensions).map((ext) => {\n                    return '.' + ext;\n                });\n            }\n        };\n\n        var mockCaches = this.mockCaches = {};\n\n        this.cache = {\n            getCache(name) {\n                return mockCaches[name] || MOCK_CACHE;\n            },\n            getSyncCache(name) {\n                return mockCaches[name] || MOCK_CACHE;\n            }\n        };\n\n        this.nextId = 0;\n    }\n\n    get isMockLassoContext() {\n        return true;\n    }\n\n    /**\n     * Converts a \"reader\" function to a function that *always* returns a stream.\n     * The actual reader function may return a promise, a String, a stream or it may use a callback.\n     */\n    createReadStream(func) {\n        var stream = new DeferredStream(function() {\n            // this function will be called when it is time to start reading data\n            var finished = false;\n\n            var callback = (err, value) => {\n                if (finished) {\n                    return;\n                }\n\n                if (err) {\n                    stream.emit('error', err);\n                    return;\n                }\n\n                if (value == null) {\n                    stream.push(null);\n                    finished = true;\n                } else {\n                    if (typeof value === 'string') {\n                        stream.push(value);\n                        stream.push(null);\n                        finished = true;\n                    } else if (typeof value.pipe === 'function') {\n                        // Looks like a stream...\n                        value.pipe(this);\n                        finished = true;\n                    } else if (typeof value.then === 'function') {\n                        // Looks like a promise...\n                        value\n                            .then((value) => {\n                                callback(null, value);\n                            })\n                            .catch(callback);\n                    } else {\n                        // Hopefully a Buffer\n                        stream.push(value);\n                        stream.push(null);\n                        finished = true;\n                    }\n                }\n            };\n\n            var result = func(callback);\n\n            if (!finished) {\n                // callback was not invoked\n                if (result === null) {\n                    callback(null, null);\n                } else if (result === undefined) {\n                    // waiting on callback\n                } else if (result && typeof result.pipe === 'function') {\n                    finished = true;\n                    return result;\n                } else {\n                    callback(null, result);\n                    // A stream was returned, so we will return it\n                }\n            }\n        });\n\n        return stream;\n    }\n\n    mockEnableCachingForCache(cacheName) {\n        this.mockCaches[cacheName] = new MockMemoryCache();\n    }\n\n    uniqueId() {\n        return this.nextId++;\n    }\n\n    async getFileLastModified(path) {\n        return Promise.resolve(-1);\n    }\n\n    isAsyncBundlingPhase() {\n        return false;\n    }\n\n    get cachingFs() {\n        return lassoCachingFS;\n    }\n\n    deferredStream(startFn, options) {\n        return new DeferredStream(startFn, options);\n    }\n\n    createFingerprintStream() {\n        return fingerprintStream.create();\n    }\n\n    readPackageFile(path) {\n        var rawManifest = manifestLoader.load(path);\n        return new LassoManifest({\n            manifest: rawManifest,\n            dependencyRegistry: this.dependencyRegistry\n        });\n    }\n\n    getResolver() {\n        if (this.resolver === undefined) {\n            this.resolver = resolve.createResolver(this, getClientPath);\n        }\n        return this.resolver;\n    }\n\n    resolve(targetModule, fromDir, options) {\n        return this.getResolver().resolve(targetModule, fromDir, options);\n    }\n\n    resolveCached(targetModule, fromDir, options) {\n        return this.getResolver().resolveCached(targetModule, fromDir, options);\n    }\n}\n\nmodule.exports = MockLassoContext;\n"
  },
  {
    "path": "test/mock/MockMemoryCache.js",
    "content": "'use strict';\n\nclass MockMemoryCache {\n    constructor() {\n        this.lookup = {};\n    }\n\n    get(key, options) {\n        var lookup = this.lookup;\n\n        var lastModified = options && options.lastModified;\n        if (!lastModified || lastModified < 0) {\n            lastModified = null;\n        }\n\n        var entry = lookup[key];\n        if (entry && lastModified && entry.lastModified !== lastModified) {\n            entry = null;\n        }\n\n        var value;\n\n        if (!entry && options.builder) {\n            value = options.builder();\n            entry = {\n                value: value,\n                lastModified: lastModified\n            };\n\n            lookup[key] = entry;\n        }\n\n        return Promise.resolve(value);\n    }\n\n    getSync() {\n        return this.get.apply(this, arguments);\n    }\n}\n\nmodule.exports = MockMemoryCache;"
  },
  {
    "path": "test/mock/MockRequireHandler.js",
    "content": "'use strict';\n\nvar nodePath = require('path');\nvar ok = require('assert').ok;\nvar resolveFrom = require('resolve-from');\n\nvar EMPTY_ARRAY_PROMISE = Promise.resolve([]);\n\nclass RequireHandler {\n    constructor(userOptions, lassoContext, path) {\n        ok(userOptions, '\"userOptions\" is required');\n        ok(lassoContext, '\"lassoContext\" is required');\n        ok(path, '\"path\" is required');\n\n        this.lassoContext = lassoContext;\n        this.userOptions = userOptions;\n        this.path = path;\n        this.includePathArg = true;\n\n        this.userThisObject = {\n            path: path,\n            resolvePath: function(pathToResolve) {\n                var dir = nodePath.dirname(path);\n                return resolveFrom(dir, pathToResolve);\n            }\n        };\n        this.lastModified = null;\n        this.object = userOptions.object === true;\n    }\n\n    async init() {\n        var lassoContext = this.lassoContext;\n        var userInit = this.userOptions.init;\n\n        return new Promise((resolve, reject) => {\n            if (userInit) {\n                var promise = userInit.call(this.userThisObject, lassoContext, (err) => {\n                    if (err) {\n                        reject(err);\n                    } else {\n                        resolve();\n                    }\n                });\n\n                if (promise !== undefined) {\n                    resolve(promise);\n                }\n            } else {\n                resolve();\n            }\n        });\n    }\n\n    createReadStream() {\n        var lassoContext = this.lassoContext;\n        var path = this.path;\n        var createReadStream = this.userOptions.createReadStream;\n        if (createReadStream) {\n\n            return this.includePathArg ?\n                createReadStream.call(this.userThisObject, path, lassoContext) :\n                createReadStream.call(this.userThisObject, lassoContext);\n        }\n\n        var userRead = this.userOptions.read;\n        if (userRead) {\n            return lassoContext.createReadStream((callback) => {\n                return this.includePathArg ?\n                userRead.call(this.userThisObject, path, lassoContext, callback) :\n                userRead.call(this.userThisObject, lassoContext, callback);\n            });\n        } else {\n            return lassoContext.createReadStream((callback) => {\n                callback(null, '');\n            });\n        }\n    }\n\n    async getLastModified() {\n        var lassoContext = this.lassoContext;\n        var path = this.path;\n        var lastModifiedPromise = this.lastModified;\n\n        if (lastModifiedPromise) {\n            return lastModifiedPromise;\n        }\n\n        var userLastModified = this.userOptions.getLastModified;\n\n        if (userLastModified) {\n            this.lastModifiedPromise = new Promise((resolve, reject) => {\n\n                let callback = (err, lastModified) => {\n                    if (err) {\n                        reject(err);\n                    } else {\n                        resolve(lastModified || -1);\n                    }\n                };\n\n                var userPromise = this.includePathArg ?\n                    userLastModified.call(this.userThisObject, path, lassoContext, callback) :\n                    userLastModified.call(this.userThisObject, lassoContext, callback);\n\n                if (userPromise !== undefined) {\n                    resolve(userPromise || -1);\n                }\n            });\n        } else {\n            this.lastModifiedPromise = this.lassoContext.getFileLastModified(path);\n        }\n\n        return this.lastModifiedPromise;\n    }\n\n    getDependencies() {\n        var lassoContext = this.lassoContext;\n        var userGetDependencies = this.userOptions.getDependencies;\n        if (!userGetDependencies) {\n            return EMPTY_ARRAY_PROMISE;\n        }\n\n        console.log('THIS USER GETDEP: ', userGetDependencies);\n        return userGetDependencies.call(this.userThisObject, lassoContext);\n    }\n\n    getDefaultBundleName(pageBundleName, lassoContext) {\n        var userGetDefaultBundleName = this.userOptions.getDefaultBundleName;\n        if (userGetDefaultBundleName) {\n            return userGetDefaultBundleName.call(this.userThisObject, pageBundleName, lassoContext);\n        }\n    }\n}\n\nmodule.exports = RequireHandler;\n"
  },
  {
    "path": "test/mock/condition.js",
    "content": "exports.ifCondition = function(condition) {\n    // This is a hack because we moved from \"flags\" to \"extensions\"\n    // We create a function that introduces two scoped variables: flags, extensions\n    var conditionFunc = eval(\"(function(flags, extensions) { return \" + condition + \";})\");\n\n    return function(flags) {\n        return conditionFunc(flags, flags);\n    };\n};\n\nexports.ifFlag = function(flag) {\n    return function(flags) {\n        return flags.contains(flag);\n    };\n};\n\nexports.ifNotFlag = function(flag) {\n    return function(flags) {\n        return !flags.contains(flag);\n    };\n};\n\n\nexports.fromObject = function(o) {\n    var condition;\n\n    if ((condition = o['if'])) {\n        return exports.ifCondition(condition);\n    } else if ((condition = o['if-flag'] || o['if-extension'])) {\n        return exports.ifFlag(condition);\n    } else if ((condition = o['if-not-flag'] || o['if-not-extension'])) {\n        return exports.ifNotFlag(condition);\n    }\n\n    return null;\n};"
  },
  {
    "path": "test/mock/create-lasso-context.js",
    "content": "\"use strict\";\n\nrequire('../util/test-init');\n\nconst configLoader = require('lasso/config-loader');\nvar LassoContext = require('lasso/LassoContext');\nvar dependencies = require('lasso/dependencies');\nvar MockMemoryCache = require('./MockMemoryCache');\n\nvar fs = require('fs');\nvar nodePath = require('path');\nvar lassoCachingFS = require('lasso-caching-fs');\n\nvar Readable = require('stream').Readable;\nvar util = require('util');\nvar fingerprintStream = require('./fingerprint-stream');\nvar MockMemoryCache = require('./MockMemoryCache');\nvar MockRequireHandler = require('./MockRequireHandler');\nvar LassoManifest = require('./LassoManifest');\nvar manifestLoader = require('./manifest-loader');\n\nvar MOCK_CACHE = {\n    get: function(key, options) {\n        return new Promise((resolve, reject) => {\n            if (options.builder) {\n                resolve(options.builder());\n            } else {\n                resolve();\n            }\n        });\n    },\n\n    put: function(key, value, options) {\n\n    },\n};\n\nclass SyncCache {\n    constructor() {\n        this._store = {};\n    }\n\n    getSync(key) {\n        return this._store[key];\n    }\n\n    putSync(key, value) {\n        this._store[key] = value;\n    }\n}\n\nvar requireExtensions = {\n    js: {\n        object: false,\n        createReadStream: function(path, lassoContext) {\n            return function() {\n                return fs.createReadStream(path, {encoding: 'utf8'});\n            };\n        }\n    },\n    json: {\n        object: true,\n        createReadStream: function(path, lassoContext) {\n            return function() {\n                return fs.createReadStream(path, {encoding: 'utf8'});\n            };\n        }\n    }\n};\n\nmodule.exports = function createLassoContext(config) {\n    var lassoContext = new LassoContext();\n    var mockCaches = {};\n    var syncCaches = {};\n    var uniqueId = 0;\n    lassoContext.isMockLassoContext = true;\n\n    if (config) {\n        const baseDir = process.cwd();\n        lassoContext.config = configLoader.load(config, baseDir, null);\n    }\n\n    lassoContext.dependencyRegistry = {\n        __DependencyRegistry: true,\n        getRequireHandler: function(path, lassoContext) {\n            var ext = nodePath.extname(path).substring(1);\n            var requireExt = requireExtensions[ext];\n            return {\n                object: requireExt.object === true,\n\n                async init() {\n                    return Promise.resolve();\n                },\n\n                async getDependencies() {\n                    return [];\n                },\n\n                createReadStream: requireExt.createReadStream(path, lassoContext),\n\n                getLastModified: function() {\n                    return Promise.resolve(-1);\n                }\n            };\n        },\n\n        createRequireHandler: function(path, lassoContext, userOptions) {\n            return new MockRequireHandler(userOptions, lassoContext, path);\n        },\n\n        getRequireExtensionNames() {\n            return Object.keys(requireExtensions).map((ext) => {\n                return '.' + ext;\n            });\n        }\n    }\n    lassoContext.uniqueId = () => uniqueId++;\n    lassoContext.cache = {\n        getCache(name) {\n            return mockCaches[name] || MOCK_CACHE;\n        },\n        getSyncCache(name) {\n            return syncCaches[name] || (syncCaches[name] = new SyncCache());\n        }\n    };\n    lassoContext.mockEnableCachingForCache = (cacheName) => {\n        mockCaches[cacheName] = new MockMemoryCache();\n    };\n    return lassoContext;\n}\n"
  },
  {
    "path": "test/mock/dependency-factory.js",
    "content": "'use strict';\nrequire('../util/test-init');\n\nvar mockLasso = require('./mock-lasso');\nvar buildPluginConfig = require('lasso/require/build-plugin-config');\nvar MockDependency = require('./MockDependency');\nvar extend = require('raptor-util/extend');\nvar fs = require('fs');\nvar path = require('path');\n\nfunction removeDashes(str) {\n    return str.replace(/-([a-z])/g, function (match, lower) {\n        return lower.toUpperCase();\n    });\n}\n\nfunction removeExt(filename) {\n    var ext = path.extname(filename);\n    return filename.slice(0, 0 - ext.length);\n}\n\nexports.create = function(pluginConfig) {\n    var mockPluginConfig = buildPluginConfig(pluginConfig);\n\n    function createDependencyFactory(mixinsFactory) {\n        class Dependency extends MockDependency {}\n        extend(Dependency.prototype, mixinsFactory.create(mockPluginConfig, mockLasso));\n        return function createDependency(props) {\n            var d = new Dependency();\n            extend(d, props);\n            return d;\n        };\n    }\n\n    var factories = {};\n    var srcDir = path.join(__dirname, '../../src/require');\n    fs.readdirSync(srcDir)\n        .forEach(function(child) {\n            if (child.startsWith('dep-')) {\n                var name = removeDashes(removeExt(child));\n                factories[name] = createDependencyFactory(require(`lasso/require/${child}`));\n            }\n        });\n\n    return factories;\n};\n"
  },
  {
    "path": "test/mock/fingerprint-stream.js",
    "content": "'use strict';\n\nvar crypto = require('crypto');\nvar inherit = require('raptor-util/inherit');\nvar Transform = require('stream').Transform;\n\nfunction FingerprintStream(options) {\n    FingerprintStream.$super.call(this, options);\n    this._shasum = crypto.createHash('sha1');\n    this._fingerprint = null;\n}\n\nFingerprintStream.prototype._transform = function(chunk, encoding, callback) {\n    this._shasum.update(chunk);\n    this.push(chunk);\n    callback();\n};\n\nFingerprintStream.prototype._flush = function(callback) {\n    this._fingerprint = this._shasum.digest('hex');\n    this._shasum = null;\n    this.emit('fingerprint',this._fingerprint);\n\n    callback();\n};\n\nFingerprintStream.prototype.on = function(event, callback) {\n    if (event === 'fingerprint' && this._fingerprint) {\n        callback.call(this, this._fingerprint);\n        return this;\n    } else {\n        return FingerprintStream.$super.prototype.on.apply(this, arguments);\n    }\n};\n\ninherit(FingerprintStream, Transform);\n\nexports.create = function() {\n    return new FingerprintStream();\n};\n"
  },
  {
    "path": "test/mock/manifest-loader.js",
    "content": "var ok = require('assert').ok;\nvar nodePath = require('path');\nvar Module = require('module').Module;\nvar fs = require('fs');\nvar resolveCache = {};\nvar manifestCache = {};\nvar isAbsolute = require('path').isAbsolute;\n\nvar allowedProps = {\n    dependencies: true,\n    async: true,\n    main: true,\n    requireRemap: true\n};\n\nfunction readManifest(path) {\n    var manifest = manifestCache[path];\n    if (manifest !== undefined) {\n        return manifest;\n    }\n\n    var json;\n\n    try {\n        json = fs.readFileSync(path, {encoding: 'utf8'});\n    }\n    catch(e) {\n        manifest = null;\n    }\n\n    if (json) {\n        try {\n            manifest = JSON.parse(json);\n        } catch(e) {\n            throw new Error('Unable to parse JSON file at path \"' + path + '\". Exception: ' + e);\n        }\n\n\n        for (var k in manifest) {\n            if (manifest.hasOwnProperty(k)) {\n                if (!allowedProps[k]) {\n                    throw new Error('Invalid property of \"' + k + '\" in lasso manifest at path \"' + path + '\"');\n                }\n            }\n        }\n\n        if (manifest.main && manifest.dependencies) {\n            throw new Error('\"dependencies\" not allowed when \"main specified. Lasso.js manifest file: ' + path);\n        }\n\n        manifest.dirname = nodePath.dirname(path);\n        manifest.filename = path;\n    }\n\n    manifestCache[path] = manifest;\n    return manifest;\n}\n\nfunction tryManifest(dirname, manifestPath) {\n    var manifest = readManifest(nodePath.resolve(dirname, manifestPath, 'browser.json'));\n    if (!manifest) {\n        manifest = readManifest(nodePath.resolve(dirname, manifestPath, 'optimizer.json'));\n    }\n    return manifest;\n}\n\nfunction tryExtensionManifest(dirname, manifestPath) {\n    var manifest = readManifest(nodePath.resolve(dirname, manifestPath + '.browser.json'));\n    if (!manifest) {\n        manifest = readManifest(nodePath.resolve(dirname, manifestPath + '.optimizer.json'));\n    }\n    return manifest;\n}\n\nfunction tryQualified(dirname, manifestPath) {\n    var path = nodePath.resolve(dirname, manifestPath);\n    return readManifest(path);\n}\n\nfunction tryAll(dirname, manifestPath) {\n    if (manifestPath.endsWith('browser.json') || manifestPath.endsWith('optimizer.json')) {\n        return tryQualified(dirname, manifestPath);         // <dirname>/<manifestPath>/browser.json\n    } else {\n        return tryManifest(dirname, manifestPath) ||         // <dirname>/<manifestPath>/browser.json\n            tryExtensionManifest(dirname, manifestPath);        // <dirname>/<manifestPath>.browser.json\n    }\n}\n\nfunction _resolve(path, from) {\n\n    if (isAbsolute(path)) {\n        return tryAll(from, path);\n    }\n\n    if (!from) {\n        throw new Error('\"from\" argument is required for non-absolute paths');\n    }\n\n    var resolveKey = path + '|' + from;\n    var manifest = resolveCache[resolveKey];\n\n    if (manifest !== undefined) {\n        return manifest;\n    }\n\n    if (process.platform === 'win32') {\n        path = path.replace(/\\\\/g, '/'); // Replace back slashes with forward slashes\n    }\n\n    if (path.startsWith('./') || path.startsWith('../')) {\n        // Don't go through the search paths for relative paths\n        manifest = tryAll(from, path);\n    }\n    else {\n        var paths = Module._nodeModulePaths(from);\n\n        for (var i=0, len=paths.length; i<len; i++) {\n            var dir = paths[i];\n\n            manifest = tryAll(dir, path);\n\n            if (manifest) {\n                break;\n            }\n        }\n    }\n\n    resolveCache[resolveKey] = manifest;\n\n    return manifest;\n}\n\nfunction load(path, from) {\n\n    ok(path, '\"path\" is required');\n    ok(typeof path === 'string', '\"path\" must be a string');\n\n    // ok(from, '\"from\" is required');\n    // ok(typeof from === 'string', '\"from\" must be a string');\n\n    // Load the lasso manifest and automatically follow \"main\"\n    // to get the destination lasso package\n    function loadHelper(path, from) {\n        var manifest = _resolve(path, from);\n        if (!manifest) {\n            var e = new Error('Lasso manifest not found: ' + path + '(searching from: ' + from + ')');\n            e.fileNotFound = path + '@' + from;\n            throw e;\n        }\n\n        if (manifest.main) {\n            var mainPath = nodePath.resolve(manifest.dirname, manifest.main);\n            return loadHelper(mainPath, manifest.dirname);\n        }\n        else {\n            return manifest;\n        }\n    }\n\n    return loadHelper(path, from);\n}\n\nexports.load = load;\n\nexports.toString = function () {\n    return '[lasso@' + __filename + ']';\n};\n"
  },
  {
    "path": "test/mock/mock-lasso.js",
    "content": "var mockLasso = {\n    dependencies: {\n        createDependency: function(d) {\n            return d;\n        }\n    }\n};\n\nmodule.exports = mockLasso;"
  },
  {
    "path": "test/modules-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst sandboxLoad = require('./util').sandboxLoad;\nconst rmdirRecursive = require('./util').rmdirRecursive;\nconst writeTestHtmlPage = require('./util').writeTestHtmlPage;\nconst buildDir = nodePath.join(__dirname, 'build');\nconst lasso = require('lasso');\n\ndescribe('lasso/modules', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/modules'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var testName = nodePath.basename(dir);\n            var pageName = 'modules-' + testName;\n\n            var lassoConfig = main.lassoConfig || (main.getLassoConfig && main.getLassoConfig());\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            if (!lassoConfig.outputDir) {\n                lassoConfig.outputDir = nodePath.join(buildDir, pageName);\n            }\n\n            if (!lassoConfig.urlPrefix) {\n                lassoConfig.urlPrefix = './';\n            }\n\n            rmdirRecursive(lassoConfig.outputDir);\n\n            var myLasso = lasso.create(lassoConfig, dir);\n\n            var tests = main.tests || [];\n\n            if (main.getLassoOptions) {\n                let lassoOptions = main.getLassoOptions(dir);\n                let checkError = main.checkError;\n\n                tests.push({\n                    check: main.check,\n                    checkError: checkError,\n                    lassoOptions: lassoOptions\n                });\n            } else if (main.tests) {\n                tests = main.tests;\n            } else {\n                throw Error('Illegal state');\n            }\n\n            for (const test of tests) {\n                var lassoOptions = test.lassoOptions;\n                if (!lassoOptions.pageName) {\n                    lassoOptions.pageName = pageName;\n                }\n\n                lassoOptions.from = dir;\n\n                var check = test.check;\n                var checkError = test.checkError;\n                var modulesRuntimeGlobal = myLasso.config.modulesRuntimeGlobal;\n\n                let lassoPageResult;\n                try {\n                    lassoPageResult = await myLasso.lassoPage(lassoOptions);\n                } catch (err) {\n                    if (checkError) {\n                        checkError(err);\n                        return;\n                    } else {\n                        throw err;\n                    }\n                }\n\n                if (checkError) {\n                    throw new Error('Error expected');\n                }\n\n                writeTestHtmlPage(lassoPageResult, nodePath.join(buildDir, pageName + '/test.html'));\n                var sandbox = sandboxLoad(lassoPageResult, modulesRuntimeGlobal);\n                sandbox.$outputDir = lassoConfig.outputDir;\n\n                await check(sandbox.window, lassoPageResult);\n            }\n        });\n});\n"
  },
  {
    "path": "test/plugins-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst WriterTracker = require('./util/WriterTracker');\nconst rmdirRecursive = require('./util').rmdirRecursive;\nconst normalizeOutput = require('./util/normalizeOutput');\nconst buildDir = nodePath.join(__dirname, 'build');\nconst lasso = require('lasso');\n\ndescribe('lasso/plugins', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/plugins'),\n        async function (dir, helpers) {\n            helpers.normalizeOutput = normalizeOutput;\n            var main = require(nodePath.join(dir, 'test.js'));\n            var testName = nodePath.basename(dir);\n            var pageName = 'plugins-' + testName;\n\n            var lassoConfig = main.getLassoConfig && main.getLassoConfig();\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            if (!lassoConfig.outputDir) {\n                lassoConfig.outputDir = nodePath.join(buildDir, pageName);\n            }\n\n            rmdirRecursive(lassoConfig.outputDir);\n\n            var myLasso = lasso.create(lassoConfig, dir);\n\n            var lassoOptions = main.getLassoOptions(dir);\n            lassoOptions.pageName = pageName;\n            lassoOptions.from = dir;\n\n            var writerTracker = WriterTracker.create(myLasso.writer);\n\n            const lassoPageResult = await myLasso.lassoPage(lassoOptions);\n            main.check(lassoPageResult, writerTracker, helpers);\n            await lasso.flushAllCaches();\n        });\n});\n"
  },
  {
    "path": "test/prebuild-page-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\nconst glob = require('util').promisify(require('glob'));\nconst lasso = require('lasso');\nconst expect = require('chai').expect;\n\nfunction replaceLassoVersion (str) {\n    return str?.replace(/lasso[^?=\\\\\\/]*/g, 'lasso');\n}\n\nfunction replaceLassoSlotURLS (slot) {\n    for (const content of slot.content) {\n        if (typeof content.code === \"object\") {\n            content.code.href = replaceLassoVersion(content.code.href);\n            content.code.src = replaceLassoVersion(content.code.src);\n        } else {\n            content.code = replaceLassoVersion(content.code);\n        }\n    }\n} \n\nfunction replaceLasstAssetURLS (asset) {\n    asset.url = replaceLassoVersion(asset.url);\n    asset.outputFile = \"\";\n    asset.sourceFile = \"\";\n}\n\nfunction replaceLassoSlotVersion (prebuild) {\n    for (let i = 0; i < prebuild.length; i++) {\n        for (const name in prebuild[i].slots) {\n            for (const slot of prebuild[i].slots[name]) {\n                replaceLassoSlotURLS(slot);\n            }\n        }\n\n        for (const asset of prebuild[i].assets) {\n            replaceLasstAssetURLS(asset);\n        }\n    }\n\n    return prebuild;\n}\n\ndescribe('lasso/flags', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/prebuild-page'),\n        async function (dir, helpers) {\n            const main = require(nodePath.join(dir, 'test.js'));\n            let lassoConfig = main.getLassoConfig && main.getLassoConfig();\n\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            const myLasso = lasso.create(lassoConfig, dir);\n\n            if (main.prebuildConfig) {\n                try {\n                    await myLasso.prebuildPage(main.prebuildConfig);\n                } catch (err) {\n                    if (main.checkError) {\n                        return main.checkError(err);\n                    } else {\n                        throw err;\n                    }\n                }\n            }\n\n            if (main.checkError) {\n                throw new Error('Error expected!');\n            }\n\n            if (main.check) {\n                await main.check(myLasso);\n            } else {\n                const files = await glob('*.prebuild.json', { cwd: dir });\n\n                for (const file of files) {\n                    const prebuildPageName = file.split('.')[0];\n                    let actualPrebuild = require(nodePath.join(dir, file));\n                    actualPrebuild = replaceLassoSlotVersion(actualPrebuild);\n\n                    const expectedPrebuildFilePath = nodePath.join(dir, `${prebuildPageName}.prebuild.expected.json`);\n                    let expectedPrebuild = require(expectedPrebuildFilePath);\n                    expectedPrebuild = replaceLassoSlotVersion(expectedPrebuild);\n                    expect(actualPrebuild).to.deep.equal(expectedPrebuild);\n                }\n            }\n\n            if (main.checkError) {\n                throw new Error('Error expected');\n            }\n\n            await lasso.flushAllCaches();\n        });\n});\n"
  },
  {
    "path": "test/require-no-op-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst nodeRequireNoOp = require('lasso/node-require-no-op');\n\ndescribe('lasso/config', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/require-no-op'),\n        async function (dir, helpers) {\n            const main = require(nodePath.join(dir, 'test.js'));\n            const checkError = main.checkError;\n\n            try {\n                main.check(nodeRequireNoOp);\n            } catch (err) {\n                if (checkError) {\n                    checkError(err);\n                    return;\n                }\n\n                throw err;\n            }\n        });\n});\n"
  },
  {
    "path": "test/resource-transforms-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst rmdirRecursive = require('./util').rmdirRecursive;\nconst buildDir = nodePath.join(__dirname, 'build');\nconst lasso = require('lasso');\n\ndescribe('lasso/resource-transforms', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/resource-transforms'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var testName = nodePath.basename(dir);\n            var pageName = 'resource-transforms-' + testName;\n\n            var lassoConfig = main.getLassoConfig && main.getLassoConfig();\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            if (!lassoConfig.outputDir) {\n                lassoConfig.outputDir = nodePath.join(buildDir, pageName);\n            }\n\n            if (!lassoConfig.projectRoot) {\n                lassoConfig.projectRoot = dir;\n            }\n\n            rmdirRecursive(lassoConfig.outputDir);\n\n            var myLasso = lasso.create(lassoConfig, dir);\n            var inputs = main.getInputs();\n\n            let i = 0;\n            for (const input of inputs) {\n                var path = input.path;\n                var options = input.options;\n\n                const result = await myLasso.lassoResource(path, options);\n                try {\n                    input.check(result);\n                } catch (e) {\n                    throw new Error(`The inputs at index ${i} failed: ${e.stack}`, e);\n                }\n\n                i++;\n            }\n        });\n});\n"
  },
  {
    "path": "test/transforms-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\n\nconst WriterTracker = require('./util/WriterTracker');\nconst rmdirRecursive = require('./util').rmdirRecursive;\nconst buildDir = nodePath.join(__dirname, 'build');\nconst lasso = require('lasso');\n\ndescribe('lasso/transforms', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/transforms'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            var testName = nodePath.basename(dir);\n            var pageName = 'transforms-' + testName;\n\n            var lassoConfig = main.getLassoConfig && main.getLassoConfig();\n            if (!lassoConfig) {\n                lassoConfig = {\n                    bundlingEnabled: false,\n                    fingerprintsEnabled: false\n                };\n            }\n\n            if (!lassoConfig.outputDir) {\n                lassoConfig.outputDir = nodePath.join(buildDir, pageName);\n            }\n\n            if (!lassoConfig.projectRoot) {\n                lassoConfig.projectRoot = dir;\n            }\n\n            rmdirRecursive(lassoConfig.outputDir);\n\n            var myLasso = lasso.create(lassoConfig, dir);\n\n            var lassoOptions = main.getLassoOptions(dir);\n            lassoOptions.pageName = pageName;\n            lassoOptions.from = dir;\n\n            var writerTracker = WriterTracker.create(myLasso.writer);\n\n            const lassoPageResult = await myLasso.lassoPage(lassoOptions);\n            main.check(lassoPageResult, writerTracker);\n            await lasso.flushAllCaches();\n        });\n});\n"
  },
  {
    "path": "test/unit/AsyncPackage-test.js",
    "content": "require('../util/test-init');\n\nconst sinon = require('sinon');\nconst expect = require('chai').expect;\nconst AsyncPackage = require('lasso/AsyncPackage');\nconst Bundle = require('lasso/Bundle');\n\ndescribe('AsyncPackage test', function () {\n    it('should return name from getName', () => {\n        let asyncPkg = new AsyncPackage('pkg');\n        expect(asyncPkg.getName()).to.equal('pkg');\n    });\n\n    it('should throw error if a bundle contains an invalid content type', () => {\n        let asyncPkg = new AsyncPackage();\n        const bundle = new Bundle();\n        bundle.setContentType('INVALID_CONTENT_TYPE');\n        bundle.setUrl('./hello');\n        asyncPkg.addBundle(bundle);\n\n        expect(() => {\n            asyncPkg.getMeta();\n        }).to.throw('Invalid bundle content type: INVALID_CONTENT_TYPE');\n    });\n\n    it('should skip adding meta if content type is not defined', () => {\n        let asyncPkg = new AsyncPackage();\n        const bundle = new Bundle();\n        let hasContentCalled = false;\n        let getUrlCalled = false;\n\n        sinon.stub(bundle, 'hasContent').callsFake(() => {\n            hasContentCalled = true;\n            return false;\n        });\n\n        sinon.stub(bundle, 'getUrl').callsFake(() => {\n            getUrlCalled = true;\n            return true;\n        });\n\n        bundle.setUrl('./hello');\n        asyncPkg.addBundle(bundle);\n\n        expect(asyncPkg.getMeta()).to.deep.equal({});\n        expect(hasContentCalled).to.equal(true);\n        expect(getUrlCalled).to.equal(false);\n    });\n\n    it('should skip adding meta if url is not defined', () => {\n        let asyncPkg = new AsyncPackage();\n        const bundle = new Bundle();\n        let hasContentCalled = false;\n        let getUrlCalled = false;\n\n        sinon.stub(bundle, 'hasContent').callsFake(() => {\n            hasContentCalled = true;\n            return true;\n        });\n\n        sinon.stub(bundle, 'getUrl').callsFake(() => {\n            getUrlCalled = true;\n            return false;\n        });\n\n        bundle.setUrl('./hello');\n        asyncPkg.addBundle(bundle);\n\n        expect(asyncPkg.getMeta()).to.deep.equal({});\n        expect(hasContentCalled).to.equal(true);\n        expect(getUrlCalled).to.equal(true);\n    });\n\n    it('should skip adding meta if url is not defined', () => {\n        let asyncPkg = new AsyncPackage();\n        const bundle = new Bundle();\n        bundle.setContentType('js');\n        asyncPkg.addBundle(bundle);\n\n        expect(asyncPkg.getMeta()).to.deep.equal({});\n    });\n});\n"
  },
  {
    "path": "test/unit/LassoPageResult-test.js",
    "content": "require('../util/test-init');\n\nconst fs = require('fs');\nconst path = require('path');\nconst expect = require('chai').expect;\nconst LassoPageResult = require('lasso/LassoPageResult');\n\ndescribe('LassoPageResult test', function () {\n    it('should deserialize from a reader stream', async () => {\n        const filePath = path.resolve(__dirname, '../fixtures/file.json');\n\n        let fileContents = await fs.promises.readFile(filePath, 'utf8');\n        fileContents = JSON.parse(fileContents);\n        let lassoPageResult = new LassoPageResult();\n        lassoPageResult = Object.assign(lassoPageResult, fileContents);\n\n        const reader = () => fs.createReadStream(filePath);\n        const result = await LassoPageResult.deserialize(reader);\n\n        expect(result).to.deep.equal(lassoPageResult);\n    });\n});\n"
  },
  {
    "path": "test/unit/hash-test.js",
    "content": "require('../util/test-init');\n\nconst expect = require('chai').expect;\nconst hashUtil = require('lasso/util/hash');\n\ndescribe('Hash test', function () {\n    it('should generate full sha1 hash', () => {\n        expect(hashUtil.generate('cats')).to.equal('8ebf601f8b808c32b8d2fb570c2e0fbdbb388add');\n    });\n\n    it('should return substring of generated hash', () => {\n        expect(hashUtil.generate('cats', 5)).to.equal('8ebf6');\n    });\n\n    it('should return currect hash overflow', () => {\n        expect(hashUtil.HASH_OVERFLOW_LENGTH).to.equal(8);\n    });\n});\n"
  },
  {
    "path": "test/util/WriterTracker.js",
    "content": "var nodePath = require('path');\nvar fs = require('fs');\nvar ok = require('assert').ok;\n\nfunction WriterTracker(writer) {\n    var _this = this;\n    this.reset();\n\n    writer.on('resourceWritten', function(resource) {\n        var outputFile = resource.outputFile;\n        ok(outputFile, 'Output file expected');\n        _this._recordOutputFile(outputFile);\n    });\n\n    writer.on('bundleWritten', function(info) {\n        var bundle = info.bundle;\n        var outputFile = bundle.outputFile;\n        if (outputFile) {\n            _this._recordOutputFile(outputFile);\n        }\n    });\n}\n\nWriterTracker.prototype = {\n    _recordOutputFile: function(outputFile) {\n        var code = fs.readFileSync(outputFile, {encoding: 'utf8'});\n        this.outputFilesByPath[outputFile] = code;\n        this.outputFilesByName[nodePath.basename(outputFile)] = code;\n    },\n\n    getOutputPaths: function() {\n        var paths = Object.keys(this.outputFilesByPath);\n        paths.sort();\n        return paths;\n    },\n\n    getOutputFilenames: function() {\n        var filenames = Object.keys(this.outputFilesByName);\n        filenames.sort();\n        return filenames;\n    },\n\n    getCodeForFilename: function(filename) {\n\t\tvar code = this.outputFilesByName[filename];\n        if (code) {\n            code = code.replace(/\\r\\n/g, '\\n');\n        }\n        return code;\n    },\n\n    getCodeForPath: function(path) {\n\t\tvar code = this.outputFilesByPath[path];\n        if (code) {\n            code = code.replace(/\\r\\n/g, '\\n');\n        }\n        return code;\n    },\n\n    reset: function() {\n        this.outputFilesByPath = {};\n        this.outputFilesByName = {};\n    },\n\n    toString: function() {\n        return '[WriterTracker@' + module.filename + ']';\n    }\n};\n\nWriterTracker.create = function(writer) {\n    return new WriterTracker(writer);\n};\n\nmodule.exports = WriterTracker;"
  },
  {
    "path": "test/util/index.js",
    "content": "var fs = require('fs');\nvar nodePath = require('path');\nconst vm = require('vm');\n\nfunction rmdirRecursive(dir) {\n    var filenames;\n\n    try {\n        filenames = fs.readdirSync(dir);\n    } catch(e) {\n        return;\n    }\n\n    filenames.forEach(function(filename) {\n        var path = nodePath.join(dir, filename);\n\n        if (fs.lstatSync(path).isDirectory()) {\n            rmdirRecursive(path);\n        } else {\n            fs.unlinkSync(path);\n        }\n    });\n\n    fs.rmdirSync(dir);\n}\n\n\n\nfunction sandboxLoad(lassoPageResult, modulesRuntimeGlobal) {\n    var sandbox = {\n    };\n\n    sandbox.window = sandbox;\n\n    var context = vm.createContext(sandbox);\n\n    function loadScript(path) {\n        var code = fs.readFileSync(path, {encoding: 'utf8'});\n        var script = new vm.Script(code, {\n            filename: path,\n            displayErrors: true\n        });\n\n        script.runInContext(context);\n    }\n\n    var files = lassoPageResult.getOutputFilesWithInfo();\n    files.forEach((file) => {\n        if (file.contentType !== 'js' || file.async) {\n            return;\n        }\n\n        var path = file.path;\n        try {\n            loadScript(path);\n        } catch (err) {\n            console.error(`Error loading file ${JSON.stringify(file)}`, err);\n            throw err;\n        }\n    });\n\n    modulesRuntimeGlobal = modulesRuntimeGlobal || '$_mod';\n\n    vm.runInContext(`window.${modulesRuntimeGlobal} && ${modulesRuntimeGlobal}.ready()`, context);\n\n    sandbox.$loadScript = sandbox.window.$loadScript = loadScript;\n    sandbox.console = sandbox.window.console = console;\n\n    return sandbox;\n}\n\n\n\nfunction writeTestHtmlPage(lassoPageResult, outputFile) {\n    var headHtml = lassoPageResult.getHeadHtml();\n    var bodyHtml = lassoPageResult.getBodyHtml();\n\n    var htmlSrc = '<html><head><title>Test Page</title>' +\n        headHtml +\n        '</head><body>' +\n        bodyHtml +\n        '</body></html>';\n\n    fs.writeFileSync(outputFile, htmlSrc, { encoding: 'utf8' });\n}\n\nexports.rmdirRecursive = rmdirRecursive;\nexports.sandboxLoad = sandboxLoad;\nexports.writeTestHtmlPage = writeTestHtmlPage;\n"
  },
  {
    "path": "test/util/module-search-path.js",
    "content": "var Module = require('module').Module;\nvar oldNodeModulePaths = Module._nodeModulePaths;\n\nexports.patchSearchPath = function(dir) {\n    Module._nodeModulePaths = function(from) {\n        var paths = oldNodeModulePaths.call(this, from);\n        paths = paths.concat([dir]);\n        return paths;\n    };\n\n    return {\n        restore: function() {\n            Module._nodeModulePaths = oldNodeModulePaths;\n        }\n    };\n};"
  },
  {
    "path": "test/util/normalizeOutput.js",
    "content": "var path = require('path');\nfunction normalizeOutput(o, dir, options) {\n\n    if (dir && typeof dir === 'object') {\n        options = dir;\n        dir = null;\n    }\n\n    var replaceVersions = options && options.replaceVersions === true;\n\n    dir = dir || process.cwd();\n    var parentDir = path.dirname(dir);\n\n    function helper(o) {\n        if (Array.isArray(o)) {\n            return o.map(helper);\n        } else if (typeof o === 'object') {\n            for (var k in o) {\n                if (o.hasOwnProperty(k)) {\n                    var v = o[k];\n                    if (/^_[a-f0-9]{6}$/.test(k)) {\n                        delete o[k];\n                        k = '_HASH';\n                    }\n                    o[k] = helper(v);\n                }\n            }\n        } else if (typeof o === 'string') {\n            o = o.split(dir).join('');\n            o = o.split(parentDir).join('');\n            o = o.split(process.cwd()).join('');\n            o = o.replace(/lasso-loader\\$[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}/g, 'lasso-loader$x.x.x');\n            o = o.replace(/_[a-f0-9]{6}/, \"_HASH\");\n\n            if (replaceVersions) {\n                o = o.replace(/[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}/g, 'x.x.x');\n            }\n        }\n\n        return o;\n    }\n\n\n    return helper(o);\n}\n\nmodule.exports = normalizeOutput;"
  },
  {
    "path": "test/util/patch-module.js",
    "content": "const fs = require('fs');\nconst nodePath = require('path');\n\nconst Module = require('module').Module;\nconst oldResolveFilename = Module._resolveFilename;\n\nconst rootDir = nodePath.join(__dirname, '../../');\nconst lassoDir = nodePath.join(rootDir, 'src');\nconst lassoInstalledDir = nodePath.join(rootDir, 'node_modules/lasso');\n\nif (fs.existsSync(lassoInstalledDir)) {\n    fs.renameSync(lassoInstalledDir, nodePath.join(rootDir, 'node_modules/~lasso'));\n}\n\nfunction buildPath (request, beginPath) {\n    return nodePath.join(beginPath, request.substring('lasso/'.length));\n}\n\nModule._resolveFilename = function(request, parent, isMain) {\n    if (request.charAt(0) !== '.') {\n        if (request === 'lasso/node-require-no-op' ||\n            request.startsWith('lasso/dist-compat/') ||\n            request.startsWith('lasso/src') ||\n            request.startsWith('lasso/middleware') ||\n            request.startsWith('lasso/browser-refresh')) {\n            request = buildPath(request, rootDir);\n        } else if (request === 'lasso') {\n            request = rootDir;\n        } else if (request.startsWith('lasso/')) {\n            request = buildPath(request, lassoDir);\n        }\n    }\n\n    return oldResolveFilename.call(this, request, parent, isMain);\n};\n"
  },
  {
    "path": "test/util/test-init.js",
    "content": "require('./patch-module');\n"
  },
  {
    "path": "test/util-test.js",
    "content": "'use strict';\nrequire('./util/test-init');\n\nconst nodePath = require('path');\nrequire('chai').config.includeStack = true;\nconst util = require('lasso/util');\n\ndescribe('lasso/util', function() {\n    require('./autotest').scanDir(\n        nodePath.join(__dirname, 'autotests/util'),\n        async function (dir, helpers) {\n            var main = require(nodePath.join(dir, 'test.js'));\n            return main.check(util);\n        });\n});\n"
  },
  {
    "path": "test-loop.sh",
    "content": "#!/bin/bash\nset -e\nCOUNTER=0\nwhile [  $COUNTER -lt 100 ]; do\n    echo The counter is $COUNTER\n    npm test\n    # rm -rf .cache/ static/ && mocha test/lasso-test.js\n    let COUNTER=COUNTER+1\ndone\n"
  }
]