code:
<!-- Before creating an issue please make sure you are using the latest version of style-loader. -->

**Do you want to request a *feature* or report a *bug*?**
<!-- Please ask questions on StackOverflow or the webpack Gitter (https://gitter.im/webpack/webpack). Questions will be closed. -->

**What is the current behavior?**

**If the current behavior is a bug, please provide the steps to reproduce.**
<!-- A great way to do this is to provide your configuration via a GitHub gist. -->

**What is the expected behavior?**

**If this is a feature request, what is motivation or use case for changing the behavior?**

**Please mention other relevant information such as your webpack version, Node.js version and Operating System.**


code:
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**What kind of change does this PR introduce?**
<!-- E.g. a bugfix, feature, refactoring, build related change, etc… -->

**Did you add tests for your changes?**

**If relevant, did you update the README?**

**Summary**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
<!-- Try to link to an open issue for more information. -->

**Does this PR introduce a breaking change?**
<!-- If this PR introduces a breaking change, please describe the impact and a migration path for existing applications. -->

**Other information**

license: mit


code:
## [4.1.3](https://github.com/vuejs/vue-style-loader/compare/v4.0.1...v4.1.3) (2021-03-03)

### Bug Fixes

* also support passed ES modules from `css-loader` in addition to CommonJS format ([#47](https://github.com/vuejs/vue-style-loader/issues/47)) ([8b584bd](https://github.com/vuejs/vue-style-loader/commit/8b584bd))
* es module interop in HMR code ([8bc2fe3](https://github.com/vuejs/vue-style-loader/commit/8bc2fe3))
* fix addStyleShadow when same style object is inserted multiple times ([12846a6](https://github.com/vuejs/vue-style-loader/commit/12846a6))
* fix inconsistent hashes between Windows and POSIX systems ([#28](https://github.com/vuejs/vue-style-loader/issues/28)) ([cf8b6e8](https://github.com/vuejs/vue-style-loader/commit/cf8b6e8))

### Features

* support vue-loader 15 ([0c7ee9d](https://github.com/vuejs/vue-style-loader/commit/0c7ee9d))

## [4.1.2](https://github.com/vuejs/vue-style-loader/compare/v4.1.1...v4.1.2) (2018-08-13)

### Bug Fixes

* fix inconsistent hashes between Windows and POSIX systems ([#28](https://github.com/vuejs/vue-style-loader/issues/28)) ([cf8b6e8](https://github.com/vuejs/vue-style-loader/commit/cf8b6e8))

## [4.1.1](https://github.com/vuejs/vue-style-loader/compare/v4.1.0...v4.1.1) (2018-07-17)

### Bug Fixes

* fix addStyleShadow when same style object is inserted multiple times ([12846a6](https://github.com/vuejs/vue-style-loader/commit/12846a6))

# [4.1.0](https://github.com/vuejs/vue-style-loader/compare/v4.0.2...v4.1.0) (2018-03-20)

### Features

* support vue-loader 15 ([0c7ee9d](https://github.com/vuejs/vue-style-loader/commit/0c7ee9d))

## [4.0.2](https://github.com/vuejs/vue-style-loader/compare/v4.0.1...v4.0.2) (2018-02-13)

## [4.0.1](https://github.com/vuejs/vue-style-loader/compare/v4.0.0...v4.0.1) (2018-01-31)

### Bug Fixes

* typo ([00087b7](https://github.com/vuejs/vue-style-loader/commit/00087b7))

# [4.0.0](https://github.com/vuejs/vue-style-loader/compare/v3.1.1...v4.0.0) (2018-01-31)

### Features

* shadowMode ([94737e5](https://github.com/vuejs/vue-style-loader/commit/94737e5))
* use ESM for runtime files ([18d0ae4](https://github.com/vuejs/vue-style-loader/commit/18d0ae4))

## [3.1.1](https://github.com/vuejs/vue-style-loader/compare/v3.1.0...v3.1.1) (2018-01-24)

# [3.1.0](https://github.com/vuejs/vue-style-loader/compare/v3.0.3...v3.1.0) (2018-01-24)

### Features

* add `ssrId` option for rendering ssr id on client ([5281305](https://github.com/vuejs/vue-style-loader/commit/5281305))


code:
# vue-style-loader [![Build Status](https://circleci.com/gh/vuejs/vue-style-loader/tree/master.svg?style=shield)](https://circleci.com/gh/vuejs/vue-loader/tree/master) [![npm package](https://img.shields.io/npm/v/vue-style-loader.svg)](https://www.npmjs.com/package/vue-style-loader)

This is a fork based on [style-loader](https://github.com/webpack/style-loader). Similar to `style-loader`, you can chain it after `css-loader` to dynamically inject CSS into the document as style tags. However, since this is included as a dependency and used by default in `vue-loader`, in most cases you don't need to configure this loader yourself.

## Options

- **manualInject** (3.1.0+):

  Type: `boolean`. When importing the style from a non-vue-file, by default the style is injected as a side effect of the import. When `manualInject` is true, the imported style object exposes a `__inject__` method, which can then be called manually at appropriate timing. If called on the server, the method expects one argument which is the `ssrContext` to attach styles to.

  ``` js
  import styles from 'styles.scss'

  export default {
    beforeCreate() { // or create a mixin for this purpose
      if(styles.__inject__) {
        styles.__inject__(this.$ssrContext)
      }
    }

    render() {
      return <div class={styles.heading}>Hello World</div>
    }
  }
  ```

  Note this behavior is enabled automatically when `vue-style-loader` is used on styles imported within a `*.vue` file. The option is only exposed for advanced usage.

- **ssrId** (3.1.0+):

  Type: `boolean`. Add `data-vue-ssr-id` attribute to injected `<style>` tags even when not in Node.js. This can be used with pre-rendering (instead of SSR) to avoid duplicate style injection on hydration.

## Differences from `style-loader`

### Server-Side Rendering Support

When bundling with `target: 'node'`, the styles in all rendered components are collected and exposed on the Vue render context object as `context.styles`, which you can simply inline into your markup's `<head>`. If you are building a Vue SSR app, you probably should use this loader for CSS imported from JavaScript files too.

### Misc

- Does not support url mode and reference counting mode. Also removed `singleton` and `insertAt` query options. It always automatically pick the style insertion mechanism that makes most sense. If you need these capabilities you should probably use the original `style-loader` instead.

- Fixed the issue that root-relative URLs are interpreted against chrome:// urls and make source map URLs work for injected `<style>` tags in Chrome.

## License

MIT


code:
/*
  MIT License http://www.opensource.org/licenses/mit-license.php
  Author Tobias Koppers @sokra
  Modified by Evan You @yyx990803
*/
var loaderUtils = require('loader-utils')
var path = require('path')
var hash = require('hash-sum')
var qs = require('querystring')

module.exports = function () {}

module.exports.pitch = function (remainingRequest) {
  var isServer = this.target === 'node'
  var isProduction = this.minimize || process.env.NODE_ENV === 'production'
  var addStylesClientPath = loaderUtils.stringifyRequest(this, '!' + path.join(__dirname, 'lib/addStylesClient.js'))
  var addStylesServerPath = loaderUtils.stringifyRequest(this, '!' + path.join(__dirname, 'lib/addStylesServer.js'))
  var addStylesShadowPath = loaderUtils.stringifyRequest(this, '!' + path.join(__dirname, 'lib/addStylesShadow.js'))

  var request = loaderUtils.stringifyRequest(this, '!!' + remainingRequest)
  var relPath = path.relative(__dirname, this.resourcePath).replace(/\\/g, '/')
  var id = JSON.stringify(hash(request + relPath))
  var options = loaderUtils.getOptions(this) || {}

  // direct css import from js --> direct, or manually call `styles.__inject__(ssrContext)` with `manualInject` option
  // css import from vue file --> component lifecycle linked
  // style embedded in vue file --> component lifecycle linked
  var isVue = (
    /"vue":true/.test(remainingRequest) ||
    options.manualInject ||
    qs.parse(this.resourceQuery.slice(1)).vue != null
  )

  var shared = [
    '// style-loader: Adds some css to the DOM by adding a <style> tag',
    '',
    '// load the styles',
    'var content = require(' + request + ');',
    // get default export if list is an ES Module (CSS Loader v4+)
    "if(content.__esModule) content = content.default;",
    // content list format is [id, css, media, sourceMap]
    "if(typeof content === 'string') content = [[module.id, content, '']];",
    'if(content.locals) module.exports = content.locals;'
  ]

  // shadowMode is enabled in vue-cli with vue build --target web-component.
  // exposes the same __inject__ method like SSR
  if (options.shadowMode) {
    return shared.concat([
      '// add CSS to Shadow Root',
      'var add = require(' + addStylesShadowPath + ').default',
      'module.exports.__inject__ = function (shadowRoot) {',
      '  add(' + id + ', content, shadowRoot)',
      '};'
    ]).join('\n')
  } else if (!isServer) {
    // on the client: dynamic inject + hot-reload
    var code = [
      '// add the styles to the DOM',
      'var add = require(' + addStylesClientPath + ').default',
      'var update = add(' + id + ', content, ' + isProduction + ', ' + JSON.stringify(options) + ');'
    ]
    if (!isProduction) {
      code = code.concat([
        '// Hot Module Replacement',
        'if(module.hot) {',
        ' // When the styles change, update the <style> tags',
        ' if(!content.locals) {',
        '   module.hot.accept(' + request + ', function() {',
        '     var newContent = require(' + request + ');',
        '     if(newContent.__esModule) newContent = newContent.default;',
        "     if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];",
        '     update(newContent);',
        '   });',
        ' }',
        ' // When the module is disposed, remove the <style> tags',
        ' module.hot.dispose(function() { update(); });',
        '}'
      ])
    }
    return shared.concat(code).join('\n')
  } else {
    // on the server: attach to Vue SSR context
    if (isVue) {
      // inside *.vue file: expose a function so it can be called in
      // component's lifecycle hooks
      return shared.concat([
        '// add CSS to SSR context',
        'var add = require(' + addStylesServerPath + ').default',
        'module.exports.__inject__ = function (context) {',
        '  add(' + id + ', content, ' + isProduction + ', context)',
        '};'
      ]).join('\n')
    } else {
      // normal import
      return shared.concat([
        'require(' + addStylesServerPath + ').default(' + id + ', content, ' + isProduction + ')'
      ]).join('\n')
    }
  }
}


code:
/*
  MIT License http://www.opensource.org/licenses/mit-license.php
  Author Tobias Koppers @sokra
  Modified by Evan You @yyx990803
*/

import listToStyles from './listToStyles'

var hasDocument = typeof document !== 'undefined'

if (typeof DEBUG !== 'undefined' && DEBUG) {
  if (!hasDocument) {
    throw new Error(
    'vue-style-loader cannot be used in a non-browser environment. ' +
    "Use { target: 'node' } in your Webpack config to indicate a server-rendering environment."
  ) }
}

/*
type StyleObject = {
  id: number;
  parts: Array<StyleObjectPart>
}

type StyleObjectPart = {
  css: string;
  media: string;
  sourceMap: ?string
}
*/

var stylesInDom = {/*
  [id: number]: {
    id: number,
    refs: number,
    parts: Array<(obj?: StyleObjectPart) => void>
  }
*/}

var head = hasDocument && (document.head || document.getElementsByTagName('head')[0])
var singletonElement = null
var singletonCounter = 0
var isProduction = false
var noop = function () {}
var options = null
var ssrIdKey = 'data-vue-ssr-id'

// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
// tags it will allow on a page
var isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\b/.test(navigator.userAgent.toLowerCase())

export default function addStylesClient (parentId, list, _isProduction, _options) {
  isProduction = _isProduction

  options = _options || {}

  var styles = listToStyles(parentId, list)
  addStylesToDom(styles)

  return function update (newList) {
    var mayRemove = []
    for (var i = 0; i < styles.length; i++) {
      var item = styles[i]
      var domStyle = stylesInDom[item.id]
      domStyle.refs--
      mayRemove.push(domStyle)
    }
    if (newList) {
      styles = listToStyles(parentId, newList)
      addStylesToDom(styles)
    } else {
      styles = []
    }
    for (var i = 0; i < mayRemove.length; i++) {
      var domStyle = mayRemove[i]
      if (domStyle.refs === 0) {
        for (var j = 0; j < domStyle.parts.length; j++) {
          domStyle.parts[j]()
        }
        delete stylesInDom[domStyle.id]
      }
    }
  }
}

function addStylesToDom (styles /* Array<StyleObject> */) {
  for (var i = 0; i < styles.length; i++) {
    var item = styles[i]
    var domStyle = stylesInDom[item.id]
    if (domStyle) {
      domStyle.refs++
      for (var j = 0; j < domStyle.parts.length; j++) {
        domStyle.parts[j](item.parts[j])
      }
      for (; j < item.parts.length; j++) {
        domStyle.parts.push(addStyle(item.parts[j]))
      }
      if (domStyle.parts.length > item.parts.length) {
        domStyle.parts.length = item.parts.length
      }
    } else {
      var parts = []
      for (var j = 0; j < item.parts.length; j++) {
        parts.push(addStyle(item.parts[j]))
      }
      stylesInDom[item.id] = { id: item.id, refs: 1, parts: parts }
    }
  }
}

function createStyleElement () {
  var styleElement = document.createElement('style')
  styleElement.type = 'text/css'
  head.appendChild(styleElement)
  return styleElement
}

function addStyle (obj /* StyleObjectPart */) {
  var update, remove
  var styleElement = document.querySelector('style[' + ssrIdKey + '~="' + obj.id + '"]')

  if (styleElement) {
    if (isProduction) {
      // has SSR styles and in production mode.
      // simply do nothing.
      return noop
    } else {
      // has SSR styles but in dev mode.
      // for some reason Chrome can't handle source map in server-rendered
      // style tags - source maps in <style> only works if the style tag is
      // created and inserted dynamically. So we remove the server rendered
      // styles and inject new ones.
      styleElement.parentNode.removeChild(styleElement)
    }
  }

  if (isOldIE) {
    // use singleton mode for IE9.
    var styleIndex = singletonCounter++
    styleElement = singletonElement || (singletonElement = createStyleElement())
    update = applyToSingletonTag.bind(null, styleElement, styleIndex, false)
    remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true)
  } else {
    // use multi-style-tag mode in all other cases
    styleElement = createStyleElement()
    update = applyToTag.bind(null, styleElement)
    remove = function () {
      styleElement.parentNode.removeChild(styleElement)
    }
  }

  update(obj)

  return function updateStyle (newObj /* StyleObjectPart */) {
    if (newObj) {
      if (newObj.css === obj.css &&
          newObj.media === obj.media &&
          newObj.sourceMap === obj.sourceMap) {
        return
      }
      update(obj = newObj)
    } else {
      remove()
    }
  }
}

var replaceText = (function () {
  var textStore = []

  return function (index, replacement) {
    textStore[index] = replacement
    return textStore.filter(Boolean).join('\n')
  }
})()

function applyToSingletonTag (styleElement, index, remove, obj) {
  var css = remove ? '' : obj.css

  if (styleElement.styleSheet) {
    styleElement.styleSheet.cssText = replaceText(index, css)
  } else {
    var cssNode = document.createTextNode(css)
    var childNodes = styleElement.childNodes
    if (childNodes[index]) styleElement.removeChild(childNodes[index])
    if (childNodes.length) {
      styleElement.insertBefore(cssNode, childNodes[index])
    } else {
      styleElement.appendChild(cssNode)
    }
  }
}

function applyToTag (styleElement, obj) {
  var css = obj.css
  var media = obj.media
  var sourceMap = obj.sourceMap

  if (media) {
    styleElement.setAttribute('media', media)
  }
  if (options.ssrId) {
    styleElement.setAttribute(ssrIdKey, obj.id)
  }

  if (sourceMap) {
    // https://developer.chrome.com/devtools/docs/javascript-debugging
    // this makes source maps inside style tags work properly in Chrome
    css += '\n/*# sourceURL=' + sourceMap.sources[0] + ' */'
    // http://stackoverflow.com/a/26603875
    css += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + ' */'
  }

  if (styleElement.styleSheet) {
    styleElement.styleSheet.cssText = css
  } else {
    while (styleElement.firstChild) {
      styleElement.removeChild(styleElement.firstChild)
    }
    styleElement.appendChild(document.createTextNode(css))
  }
}


code:
import listToStyles from './listToStyles'

export default function addStylesServer (parentId, list, isProduction, context) {
  if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
    context = __VUE_SSR_CONTEXT__
  }
  if (context) {
    if (!context.hasOwnProperty('styles')) {
      Object.defineProperty(context, 'styles', {
        enumerable: true,
        get: function() {
          return renderStyles(context._styles)
        }
      })
      // expose renderStyles for vue-server-renderer (vuejs/#6353)
      context._renderStyles = renderStyles
    }

    var styles = context._styles || (context._styles = {})
    list = listToStyles(parentId, list)
    if (isProduction) {
      addStyleProd(styles, list)
    } else {
      addStyleDev(styles, list)
    }
  }
}

// In production, render as few style tags as possible.
// (mostly because IE9 has a limit on number of style tags)
function addStyleProd (styles, list) {
  for (var i = 0; i < list.length; i++) {
    var parts = list[i].parts
    for (var j = 0; j < parts.length; j++) {
      var part = parts[j]
      // group style tags by media types.
      var id = part.media || 'default'
      var style = styles[id]
      if (style) {
        if (style.ids.indexOf(part.id) < 0) {
          style.ids.push(part.id)
          style.css += '\n' + part.css
        }
      } else {
        styles[id] = {
          ids: [part.id],
          css: part.css,
          media: part.media
        }
      }
    }
  }
}

// In dev we use individual style tag for each module for hot-reload
// and source maps.
function addStyleDev (styles, list) {
  for (var i = 0; i < list.length; i++) {
    var parts = list[i].parts
    for (var j = 0; j < parts.length; j++) {
      var part = parts[j]
      styles[part.id] = {
        ids: [part.id],
        css: part.css,
        media: part.media
      }
    }
  }
}

function renderStyles (styles) {
  var css = ''
  for (var key in styles) {
    var style = styles[key]
    css += '<style data-vue-ssr-id="' + style.ids.join(' ') + '"' +
        (style.media ? ( ' media="' + style.media + '"' ) : '') + '>' +
        style.css + '</style>'
  }
  return css
}


code:
import listToStyles from './listToStyles'

export default function addStylesToShadowDOM (parentId, list, shadowRoot) {
  var styles = listToStyles(parentId, list)
  addStyles(styles, shadowRoot)
}

/*
type StyleObject = {
  id: number;
  parts: Array<StyleObjectPart>
}

type StyleObjectPart = {
  css: string;
  media: string;
  sourceMap: ?string
}
*/

function addStyles (styles /* Array<StyleObject> */, shadowRoot) {
  const injectedStyles =
    shadowRoot._injectedStyles ||
    (shadowRoot._injectedStyles = {})
  for (var i = 0; i < styles.length; i++) {
    var item = styles[i]
    var style = injectedStyles[item.id]
    if (!style) {
      for (var j = 0; j < item.parts.length; j++) {
        addStyle(item.parts[j], shadowRoot)
      }
      injectedStyles[item.id] = true
    }
  }
}

function createStyleElement (shadowRoot) {
  var styleElement = document.createElement('style')
  styleElement.type = 'text/css'
  shadowRoot.appendChild(styleElement)
  return styleElement
}

function addStyle (obj /* StyleObjectPart */, shadowRoot) {
  var styleElement = createStyleElement(shadowRoot)
  var css = obj.css
  var media = obj.media
  var sourceMap = obj.sourceMap

  if (media) {
    styleElement.setAttribute('media', media)
  }

  if (sourceMap) {
    // https://developer.chrome.com/devtools/docs/javascript-debugging
    // this makes source maps inside style tags work properly in Chrome
    css += '\n/*# sourceURL=' + sourceMap.sources[0] + ' */'
    // http://stackoverflow.com/a/26603875
    css += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + ' */'
  }

  if (styleElement.styleSheet) {
    styleElement.styleSheet.cssText = css
  } else {
    while (styleElement.firstChild) {
      styleElement.removeChild(styleElement.firstChild)
    }
    styleElement.appendChild(document.createTextNode(css))
  }
}


code:
/**
 * Translates the list format produced by css-loader into something
 * easier to manipulate.
 */
export default function listToStyles (parentId, list) {
  var styles = []
  var newStyles = {}
  for (var i = 0; i < list.length; i++) {
    var item = list[i]
    var id = item[0]
    var css = item[1]
    var media = item[2]
    var sourceMap = item[3]
    var part = {
      id: parentId + ':' + i,
      css: css,
      media: media,
      sourceMap: sourceMap
    }
    if (!newStyles[id]) {
      styles.push(newStyles[id] = { id: id, parts: [part] })
    } else {
      newStyles[id].parts.push(part)
    }
  }
  return styles
}


code:
# editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false


code:
# 1.0.2 Quick Sort

- Sorts object keys so that property order doesn't affect outcome

# 1.0.1 Perfect Circle

- Guard against circular references

# 1.0.0 IPO

- Initial Public Release


code:
'use strict';

function pad (hash, len) {
  while (hash.length < len) {
    hash = '0' + hash;
  }
  return hash;
}

function fold (hash, text) {
  var i;
  var chr;
  var len;
  if (text.length === 0) {
    return hash;
  }
  for (i = 0, len = text.length; i < len; i++) {
    chr = text.charCodeAt(i);
    hash = ((hash << 5) - hash) + chr;
    hash |= 0;
  }
  return hash < 0 ? hash * -2 : hash;
}

function foldObject (hash, o, seen) {
  return Object.keys(o).sort().reduce(foldKey, hash);
  function foldKey (hash, key) {
    return foldValue(hash, o[key], key, seen);
  }
}

function foldValue (input, value, key, seen) {
  var hash = fold(fold(fold(input, key), toString(value)), typeof value);
  if (value === null) {
    return fold(hash, 'null');
  }
  if (value === undefined) {
    return fold(hash, 'undefined');
  }
  if (typeof value === 'object') {
    if (seen.indexOf(value) !== -1) {
      return fold(hash, '[Circular]' + key);
    }
    seen.push(value);
    return foldObject(hash, value, seen);
  }
  return fold(hash, value.toString());
}

function toString (o) {
  return Object.prototype.toString.call(o);
}

function sum (o) {
  return pad(foldValue(0, o, '', []).toString(16), 8);
}

module.exports = sum;


hash-sum

description: Blazing fast unique hash generator

license: MIT

type: git

test: jshint . && tape test.js


code:
# hash-sum

> blazing fast unique hash generator

# install

```shell
npm i hash-sum -S
```

# features

- no dependencies
- minimal footprint
- works in all of node.js, io.js, and the browser
- hashes functions based on their source code
- produces different hashes for different object types
- support for circular references in objects
- ignores property assignment order

# `sum(value)`

yields a four-byte hexadecimal hash based off of `value`.

```
# creates unique hashes
 creates unique hashes
4d237d49 from: [ 0, 1, 2, 3 ]
766ec173 from: { url: 12 }
2f473108 from: { headers: 12 }
23308836 from: { headers: 122 }
062bce44 from: { headers: '122' }
acb9f66e from: { headers: { accept: 'text/plain' } }
1c365a2d from: { payload: [ 0, 1, 2, 3 ], headers: [ { a: 'b' } ] }
7319ae9d from: { a: [Function] }
8a3a0e86 from: { b: [Function] }
b6d7f5d4 from: { b: [Function] }
6c95fc65 from: function () {}
2941766e from: function (a) {}
294f8def from: function (b) {}
2d9c0cb8 from: function (a) { return a;}
ed5c63fc from: function (a) {return a;}
bba68bf6 from: ''
2d27667d from: 'null'
774b96ed from: 'false'
2d2a1684 from: 'true'
8daa1a0c from: '0'
8daa1a0a from: '1'
e38f07cc from: 'void 0'
6037ea1a from: 'undefined'
9b7df12e from: null
3c206f76 from: false
01e34ba8 from: true
1a96284a from: 0
1a96284b from: 1
29172c1a from: undefined
4505230f from: {}
3718c6e8 from: { a: {}, b: {} }
5d844489 from: []
938eaaf0 from: Tue Jul 14 2015 15:35:36 GMT-0300 (ART)
dfe5fb2e from: global
ok 1 should be equal
```

# license

MIT


code:
'use strict';

var _ = require('lodash');
var test = require('tape');
var sum = require('./');

test('creates unique hashes', function (t) {
  var results = [];
  sub([0,1,2,3]);
  sub({url:12});
  sub({headers:12});
  sub({headers:122});
  sub({headers:'122'});
  sub({headers:{accept:'text/plain'}});
  sub({payload:[0,1,2,3],headers:[{a:'b'}]});
  sub({a:function () {}});
  sub({b:function () {}});
  sub({b:function (a) {}});
  sub(function () {});
  sub(function (a) {});
  sub(function (b) {});
  sub(function (a) { return a;});
  sub(function (a) {return a;});
  sub('');
  sub('null');
  sub('false');
  sub('true');
  sub('0');
  sub('1');
  sub('void 0');
  sub('undefined');
  sub(null);
  sub(false);
  sub(true);
  sub(0);
  sub(1);
  sub(void 0);
  sub({});
  sub({a:{},b:{}});
  sub([]);
  sub(new Date());
  sub(global, 'global');
  t.equal(results.length, _.uniq(results).length);
  t.end();

  function sub (value, name) {
    var hash = sum(value);
    results.push(hash);
    console.log('%s from:', hash, name || value);
  }
});

test('hashes clash if same properties', function (t) {
  equals({a:'1'},{a:'1'});
  equals({a:'1',b:1},{b:1,a:'1'});
  t.end();

  function equals (a, b) {
    t.equal(sum(a), sum(b));
  }
});


vue-style-loader

author: Evan You

description: Vue.js style loader module for webpack

test: jest

prepublishOnly: conventional-changelog -p angular -r 2 -i CHANGELOG.md -s


code:
import addStylesClient from '../lib/addStylesClient'
import addStylesServer from '../lib/addStylesServer'

const mockedList = [
  [1, 'h1 { color: red; }', ''],
  [1, 'p { color: green; }', ''],
  [2, 'span { color: blue; }', ''],
  [2, 'span { color: blue; }', 'print']
]

test('addStylesClient (dev)', () => {
  const update = addStylesClient('foo', mockedList, false)
  assertStylesMatch(mockedList)
  const mockedList2 = mockedList.slice(1, 3)
  update(mockedList2)
  assertStylesMatch(mockedList2)
  update()
  expect(document.querySelectorAll('style').length).toBe(0)
})

test('addStylesClient (prod)', () => {
  const update = addStylesClient('foo', mockedList, true)
  assertStylesMatch(mockedList)
  const mockedList2 = mockedList.slice(2)
  update(mockedList2)
  assertStylesMatch(mockedList2)
  update()
  expect(document.querySelectorAll('style').length).toBe(0)
})

test('addStylesClient (dev + ssr)', () => {
  mockSSRTags(mockedList, 'foo')
  const update = addStylesClient('foo', mockedList, false)
  assertStylesMatch(mockedList)
  update()
  expect(document.querySelectorAll('style').length).toBe(0)
})

test('addStylesClient (prod + ssr)', () => {
  mockProdSSRTags(mockedList, 'foo')
  const update = addStylesClient('foo', mockedList, true)
  expect(document.querySelectorAll('style').length).toBe(1)
})

test('addStylesServer (dev)', () => {
  const context = global.__VUE_SSR_CONTEXT__ = {}
  addStylesServer('foo', mockedList, false)
  expect(context.styles).toBe(
    `<style data-vue-ssr-id="foo:0">h1 { color: red; }</style>` +
    `<style data-vue-ssr-id="foo:1">p { color: green; }</style>` +
    `<style data-vue-ssr-id="foo:2">span { color: blue; }</style>` +
    `<style data-vue-ssr-id="foo:3" media="print">span { color: blue; }</style>`
  )
})

test('addStylesServer (prod)', () => {
  const context = global.__VUE_SSR_CONTEXT__ = {}
  addStylesServer('foo', mockedList, true)
  expect(context.styles).toBe(
    `<style data-vue-ssr-id="foo:0 foo:1 foo:2">` +
      `h1 { color: red; }\np { color: green; }\nspan { color: blue; }` +
    `</style>` +
    `<style data-vue-ssr-id="foo:3" media="print">span { color: blue; }</style>`
  )
})

// --- helpers ---

function assertStylesMatch (list) {
  const styles = document.querySelectorAll('style')
  expect(styles.length).toBe(list.length)
  ;[].forEach.call(styles, (style, i) => {
    expect(style.textContent.indexOf(list[i][1]) > -1).toBe(true)
  })
}

function mockSSRTags (list, parentId) {
  list.forEach((item, i) => {
    const style = document.createElement('style')
    style.setAttribute('data-vue-ssr-id', `${parentId}:${i}`)
    style.textContent = item[1]
    if (item[2]) {
      style.setAttribute('media', item[2])
    }
    document.head.appendChild(style)
  })
}

function mockProdSSRTags (list, parentId) {
  const style = document.createElement('style')
  style.setAttribute('data-vue-ssr-id', list.map((item, i) => `${parentId}:${i}`).join(' '))
  style.textContent = list.map(item => item[1]).join('\n')
  document.head.appendChild(style)
}


code:
This is an internal package used by `vue-loader` and `vueify`. It processes the raw render functions generated by `vue-template-compiler` to:

1. add support to ES2015 features in template expressions via Buble. (see [supported features here](https://buble.surge.sh/guide/#supported-features)).

**Note:** since version 1.8.0, object rest spread usage inside templates are transpiled to `Object.assign` calls by default. This means if you need to support IE, you will need to polyfill `Object.assign`. (Latest version of Vue CLI will do this for you).

2. remove the `with` block inside render functions to make it strict-mode compliant. This is performed only at build time so that the base template compiler can be extremely small and lightweight.

The buble implementation is built from a fork at https://github.com/yyx990803/buble


code:
var buble = require('./buble.js')

// selectively support some handy ES2015 features in templates.
var defaultOptions = {
  transforms: {
    modules: false,
    // this is a custom feature for stripping with from Vue render functions.
    stripWith: true,
    // custom feature ensures with context targets functional render
    stripWithFunctional: false
  },
  // allow spread...
  objectAssign: 'Object.assign'
}

module.exports = function transpile (code, opts) {
  if (opts) {
    opts = Object.assign({}, defaultOptions, opts)
    opts.transforms = Object.assign({}, defaultOptions.transforms, opts.transforms)
  } else {
    opts = defaultOptions
  }
  var code = buble.transform(code, opts).code
  // console.log(code)
  return code
}


description: Post compiler for Vue template render functions to support ES2015+ features

build: cd buble && npm run build && cp dist/buble-browser-deps.umd.js ../buble.js

prepublishOnly: jest && npm run build


code:
# vue

## Which dist file to use?

### From CDN or without a Bundler

- **`vue(.runtime).global(.prod).js`**:
  - For direct use via `<script src="...">` in the browser. Exposes the `Vue` global.
  - Note that global builds are not [UMD](https://github.com/umdjs/umd) builds.  They are built as [IIFEs](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) and is only meant for direct use via `<script src="...">`.
  - In-browser template compilation:
    - **`vue.global.js`** is the "full" build that includes both the compiler and the runtime so it supports compiling templates on the fly.
    - **`vue.runtime.global.js`** contains only the runtime and requires templates to be pre-compiled during a build step.
  - Inlines all Vue core internal packages - i.e. it's a single file with no dependencies on other files. This means you **must** import everything from this file and this file only to ensure you are getting the same instance of code.
  - Contains hard-coded prod/dev branches, and the prod build is pre-minified. Use the `*.prod.js` files for production.

- **`vue(.runtime).esm-browser(.prod).js`**:
  - For usage via native ES modules imports (in browser via `<script type="module">`.
  - Shares the same runtime compilation, dependency inlining and hard-coded prod/dev behavior with the global build.

### With a Bundler

- **`vue(.runtime).esm-bundler.js`**:

  - For use with bundlers like `webpack`, `rollup` and `parcel`.
  - Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler)
  - Does not ship minified builds (to be done together with the rest of the code after bundling)
  - Imports dependencies (e.g. `@vue/runtime-core`, `@vue/runtime-compiler`)
    - Imported dependencies are also `esm-bundler` builds and will in turn import their dependencies (e.g. `@vue/runtime-core` imports `@vue/reactivity`)
    - This means you **can** install/import these deps individually without ending up with different instances of these dependencies, but you must make sure they all resolve to the same version.
  - In-browser template compilation:
    - **`vue.runtime.esm-bundler.js` (default)** is runtime only, and requires all templates to be pre-compiled. This is the default entry for bundlers (via `module` field in `package.json`) because when using a bundler templates are typically pre-compiled (e.g. in `*.vue` files).
    - **`vue.esm-bundler.js`**: includes the runtime compiler. Use this if you are using a bundler but still want runtime template compilation (e.g. in-DOM templates or templates via inline JavaScript strings). You will need to configure your bundler to alias `vue` to this file.

#### Bundler Build Feature Flags

[Detailed Reference on vuejs.org](https://vuejs.org/api/compile-time-flags.html)

`esm-bundler` builds of Vue expose global feature flags that can be overwritten at compile time:

- `__VUE_OPTIONS_API__`
  - Default: `true`
  - Enable / disable Options API support

- `__VUE_PROD_DEVTOOLS__`
  - Default: `false`
  - Enable / disable devtools support in production

- `__VUE_PROD_HYDRATION_MISMATCH_DETAILS__`
  - Default: `false`
  - Enable / disable detailed warnings for hydration mismatches in production

The build will work without configuring these flags, however it is **strongly recommended** to properly configure them in order to get proper tree-shaking in the final bundle.

### For Server-Side Rendering

- **`vue.cjs(.prod).js`**:
  - For use in Node.js server-side rendering via `require()`.
  - If you bundle your app with webpack with `target: 'node'` and properly externalize `vue`, this is the build that will be loaded.
  - The dev/prod files are pre-built, but the appropriate file is automatically required based on `process.env.NODE_ENV`.


code:
module.exports = require('@vue/compiler-sfc')

require('./register-ts.js')


code:
export * from '@vue/compiler-sfc'

import './register-ts.js'


code:
if (typeof require !== 'undefined') {
  require('@vue/compiler-sfc').registerTS(() => require('typescript'))
}


code:
/**
* vue v3.4.31
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var compilerDom = require('@vue/compiler-dom');
var runtimeDom = require('@vue/runtime-dom');
var shared = require('@vue/shared');

function _interopNamespaceDefault(e) {
  var n = Object.create(null);
  if (e) {
    for (var k in e) {
      n[k] = e[k];
    }
  }
  n.default = e;
  return Object.freeze(n);
}

var runtimeDom__namespace = /*#__PURE__*/_interopNamespaceDefault(runtimeDom);

const compileCache = /* @__PURE__ */ new WeakMap();
function getCache(options) {
  let c = compileCache.get(options != null ? options : shared.EMPTY_OBJ);
  if (!c) {
    c = /* @__PURE__ */ Object.create(null);
    compileCache.set(options != null ? options : shared.EMPTY_OBJ, c);
  }
  return c;
}
function compileToFunction(template, options) {
  if (!shared.isString(template)) {
    if (template.nodeType) {
      template = template.innerHTML;
    } else {
      runtimeDom.warn(`invalid template option: `, template);
      return shared.NOOP;
    }
  }
  const key = template;
  const cache = getCache(options);
  const cached = cache[key];
  if (cached) {
    return cached;
  }
  if (template[0] === "#") {
    const el = document.querySelector(template);
    if (!el) {
      runtimeDom.warn(`Template element not found or is empty: ${template}`);
    }
    template = el ? el.innerHTML : ``;
  }
  const opts = shared.extend(
    {
      hoistStatic: true,
      onError: onError ,
      onWarn: (e) => onError(e, true)
    },
    options
  );
  if (!opts.isCustomElement && typeof customElements !== "undefined") {
    opts.isCustomElement = (tag) => !!customElements.get(tag);
  }
  const { code } = compilerDom.compile(template, opts);
  function onError(err, asWarning = false) {
    const message = asWarning ? err.message : `Template compilation error: ${err.message}`;
    const codeFrame = err.loc && shared.generateCodeFrame(
      template,
      err.loc.start.offset,
      err.loc.end.offset
    );
    runtimeDom.warn(codeFrame ? `${message}
${codeFrame}` : message);
  }
  const render = new Function("Vue", code)(runtimeDom__namespace);
  render._rc = true;
  return cache[key] = render;
}
runtimeDom.registerRuntimeCompiler(compileToFunction);

exports.compile = compileToFunction;
Object.keys(runtimeDom).forEach(function (k) {
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = runtimeDom[k];
});


code:
/**
* vue v3.4.31
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var compilerDom = require('@vue/compiler-dom');
var runtimeDom = require('@vue/runtime-dom');
var shared = require('@vue/shared');

function _interopNamespaceDefault(e) {
  var n = Object.create(null);
  if (e) {
    for (var k in e) {
      n[k] = e[k];
    }
  }
  n.default = e;
  return Object.freeze(n);
}

var runtimeDom__namespace = /*#__PURE__*/_interopNamespaceDefault(runtimeDom);

const compileCache = /* @__PURE__ */ new WeakMap();
function getCache(options) {
  let c = compileCache.get(options != null ? options : shared.EMPTY_OBJ);
  if (!c) {
    c = /* @__PURE__ */ Object.create(null);
    compileCache.set(options != null ? options : shared.EMPTY_OBJ, c);
  }
  return c;
}
function compileToFunction(template, options) {
  if (!shared.isString(template)) {
    if (template.nodeType) {
      template = template.innerHTML;
    } else {
      return shared.NOOP;
    }
  }
  const key = template;
  const cache = getCache(options);
  const cached = cache[key];
  if (cached) {
    return cached;
  }
  if (template[0] === "#") {
    const el = document.querySelector(template);
    template = el ? el.innerHTML : ``;
  }
  const opts = shared.extend(
    {
      hoistStatic: true,
      onError: void 0,
      onWarn: shared.NOOP
    },
    options
  );
  if (!opts.isCustomElement && typeof customElements !== "undefined") {
    opts.isCustomElement = (tag) => !!customElements.get(tag);
  }
  const { code } = compilerDom.compile(template, opts);
  const render = new Function("Vue", code)(runtimeDom__namespace);
  render._rc = true;
  return cache[key] = render;
}
runtimeDom.registerRuntimeCompiler(compileToFunction);

exports.compile = compileToFunction;
Object.keys(runtimeDom).forEach(function (k) {
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) exports[k] = runtimeDom[k];
});


code:
import { CompilerOptions } from '@vue/compiler-dom';
import { RenderFunction } from '@vue/runtime-dom';
export * from '@vue/runtime-dom';

export declare function compileToFunction(template: string | HTMLElement, options?: CompilerOptions): RenderFunction;

export { compileToFunction as compile };


code:
/**
* vue v3.4.31
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/
import * as runtimeDom from '@vue/runtime-dom';
import { initCustomFormatter, registerRuntimeCompiler, warn } from '@vue/runtime-dom';
export * from '@vue/runtime-dom';
import { compile } from '@vue/compiler-dom';
import { isString, NOOP, extend, generateCodeFrame, EMPTY_OBJ } from '@vue/shared';

function initDev() {
  {
    initCustomFormatter();
  }
}

if (!!(process.env.NODE_ENV !== "production")) {
  initDev();
}
const compileCache = /* @__PURE__ */ new WeakMap();
function getCache(options) {
  let c = compileCache.get(options != null ? options : EMPTY_OBJ);
  if (!c) {
    c = /* @__PURE__ */ Object.create(null);
    compileCache.set(options != null ? options : EMPTY_OBJ, c);
  }
  return c;
}
function compileToFunction(template, options) {
  if (!isString(template)) {
    if (template.nodeType) {
      template = template.innerHTML;
    } else {
      !!(process.env.NODE_ENV !== "production") && warn(`invalid template option: `, template);
      return NOOP;
    }
  }
  const key = template;
  const cache = getCache(options);
  const cached = cache[key];
  if (cached) {
    return cached;
  }
  if (template[0] === "#") {
    const el = document.querySelector(template);
    if (!!(process.env.NODE_ENV !== "production") && !el) {
      warn(`Template element not found or is empty: ${template}`);
    }
    template = el ? el.innerHTML : ``;
  }
  const opts = extend(
    {
      hoistStatic: true,
      onError: !!(process.env.NODE_ENV !== "production") ? onError : void 0,
      onWarn: !!(process.env.NODE_ENV !== "production") ? (e) => onError(e, true) : NOOP
    },
    options
  );
  if (!opts.isCustomElement && typeof customElements !== "undefined") {
    opts.isCustomElement = (tag) => !!customElements.get(tag);
  }
  const { code } = compile(template, opts);
  function onError(err, asWarning = false) {
    const message = asWarning ? err.message : `Template compilation error: ${err.message}`;
    const codeFrame = err.loc && generateCodeFrame(
      template,
      err.loc.start.offset,
      err.loc.end.offset
    );
    warn(codeFrame ? `${message}
${codeFrame}` : message);
  }
  const render = new Function("Vue", code)(runtimeDom);
  render._rc = true;
  return cache[key] = render;
}
registerRuntimeCompiler(compileToFunction);

export { compileToFunction as compile };


code:
/**
* vue v3.4.31
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/
import { initCustomFormatter, warn } from '@vue/runtime-dom';
export * from '@vue/runtime-dom';

function initDev() {
  {
    initCustomFormatter();
  }
}

if (!!(process.env.NODE_ENV !== "production")) {
  initDev();
}
const compile = () => {
  if (!!(process.env.NODE_ENV !== "production")) {
    warn(
      `Runtime compilation is not supported in this build of Vue.` + (` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".` )
    );
  }
};

export { compile };


code:
'use strict'

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./dist/vue.cjs.prod.js')
} else {
  module.exports = require('./dist/vue.cjs.js')
}


code:
/* eslint-disable @typescript-eslint/prefer-ts-expect-error */
import type { NativeElements, ReservedProps, VNode } from '@vue/runtime-dom'

/**
 * JSX namespace for usage with @jsxImportsSource directive
 * when ts compilerOptions.jsx is 'react-jsx' or 'react-jsxdev'
 * https://www.typescriptlang.org/tsconfig#jsxImportSource
 */
export { h as jsx, h as jsxDEV, Fragment } from '@vue/runtime-dom'

export namespace JSX {
  export interface Element extends VNode {}
  export interface ElementClass {
    $props: {}
  }
  export interface ElementAttributesProperty {
    $props: {}
  }
  export interface IntrinsicElements extends NativeElements {
    // allow arbitrary elements
    // @ts-ignore suppress ts:2374 = Duplicate string index signature.
    [name: string]: any
  }
  export interface IntrinsicAttributes extends ReservedProps {}
}


code:
const { h, Fragment } = require('vue')

function jsx(type, props, key) {
  const { children } = props
  delete props.children
  if (arguments.length > 2) {
    props.key = key
  }
  return h(type, props, children)
}

exports.jsx = jsx
exports.jsxs = jsx
exports.jsxDEV = jsx
exports.Fragment = Fragment


code:
import { h, Fragment } from 'vue'

function jsx(type, props, key) {
  const { children } = props
  delete props.children
  if (arguments.length > 2) {
    props.key = key
  }
  return h(type, props, children)
}

export { Fragment, jsx, jsx as jsxs, jsx as jsxDEV }


code:
/* eslint-disable @typescript-eslint/prefer-ts-expect-error */
// global JSX namespace registration
// somehow we have to copy=pase the jsx-runtime types here to make TypeScript happy
import type { NativeElements, ReservedProps, VNode } from '@vue/runtime-dom'

declare global {
  namespace JSX {
    export interface Element extends VNode {}
    export interface ElementClass {
      $props: {}
    }
    export interface ElementAttributesProperty {
      $props: {}
    }
    export interface IntrinsicElements extends NativeElements {
      // allow arbitrary elements
      // @ts-ignore suppress ts:2374 = Duplicate string index signature.
      [name: string]: any
    }
    export interface IntrinsicAttributes extends ReservedProps {}
  }
}


vue

description: The progressive JavaScript framework for building modern web UI.

Vue

formats: esm-bundler esm-bundler-runtime cjs global global-runtime esm-browser esm-browser-runtime


code:
# watchpack

Wrapper library for directory and file watching.

[![Test](https://github.com/webpack/watchpack/actions/workflows/test.yml/badge.svg)](https://github.com/webpack/watchpack/actions/workflows/test.yml)
[![Codecov](https://codecov.io/gh/webpack/watchpack/graph/badge.svg?token=8xk2OrrxWm)](https://codecov.io/gh/webpack/watchpack)
[![Downloads](https://img.shields.io/npm/dm/watchpack.svg)](https://www.npmjs.com/package/watchpack)

## Concept

watchpack high level API doesn't map directly to watchers. Instead a three level architecture ensures that for each directory only a single watcher exists.

- The high level API requests `DirectoryWatchers` from a `WatcherManager`, which ensures that only a single `DirectoryWatcher` per directory is created.
- A user-faced `Watcher` can be obtained from a `DirectoryWatcher` and provides a filtered view on the `DirectoryWatcher`.
- Reference-counting is used on the `DirectoryWatcher` and `Watcher` to decide when to close them.
- The real watchers are created by the `DirectoryWatcher`.
- Files are never watched directly. This should keep the watcher count low.
- Watching can be started in the past. This way watching can start after file reading.
- Symlinks are not followed, instead the symlink is watched.

## API

```javascript
var Watchpack = require("watchpack");

var wp = new Watchpack({
	// options:
	aggregateTimeout: 1000,
	// fire "aggregated" event when after a change for 1000ms no additional change occurred
	// aggregated defaults to undefined, which doesn't fire an "aggregated" event

	poll: true,
	// poll: true - use polling with the default interval
	// poll: 10000 - use polling with an interval of 10s
	// poll defaults to undefined, which prefer native watching methods
	// Note: enable polling when watching on a network path
	// When WATCHPACK_POLLING environment variable is set it will override this option

	followSymlinks: true,
	// true: follows symlinks and watches symlinks and real files
	//   (This makes sense when symlinks has not been resolved yet, comes with a performance hit)
	// false (default): watches only specified item they may be real files or symlinks
	//   (This makes sense when symlinks has already been resolved)

	ignored: "**/.git"
	// ignored: "string" - a glob pattern for files or folders that should not be watched
	// ignored: ["string", "string"] - multiple glob patterns that should be ignored
	// ignored: /regexp/ - a regular expression for files or folders that should not be watched
	// ignored: (entry) => boolean - an arbitrary function which must return truthy to ignore an entry
	// For all cases expect the arbitrary function the path will have path separator normalized to '/'.
	// All subdirectories are ignored too
});

// Watchpack.prototype.watch({
//   files: Iterable<string>,
//   directories: Iterable<string>,
//   missing: Iterable<string>,
//   startTime?: number
// })
wp.watch({
	files: listOfFiles,
	directories: listOfDirectories,
	missing: listOfNotExistingItems,
	startTime: Date.now() - 10000
});
// starts watching these files and directories
// calling this again will override the files and directories
// files: can be files or directories, for files: content and existence changes are tracked
//        for directories: only existence and timestamp changes are tracked
// directories: only directories, directory content (and content of children, ...) and
//              existence changes are tracked.
//              assumed to exist, when directory is not found without further information a remove event is emitted
// missing: can be files or directorees,
//          only existence changes are tracked
//          expected to not exist, no remove event is emitted when not found initially
// files and directories are assumed to exist, when they are not found without further information a remove event is emitted
// missing is assumed to not exist and no remove event is emitted

wp.on("change", function(filePath, mtime, explanation) {
	// filePath: the changed file
	// mtime: last modified time for the changed file
	// explanation: textual information how this change was detected
});

wp.on("remove", function(filePath, explanation) {
	// filePath: the removed file or directory
	// explanation: textual information how this change was detected
});

wp.on("aggregated", function(changes, removals) {
	// changes: a Set of all changed files
	// removals: a Set of all removed files
	// watchpack gives up ownership on these Sets.
});

// Watchpack.prototype.pause()
wp.pause();
// stops emitting events, but keeps watchers open
// next "watch" call can reuse the watchers
// The watcher will keep aggregating events
// which can be received with getAggregated()

// Watchpack.prototype.close()
wp.close();
// stops emitting events and closes all watchers

// Watchpack.prototype.getAggregated(): { changes: Set<string>, removals: Set<string> }
const { changes, removals } = wp.getAggregated();
// returns the current aggregated info and removes that from the watcher
// The next aggregated event won't include that info and will only emitted
// when futher changes happen
// Can also be used when paused.

// Watchpack.prototype.collectTimeInfoEntries(fileInfoEntries: Map<string, Entry>, directoryInfoEntries: Map<string, Entry>)
wp.collectTimeInfoEntries(fileInfoEntries, directoryInfoEntries);
// collects time info objects for all known files and directories
// this include info from files not directly watched
// key: absolute path, value: object with { safeTime, timestamp }
// safeTime: a point in time at which it is safe to say all changes happened before that
// timestamp: only for files, the mtime timestamp of the file

// Watchpack.prototype.getTimeInfoEntries()
var fileTimes = wp.getTimeInfoEntries();
// returns a Map with all known time info objects for files and directories
// similar to collectTimeInfoEntries but returns a single map with all entries

// (deprecated)
// Watchpack.prototype.getTimes()
var fileTimes = wp.getTimes();
// returns an object with all known change times for files
// this include timestamps from files not directly watched
// key: absolute path, value: timestamp as number
```


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const EventEmitter = require("events").EventEmitter;
const fs = require("graceful-fs");
const path = require("path");

const watchEventSource = require("./watchEventSource");

const EXISTANCE_ONLY_TIME_ENTRY = Object.freeze({});

let FS_ACCURACY = 2000;

const IS_OSX = require("os").platform() === "darwin";
const WATCHPACK_POLLING = process.env.WATCHPACK_POLLING;
const FORCE_POLLING =
	`${+WATCHPACK_POLLING}` === WATCHPACK_POLLING
		? +WATCHPACK_POLLING
		: !!WATCHPACK_POLLING && WATCHPACK_POLLING !== "false";

function withoutCase(str) {
	return str.toLowerCase();
}

function needCalls(times, callback) {
	return function() {
		if (--times === 0) {
			return callback();
		}
	};
}

class Watcher extends EventEmitter {
	constructor(directoryWatcher, filePath, startTime) {
		super();
		this.directoryWatcher = directoryWatcher;
		this.path = filePath;
		this.startTime = startTime && +startTime;
	}

	checkStartTime(mtime, initial) {
		const startTime = this.startTime;
		if (typeof startTime !== "number") return !initial;
		return startTime <= mtime;
	}

	close() {
		this.emit("closed");
	}
}

class DirectoryWatcher extends EventEmitter {
	constructor(watcherManager, directoryPath, options) {
		super();
		if (FORCE_POLLING) {
			options.poll = FORCE_POLLING;
		}
		this.watcherManager = watcherManager;
		this.options = options;
		this.path = directoryPath;
		// safeTime is the point in time after which reading is safe to be unchanged
		// timestamp is a value that should be compared with another timestamp (mtime)
		/** @type {Map<string, { safeTime: number, timestamp: number }} */
		this.files = new Map();
		/** @type {Map<string, number>} */
		this.filesWithoutCase = new Map();
		this.directories = new Map();
		this.lastWatchEvent = 0;
		this.initialScan = true;
		this.ignored = options.ignored || (() => false);
		this.nestedWatching = false;
		this.polledWatching =
			typeof options.poll === "number"
				? options.poll
				: options.poll
				? 5007
				: false;
		this.timeout = undefined;
		this.initialScanRemoved = new Set();
		this.initialScanFinished = undefined;
		/** @type {Map<string, Set<Watcher>>} */
		this.watchers = new Map();
		this.parentWatcher = null;
		this.refs = 0;
		this._activeEvents = new Map();
		this.closed = false;
		this.scanning = false;
		this.scanAgain = false;
		this.scanAgainInitial = false;

		this.createWatcher();
		this.doScan(true);
	}

	createWatcher() {
		try {
			if (this.polledWatching) {
				this.watcher = {
					close: () => {
						if (this.timeout) {
							clearTimeout(this.timeout);
							this.timeout = undefined;
						}
					}
				};
			} else {
				if (IS_OSX) {
					this.watchInParentDirectory();
				}
				this.watcher = watchEventSource.watch(this.path);
				this.watcher.on("change", this.onWatchEvent.bind(this));
				this.watcher.on("error", this.onWatcherError.bind(this));
			}
		} catch (err) {
			this.onWatcherError(err);
		}
	}

	forEachWatcher(path, fn) {
		const watchers = this.watchers.get(withoutCase(path));
		if (watchers !== undefined) {
			for (const w of watchers) {
				fn(w);
			}
		}
	}

	setMissing(itemPath, initial, type) {
		if (this.initialScan) {
			this.initialScanRemoved.add(itemPath);
		}

		const oldDirectory = this.directories.get(itemPath);
		if (oldDirectory) {
			if (this.nestedWatching) oldDirectory.close();
			this.directories.delete(itemPath);

			this.forEachWatcher(itemPath, w => w.emit("remove", type));
			if (!initial) {
				this.forEachWatcher(this.path, w =>
					w.emit("change", itemPath, null, type, initial)
				);
			}
		}

		const oldFile = this.files.get(itemPath);
		if (oldFile) {
			this.files.delete(itemPath);
			const key = withoutCase(itemPath);
			const count = this.filesWithoutCase.get(key) - 1;
			if (count <= 0) {
				this.filesWithoutCase.delete(key);
				this.forEachWatcher(itemPath, w => w.emit("remove", type));
			} else {
				this.filesWithoutCase.set(key, count);
			}

			if (!initial) {
				this.forEachWatcher(this.path, w =>
					w.emit("change", itemPath, null, type, initial)
				);
			}
		}
	}

	setFileTime(filePath, mtime, initial, ignoreWhenEqual, type) {
		const now = Date.now();

		if (this.ignored(filePath)) return;

		const old = this.files.get(filePath);

		let safeTime, accuracy;
		if (initial) {
			safeTime = Math.min(now, mtime) + FS_ACCURACY;
			accuracy = FS_ACCURACY;
		} else {
			safeTime = now;
			accuracy = 0;

			if (old && old.timestamp === mtime && mtime + FS_ACCURACY < now) {
				// We are sure that mtime is untouched
				// This can be caused by some file attribute change
				// e. g. when access time has been changed
				// but the file content is untouched
				return;
			}
		}

		if (ignoreWhenEqual && old && old.timestamp === mtime) return;

		this.files.set(filePath, {
			safeTime,
			accuracy,
			timestamp: mtime
		});

		if (!old) {
			const key = withoutCase(filePath);
			const count = this.filesWithoutCase.get(key);
			this.filesWithoutCase.set(key, (count || 0) + 1);
			if (count !== undefined) {
				// There is already a file with case-insensitive-equal name
				// On a case-insensitive filesystem we may miss the renaming
				// when only casing is changed.
				// To be sure that our information is correct
				// we trigger a rescan here
				this.doScan(false);
			}

			this.forEachWatcher(filePath, w => {
				if (!initial || w.checkStartTime(safeTime, initial)) {
					w.emit("change", mtime, type);
				}
			});
		} else if (!initial) {
			this.forEachWatcher(filePath, w => w.emit("change", mtime, type));
		}
		this.forEachWatcher(this.path, w => {
			if (!initial || w.checkStartTime(safeTime, initial)) {
				w.emit("change", filePath, safeTime, type, initial);
			}
		});
	}

	setDirectory(directoryPath, birthtime, initial, type) {
		if (this.ignored(directoryPath)) return;
		if (directoryPath === this.path) {
			if (!initial) {
				this.forEachWatcher(this.path, w =>
					w.emit("change", directoryPath, birthtime, type, initial)
				);
			}
		} else {
			const old = this.directories.get(directoryPath);
			if (!old) {
				const now = Date.now();

				if (this.nestedWatching) {
					this.createNestedWatcher(directoryPath);
				} else {
					this.directories.set(directoryPath, true);
				}

				let safeTime;
				if (initial) {
					safeTime = Math.min(now, birthtime) + FS_ACCURACY;
				} else {
					safeTime = now;
				}

				this.forEachWatcher(directoryPath, w => {
					if (!initial || w.checkStartTime(safeTime, false)) {
						w.emit("change", birthtime, type);
					}
				});
				this.forEachWatcher(this.path, w => {
					if (!initial || w.checkStartTime(safeTime, initial)) {
						w.emit("change", directoryPath, safeTime, type, initial);
					}
				});
			}
		}
	}

	createNestedWatcher(directoryPath) {
		const watcher = this.watcherManager.watchDirectory(directoryPath, 1);
		watcher.on("change", (filePath, mtime, type, initial) => {
			this.forEachWatcher(this.path, w => {
				if (!initial || w.checkStartTime(mtime, initial)) {
					w.emit("change", filePath, mtime, type, initial);
				}
			});
		});
		this.directories.set(directoryPath, watcher);
	}

	setNestedWatching(flag) {
		if (this.nestedWatching !== !!flag) {
			this.nestedWatching = !!flag;
			if (this.nestedWatching) {
				for (const directory of this.directories.keys()) {
					this.createNestedWatcher(directory);
				}
			} else {
				for (const [directory, watcher] of this.directories) {
					watcher.close();
					this.directories.set(directory, true);
				}
			}
		}
	}

	watch(filePath, startTime) {
		const key = withoutCase(filePath);
		let watchers = this.watchers.get(key);
		if (watchers === undefined) {
			watchers = new Set();
			this.watchers.set(key, watchers);
		}
		this.refs++;
		const watcher = new Watcher(this, filePath, startTime);
		watcher.on("closed", () => {
			if (--this.refs <= 0) {
				this.close();
				return;
			}
			watchers.delete(watcher);
			if (watchers.size === 0) {
				this.watchers.delete(key);
				if (this.path === filePath) this.setNestedWatching(false);
			}
		});
		watchers.add(watcher);
		let safeTime;
		if (filePath === this.path) {
			this.setNestedWatching(true);
			safeTime = this.lastWatchEvent;
			for (const entry of this.files.values()) {
				fixupEntryAccuracy(entry);
				safeTime = Math.max(safeTime, entry.safeTime);
			}
		} else {
			const entry = this.files.get(filePath);
			if (entry) {
				fixupEntryAccuracy(entry);
				safeTime = entry.safeTime;
			} else {
				safeTime = 0;
			}
		}
		if (safeTime) {
			if (safeTime >= startTime) {
				process.nextTick(() => {
					if (this.closed) return;
					if (filePath === this.path) {
						watcher.emit(
							"change",
							filePath,
							safeTime,
							"watch (outdated on attach)",
							true
						);
					} else {
						watcher.emit(
							"change",
							safeTime,
							"watch (outdated on attach)",
							true
						);
					}
				});
			}
		} else if (this.initialScan) {
			if (this.initialScanRemoved.has(filePath)) {
				process.nextTick(() => {
					if (this.closed) return;
					watcher.emit("remove");
				});
			}
		} else if (
			filePath !== this.path &&
			!this.directories.has(filePath) &&
			watcher.checkStartTime(this.initialScanFinished, false)
		) {
			process.nextTick(() => {
				if (this.closed) return;
				watcher.emit("initial-missing", "watch (missing on attach)");
			});
		}
		return watcher;
	}

	onWatchEvent(eventType, filename) {
		if (this.closed) return;
		if (!filename) {
			// In some cases no filename is provided
			// This seem to happen on windows
			// So some event happened but we don't know which file is affected
			// We have to do a full scan of the directory
			this.doScan(false);
			return;
		}

		const filePath = path.join(this.path, filename);
		if (this.ignored(filePath)) return;

		if (this._activeEvents.get(filename) === undefined) {
			this._activeEvents.set(filename, false);
			const checkStats = () => {
				if (this.closed) return;
				this._activeEvents.set(filename, false);
				fs.lstat(filePath, (err, stats) => {
					if (this.closed) return;
					if (this._activeEvents.get(filename) === true) {
						process.nextTick(checkStats);
						return;
					}
					this._activeEvents.delete(filename);
					// ENOENT happens when the file/directory doesn't exist
					// EPERM happens when the containing directory doesn't exist
					if (err) {
						if (
							err.code !== "ENOENT" &&
							err.code !== "EPERM" &&
							err.code !== "EBUSY"
						) {
							this.onStatsError(err);
						} else {
							if (filename === path.basename(this.path)) {
								// This may indicate that the directory itself was removed
								if (!fs.existsSync(this.path)) {
									this.onDirectoryRemoved("stat failed");
								}
							}
						}
					}
					this.lastWatchEvent = Date.now();
					if (!stats) {
						this.setMissing(filePath, false, eventType);
					} else if (stats.isDirectory()) {
						this.setDirectory(
							filePath,
							+stats.birthtime || 1,
							false,
							eventType
						);
					} else if (stats.isFile() || stats.isSymbolicLink()) {
						if (stats.mtime) {
							ensureFsAccuracy(stats.mtime);
						}
						this.setFileTime(
							filePath,
							+stats.mtime || +stats.ctime || 1,
							false,
							false,
							eventType
						);
					}
				});
			};
			process.nextTick(checkStats);
		} else {
			this._activeEvents.set(filename, true);
		}
	}

	onWatcherError(err) {
		if (this.closed) return;
		if (err) {
			if (err.code !== "EPERM" && err.code !== "ENOENT") {
				console.error("Watchpack Error (watcher): " + err);
			}
			this.onDirectoryRemoved("watch error");
		}
	}

	onStatsError(err) {
		if (err) {
			console.error("Watchpack Error (stats): " + err);
		}
	}

	onScanError(err) {
		if (err) {
			console.error("Watchpack Error (initial scan): " + err);
		}
		this.onScanFinished();
	}

	onScanFinished() {
		if (this.polledWatching) {
			this.timeout = setTimeout(() => {
				if (this.closed) return;
				this.doScan(false);
			}, this.polledWatching);
		}
	}

	onDirectoryRemoved(reason) {
		if (this.watcher) {
			this.watcher.close();
			this.watcher = null;
		}
		this.watchInParentDirectory();
		const type = `directory-removed (${reason})`;
		for (const directory of this.directories.keys()) {
			this.setMissing(directory, null, type);
		}
		for (const file of this.files.keys()) {
			this.setMissing(file, null, type);
		}
	}

	watchInParentDirectory() {
		if (!this.parentWatcher) {
			const parentDir = path.dirname(this.path);
			// avoid watching in the root directory
			// removing directories in the root directory is not supported
			if (path.dirname(parentDir) === parentDir) return;

			this.parentWatcher = this.watcherManager.watchFile(this.path, 1);
			this.parentWatcher.on("change", (mtime, type) => {
				if (this.closed) return;

				// On non-osx platforms we don't need this watcher to detect
				// directory removal, as an EPERM error indicates that
				if ((!IS_OSX || this.polledWatching) && this.parentWatcher) {
					this.parentWatcher.close();
					this.parentWatcher = null;
				}
				// Try to create the watcher when parent directory is found
				if (!this.watcher) {
					this.createWatcher();
					this.doScan(false);

					// directory was created so we emit an event
					this.forEachWatcher(this.path, w =>
						w.emit("change", this.path, mtime, type, false)
					);
				}
			});
			this.parentWatcher.on("remove", () => {
				this.onDirectoryRemoved("parent directory removed");
			});
		}
	}

	doScan(initial) {
		if (this.scanning) {
			if (this.scanAgain) {
				if (!initial) this.scanAgainInitial = false;
			} else {
				this.scanAgain = true;
				this.scanAgainInitial = initial;
			}
			return;
		}
		this.scanning = true;
		if (this.timeout) {
			clearTimeout(this.timeout);
			this.timeout = undefined;
		}
		process.nextTick(() => {
			if (this.closed) return;
			fs.readdir(this.path, (err, items) => {
				if (this.closed) return;
				if (err) {
					if (err.code === "ENOENT" || err.code === "EPERM") {
						this.onDirectoryRemoved("scan readdir failed");
					} else {
						this.onScanError(err);
					}
					this.initialScan = false;
					this.initialScanFinished = Date.now();
					if (initial) {
						for (const watchers of this.watchers.values()) {
							for (const watcher of watchers) {
								if (watcher.checkStartTime(this.initialScanFinished, false)) {
									watcher.emit(
										"initial-missing",
										"scan (parent directory missing in initial scan)"
									);
								}
							}
						}
					}
					if (this.scanAgain) {
						this.scanAgain = false;
						this.doScan(this.scanAgainInitial);
					} else {
						this.scanning = false;
					}
					return;
				}
				const itemPaths = new Set(
					items.map(item => path.join(this.path, item.normalize("NFC")))
				);
				for (const file of this.files.keys()) {
					if (!itemPaths.has(file)) {
						this.setMissing(file, initial, "scan (missing)");
					}
				}
				for (const directory of this.directories.keys()) {
					if (!itemPaths.has(directory)) {
						this.setMissing(directory, initial, "scan (missing)");
					}
				}
				if (this.scanAgain) {
					// Early repeat of scan
					this.scanAgain = false;
					this.doScan(initial);
					return;
				}
				const itemFinished = needCalls(itemPaths.size + 1, () => {
					if (this.closed) return;
					this.initialScan = false;
					this.initialScanRemoved = null;
					this.initialScanFinished = Date.now();
					if (initial) {
						const missingWatchers = new Map(this.watchers);
						missingWatchers.delete(withoutCase(this.path));
						for (const item of itemPaths) {
							missingWatchers.delete(withoutCase(item));
						}
						for (const watchers of missingWatchers.values()) {
							for (const watcher of watchers) {
								if (watcher.checkStartTime(this.initialScanFinished, false)) {
									watcher.emit(
										"initial-missing",
										"scan (missing in initial scan)"
									);
								}
							}
						}
					}
					if (this.scanAgain) {
						this.scanAgain = false;
						this.doScan(this.scanAgainInitial);
					} else {
						this.scanning = false;
						this.onScanFinished();
					}
				});
				for (const itemPath of itemPaths) {
					fs.lstat(itemPath, (err2, stats) => {
						if (this.closed) return;
						if (err2) {
							if (
								err2.code === "ENOENT" ||
								err2.code === "EPERM" ||
								err2.code === "EACCES" ||
								err2.code === "EBUSY"
							) {
								this.setMissing(itemPath, initial, "scan (" + err2.code + ")");
							} else {
								this.onScanError(err2);
							}
							itemFinished();
							return;
						}
						if (stats.isFile() || stats.isSymbolicLink()) {
							if (stats.mtime) {
								ensureFsAccuracy(stats.mtime);
							}
							this.setFileTime(
								itemPath,
								+stats.mtime || +stats.ctime || 1,
								initial,
								true,
								"scan (file)"
							);
						} else if (stats.isDirectory()) {
							if (!initial || !this.directories.has(itemPath))
								this.setDirectory(
									itemPath,
									+stats.birthtime || 1,
									initial,
									"scan (dir)"
								);
						}
						itemFinished();
					});
				}
				itemFinished();
			});
		});
	}

	getTimes() {
		const obj = Object.create(null);
		let safeTime = this.lastWatchEvent;
		for (const [file, entry] of this.files) {
			fixupEntryAccuracy(entry);
			safeTime = Math.max(safeTime, entry.safeTime);
			obj[file] = Math.max(entry.safeTime, entry.timestamp);
		}
		if (this.nestedWatching) {
			for (const w of this.directories.values()) {
				const times = w.directoryWatcher.getTimes();
				for (const file of Object.keys(times)) {
					const time = times[file];
					safeTime = Math.max(safeTime, time);
					obj[file] = time;
				}
			}
			obj[this.path] = safeTime;
		}
		if (!this.initialScan) {
			for (const watchers of this.watchers.values()) {
				for (const watcher of watchers) {
					const path = watcher.path;
					if (!Object.prototype.hasOwnProperty.call(obj, path)) {
						obj[path] = null;
					}
				}
			}
		}
		return obj;
	}

	collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
		let safeTime = this.lastWatchEvent;
		for (const [file, entry] of this.files) {
			fixupEntryAccuracy(entry);
			safeTime = Math.max(safeTime, entry.safeTime);
			fileTimestamps.set(file, entry);
		}
		if (this.nestedWatching) {
			for (const w of this.directories.values()) {
				safeTime = Math.max(
					safeTime,
					w.directoryWatcher.collectTimeInfoEntries(
						fileTimestamps,
						directoryTimestamps
					)
				);
			}
			fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
			directoryTimestamps.set(this.path, {
				safeTime
			});
		} else {
			for (const dir of this.directories.keys()) {
				// No additional info about this directory
				// but maybe another DirectoryWatcher has info
				fileTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
				if (!directoryTimestamps.has(dir))
					directoryTimestamps.set(dir, EXISTANCE_ONLY_TIME_ENTRY);
			}
			fileTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
			directoryTimestamps.set(this.path, EXISTANCE_ONLY_TIME_ENTRY);
		}
		if (!this.initialScan) {
			for (const watchers of this.watchers.values()) {
				for (const watcher of watchers) {
					const path = watcher.path;
					if (!fileTimestamps.has(path)) {
						fileTimestamps.set(path, null);
					}
				}
			}
		}
		return safeTime;
	}

	close() {
		this.closed = true;
		this.initialScan = false;
		if (this.watcher) {
			this.watcher.close();
			this.watcher = null;
		}
		if (this.nestedWatching) {
			for (const w of this.directories.values()) {
				w.close();
			}
			this.directories.clear();
		}
		if (this.parentWatcher) {
			this.parentWatcher.close();
			this.parentWatcher = null;
		}
		this.emit("closed");
	}
}

module.exports = DirectoryWatcher;
module.exports.EXISTANCE_ONLY_TIME_ENTRY = EXISTANCE_ONLY_TIME_ENTRY;

function fixupEntryAccuracy(entry) {
	if (entry.accuracy > FS_ACCURACY) {
		entry.safeTime = entry.safeTime - entry.accuracy + FS_ACCURACY;
		entry.accuracy = FS_ACCURACY;
	}
}

function ensureFsAccuracy(mtime) {
	if (!mtime) return;
	if (FS_ACCURACY > 1 && mtime % 1 !== 0) FS_ACCURACY = 1;
	else if (FS_ACCURACY > 10 && mtime % 10 !== 0) FS_ACCURACY = 10;
	else if (FS_ACCURACY > 100 && mtime % 100 !== 0) FS_ACCURACY = 100;
	else if (FS_ACCURACY > 1000 && mtime % 1000 !== 0) FS_ACCURACY = 1000;
}


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const fs = require("fs");
const path = require("path");

// macOS, Linux, and Windows all rely on these errors
const EXPECTED_ERRORS = new Set(["EINVAL", "ENOENT"]);

// On Windows there is also this error in some cases
if (process.platform === "win32") EXPECTED_ERRORS.add("UNKNOWN");

class LinkResolver {
	constructor() {
		this.cache = new Map();
	}

	/**
	 * @param {string} file path to file or directory
	 * @returns {string[]} array of file and all symlinks contributed in the resolving process (first item is the resolved file)
	 */
	resolve(file) {
		const cacheEntry = this.cache.get(file);
		if (cacheEntry !== undefined) {
			return cacheEntry;
		}
		const parent = path.dirname(file);
		if (parent === file) {
			// At root of filesystem there can't be a link
			const result = Object.freeze([file]);
			this.cache.set(file, result);
			return result;
		}
		// resolve the parent directory to find links there and get the real path
		const parentResolved = this.resolve(parent);
		let realFile = file;

		// is the parent directory really somewhere else?
		if (parentResolved[0] !== parent) {
			// get the real location of file
			const basename = path.basename(file);
			realFile = path.resolve(parentResolved[0], basename);
		}
		// try to read the link content
		try {
			const linkContent = fs.readlinkSync(realFile);

			// resolve the link content relative to the parent directory
			const resolvedLink = path.resolve(parentResolved[0], linkContent);

			// recursive resolve the link content for more links in the structure
			const linkResolved = this.resolve(resolvedLink);

			// merge parent and link resolve results
			let result;
			if (linkResolved.length > 1 && parentResolved.length > 1) {
				// when both contain links we need to duplicate them with a Set
				const resultSet = new Set(linkResolved);
				// add the link
				resultSet.add(realFile);
				// add all symlinks of the parent
				for (let i = 1; i < parentResolved.length; i++) {
					resultSet.add(parentResolved[i]);
				}
				result = Object.freeze(Array.from(resultSet));
			} else if (parentResolved.length > 1) {
				// we have links in the parent but not for the link content location
				result = parentResolved.slice();
				result[0] = linkResolved[0];
				// add the link
				result.push(realFile);
				Object.freeze(result);
			} else if (linkResolved.length > 1) {
				// we can return the link content location result
				result = linkResolved.slice();
				// add the link
				result.push(realFile);
				Object.freeze(result);
			} else {
				// neither link content location nor parent have links
				// this link is the only link here
				result = Object.freeze([
					// the resolve real location
					linkResolved[0],
					// add the link
					realFile
				]);
			}
			this.cache.set(file, result);
			return result;
		} catch (e) {
			if (!EXPECTED_ERRORS.has(e.code)) {
				throw e;
			}
			// no link
			const result = parentResolved.slice();
			result[0] = realFile;
			Object.freeze(result);
			this.cache.set(file, result);
			return result;
		}
	}
}
module.exports = LinkResolver;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const path = require("path");
const DirectoryWatcher = require("./DirectoryWatcher");

class WatcherManager {
	constructor(options) {
		this.options = options;
		this.directoryWatchers = new Map();
	}

	getDirectoryWatcher(directory) {
		const watcher = this.directoryWatchers.get(directory);
		if (watcher === undefined) {
			const newWatcher = new DirectoryWatcher(this, directory, this.options);
			this.directoryWatchers.set(directory, newWatcher);
			newWatcher.on("closed", () => {
				this.directoryWatchers.delete(directory);
			});
			return newWatcher;
		}
		return watcher;
	}

	watchFile(p, startTime) {
		const directory = path.dirname(p);
		if (directory === p) return null;
		return this.getDirectoryWatcher(directory).watch(p, startTime);
	}

	watchDirectory(directory, startTime) {
		return this.getDirectoryWatcher(directory).watch(directory, startTime);
	}
}

const watcherManagers = new WeakMap();
/**
 * @param {object} options options
 * @returns {WatcherManager} the watcher manager
 */
module.exports = options => {
	const watcherManager = watcherManagers.get(options);
	if (watcherManager !== undefined) return watcherManager;
	const newWatcherManager = new WatcherManager(options);
	watcherManagers.set(options, newWatcherManager);
	return newWatcherManager;
};
module.exports.WatcherManager = WatcherManager;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const path = require("path");

/**
 * @template T
 * @typedef {Object} TreeNode
 * @property {string} filePath
 * @property {TreeNode} parent
 * @property {TreeNode[]} children
 * @property {number} entries
 * @property {boolean} active
 * @property {T[] | T | undefined} value
 */

/**
 * @template T
 * @param {Map<string, T[] | T} plan
 * @param {number} limit
 * @returns {Map<string, Map<T, string>>} the new plan
 */
module.exports = (plan, limit) => {
	const treeMap = new Map();
	// Convert to tree
	for (const [filePath, value] of plan) {
		treeMap.set(filePath, {
			filePath,
			parent: undefined,
			children: undefined,
			entries: 1,
			active: true,
			value
		});
	}
	let currentCount = treeMap.size;
	// Create parents and calculate sum of entries
	for (const node of treeMap.values()) {
		const parentPath = path.dirname(node.filePath);
		if (parentPath !== node.filePath) {
			let parent = treeMap.get(parentPath);
			if (parent === undefined) {
				parent = {
					filePath: parentPath,
					parent: undefined,
					children: [node],
					entries: node.entries,
					active: false,
					value: undefined
				};
				treeMap.set(parentPath, parent);
				node.parent = parent;
			} else {
				node.parent = parent;
				if (parent.children === undefined) {
					parent.children = [node];
				} else {
					parent.children.push(node);
				}
				do {
					parent.entries += node.entries;
					parent = parent.parent;
				} while (parent);
			}
		}
	}
	// Reduce until limit reached
	while (currentCount > limit) {
		// Select node that helps reaching the limit most effectively without overmerging
		const overLimit = currentCount - limit;
		let bestNode = undefined;
		let bestCost = Infinity;
		for (const node of treeMap.values()) {
			if (node.entries <= 1 || !node.children || !node.parent) continue;
			if (node.children.length === 0) continue;
			if (node.children.length === 1 && !node.value) continue;
			// Try to select the node with has just a bit more entries than we need to reduce
			// When just a bit more is over 30% over the limit,
			// also consider just a bit less entries then we need to reduce
			const cost =
				node.entries - 1 >= overLimit
					? node.entries - 1 - overLimit
					: overLimit - node.entries + 1 + limit * 0.3;
			if (cost < bestCost) {
				bestNode = node;
				bestCost = cost;
			}
		}
		if (!bestNode) break;
		// Merge all children
		const reduction = bestNode.entries - 1;
		bestNode.active = true;
		bestNode.entries = 1;
		currentCount -= reduction;
		let parent = bestNode.parent;
		while (parent) {
			parent.entries -= reduction;
			parent = parent.parent;
		}
		const queue = new Set(bestNode.children);
		for (const node of queue) {
			node.active = false;
			node.entries = 0;
			if (node.children) {
				for (const child of node.children) queue.add(child);
			}
		}
	}
	// Write down new plan
	const newPlan = new Map();
	for (const rootNode of treeMap.values()) {
		if (!rootNode.active) continue;
		const map = new Map();
		const queue = new Set([rootNode]);
		for (const node of queue) {
			if (node.active && node !== rootNode) continue;
			if (node.value) {
				if (Array.isArray(node.value)) {
					for (const item of node.value) {
						map.set(item, node.filePath);
					}
				} else {
					map.set(node.value, node.filePath);
				}
			}
			if (node.children) {
				for (const child of node.children) {
					queue.add(child);
				}
			}
		}
		newPlan.set(rootNode.filePath, map);
	}
	return newPlan;
};


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const fs = require("fs");
const path = require("path");
const { EventEmitter } = require("events");
const reducePlan = require("./reducePlan");

const IS_OSX = require("os").platform() === "darwin";
const IS_WIN = require("os").platform() === "win32";
const SUPPORTS_RECURSIVE_WATCHING = IS_OSX || IS_WIN;

const watcherLimit =
	+process.env.WATCHPACK_WATCHER_LIMIT || (IS_OSX ? 2000 : 10000);

const recursiveWatcherLogging = !!process.env
	.WATCHPACK_RECURSIVE_WATCHER_LOGGING;

let isBatch = false;
let watcherCount = 0;

/** @type {Map<Watcher, string>} */
const pendingWatchers = new Map();

/** @type {Map<string, RecursiveWatcher>} */
const recursiveWatchers = new Map();

/** @type {Map<string, DirectWatcher>} */
const directWatchers = new Map();

/** @type {Map<Watcher, RecursiveWatcher | DirectWatcher>} */
const underlyingWatcher = new Map();

class DirectWatcher {
	constructor(filePath) {
		this.filePath = filePath;
		this.watchers = new Set();
		this.watcher = undefined;
		try {
			const watcher = fs.watch(filePath);
			this.watcher = watcher;
			watcher.on("change", (type, filename) => {
				for (const w of this.watchers) {
					w.emit("change", type, filename);
				}
			});
			watcher.on("error", error => {
				for (const w of this.watchers) {
					w.emit("error", error);
				}
			});
		} catch (err) {
			process.nextTick(() => {
				for (const w of this.watchers) {
					w.emit("error", err);
				}
			});
		}
		watcherCount++;
	}

	add(watcher) {
		underlyingWatcher.set(watcher, this);
		this.watchers.add(watcher);
	}

	remove(watcher) {
		this.watchers.delete(watcher);
		if (this.watchers.size === 0) {
			directWatchers.delete(this.filePath);
			watcherCount--;
			if (this.watcher) this.watcher.close();
		}
	}

	getWatchers() {
		return this.watchers;
	}
}

class RecursiveWatcher {
	constructor(rootPath) {
		this.rootPath = rootPath;
		/** @type {Map<Watcher, string>} */
		this.mapWatcherToPath = new Map();
		/** @type {Map<string, Set<Watcher>>} */
		this.mapPathToWatchers = new Map();
		this.watcher = undefined;
		try {
			const watcher = fs.watch(rootPath, {
				recursive: true
			});
			this.watcher = watcher;
			watcher.on("change", (type, filename) => {
				if (!filename) {
					if (recursiveWatcherLogging) {
						process.stderr.write(
							`[watchpack] dispatch ${type} event in recursive watcher (${this.rootPath}) to all watchers\n`
						);
					}
					for (const w of this.mapWatcherToPath.keys()) {
						w.emit("change", type);
					}
				} else {
					const dir = path.dirname(filename);
					const watchers = this.mapPathToWatchers.get(dir);
					if (recursiveWatcherLogging) {
						process.stderr.write(
							`[watchpack] dispatch ${type} event in recursive watcher (${
								this.rootPath
							}) for '${filename}' to ${
								watchers ? watchers.size : 0
							} watchers\n`
						);
					}
					if (watchers === undefined) return;
					for (const w of watchers) {
						w.emit("change", type, path.basename(filename));
					}
				}
			});
			watcher.on("error", error => {
				for (const w of this.mapWatcherToPath.keys()) {
					w.emit("error", error);
				}
			});
		} catch (err) {
			process.nextTick(() => {
				for (const w of this.mapWatcherToPath.keys()) {
					w.emit("error", err);
				}
			});
		}
		watcherCount++;
		if (recursiveWatcherLogging) {
			process.stderr.write(
				`[watchpack] created recursive watcher at ${rootPath}\n`
			);
		}
	}

	add(filePath, watcher) {
		underlyingWatcher.set(watcher, this);
		const subpath = filePath.slice(this.rootPath.length + 1) || ".";
		this.mapWatcherToPath.set(watcher, subpath);
		const set = this.mapPathToWatchers.get(subpath);
		if (set === undefined) {
			const newSet = new Set();
			newSet.add(watcher);
			this.mapPathToWatchers.set(subpath, newSet);
		} else {
			set.add(watcher);
		}
	}

	remove(watcher) {
		const subpath = this.mapWatcherToPath.get(watcher);
		if (!subpath) return;
		this.mapWatcherToPath.delete(watcher);
		const set = this.mapPathToWatchers.get(subpath);
		set.delete(watcher);
		if (set.size === 0) {
			this.mapPathToWatchers.delete(subpath);
		}
		if (this.mapWatcherToPath.size === 0) {
			recursiveWatchers.delete(this.rootPath);
			watcherCount--;
			if (this.watcher) this.watcher.close();
			if (recursiveWatcherLogging) {
				process.stderr.write(
					`[watchpack] closed recursive watcher at ${this.rootPath}\n`
				);
			}
		}
	}

	getWatchers() {
		return this.mapWatcherToPath;
	}
}

class Watcher extends EventEmitter {
	close() {
		if (pendingWatchers.has(this)) {
			pendingWatchers.delete(this);
			return;
		}
		const watcher = underlyingWatcher.get(this);
		watcher.remove(this);
		underlyingWatcher.delete(this);
	}
}

const createDirectWatcher = filePath => {
	const existing = directWatchers.get(filePath);
	if (existing !== undefined) return existing;
	const w = new DirectWatcher(filePath);
	directWatchers.set(filePath, w);
	return w;
};

const createRecursiveWatcher = rootPath => {
	const existing = recursiveWatchers.get(rootPath);
	if (existing !== undefined) return existing;
	const w = new RecursiveWatcher(rootPath);
	recursiveWatchers.set(rootPath, w);
	return w;
};

const execute = () => {
	/** @type {Map<string, Watcher[] | Watcher>} */
	const map = new Map();
	const addWatcher = (watcher, filePath) => {
		const entry = map.get(filePath);
		if (entry === undefined) {
			map.set(filePath, watcher);
		} else if (Array.isArray(entry)) {
			entry.push(watcher);
		} else {
			map.set(filePath, [entry, watcher]);
		}
	};
	for (const [watcher, filePath] of pendingWatchers) {
		addWatcher(watcher, filePath);
	}
	pendingWatchers.clear();

	// Fast case when we are not reaching the limit
	if (!SUPPORTS_RECURSIVE_WATCHING || watcherLimit - watcherCount >= map.size) {
		// Create watchers for all entries in the map
		for (const [filePath, entry] of map) {
			const w = createDirectWatcher(filePath);
			if (Array.isArray(entry)) {
				for (const item of entry) w.add(item);
			} else {
				w.add(entry);
			}
		}
		return;
	}

	// Reconsider existing watchers to improving watch plan
	for (const watcher of recursiveWatchers.values()) {
		for (const [w, subpath] of watcher.getWatchers()) {
			addWatcher(w, path.join(watcher.rootPath, subpath));
		}
	}
	for (const watcher of directWatchers.values()) {
		for (const w of watcher.getWatchers()) {
			addWatcher(w, watcher.filePath);
		}
	}

	// Merge map entries to keep watcher limit
	// Create a 10% buffer to be able to enter fast case more often
	const plan = reducePlan(map, watcherLimit * 0.9);

	// Update watchers for all entries in the map
	for (const [filePath, entry] of plan) {
		if (entry.size === 1) {
			for (const [watcher, filePath] of entry) {
				const w = createDirectWatcher(filePath);
				const old = underlyingWatcher.get(watcher);
				if (old === w) continue;
				w.add(watcher);
				if (old !== undefined) old.remove(watcher);
			}
		} else {
			const filePaths = new Set(entry.values());
			if (filePaths.size > 1) {
				const w = createRecursiveWatcher(filePath);
				for (const [watcher, watcherPath] of entry) {
					const old = underlyingWatcher.get(watcher);
					if (old === w) continue;
					w.add(watcherPath, watcher);
					if (old !== undefined) old.remove(watcher);
				}
			} else {
				for (const filePath of filePaths) {
					const w = createDirectWatcher(filePath);
					for (const watcher of entry.keys()) {
						const old = underlyingWatcher.get(watcher);
						if (old === w) continue;
						w.add(watcher);
						if (old !== undefined) old.remove(watcher);
					}
				}
			}
		}
	}
};

exports.watch = filePath => {
	const watcher = new Watcher();
	// Find an existing watcher
	const directWatcher = directWatchers.get(filePath);
	if (directWatcher !== undefined) {
		directWatcher.add(watcher);
		return watcher;
	}
	let current = filePath;
	for (;;) {
		const recursiveWatcher = recursiveWatchers.get(current);
		if (recursiveWatcher !== undefined) {
			recursiveWatcher.add(filePath, watcher);
			return watcher;
		}
		const parent = path.dirname(current);
		if (parent === current) break;
		current = parent;
	}
	// Queue up watcher for creation
	pendingWatchers.set(watcher, filePath);
	if (!isBatch) execute();
	return watcher;
};

exports.batch = fn => {
	isBatch = true;
	try {
		fn();
	} finally {
		isBatch = false;
		execute();
	}
};

exports.getNumberOfWatchers = () => {
	return watcherCount;
};


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
"use strict";

const getWatcherManager = require("./getWatcherManager");
const LinkResolver = require("./LinkResolver");
const EventEmitter = require("events").EventEmitter;
const globToRegExp = require("glob-to-regexp");
const watchEventSource = require("./watchEventSource");

const EMPTY_ARRAY = [];
const EMPTY_OPTIONS = {};

function addWatchersToSet(watchers, set) {
	for (const ww of watchers) {
		const w = ww.watcher;
		if (!set.has(w.directoryWatcher)) {
			set.add(w.directoryWatcher);
		}
	}
}

const stringToRegexp = ignored => {
	const source = globToRegExp(ignored, { globstar: true, extended: true })
		.source;
	const matchingStart = source.slice(0, source.length - 1) + "(?:$|\\/)";
	return matchingStart;
};

const ignoredToFunction = ignored => {
	if (Array.isArray(ignored)) {
		const regexp = new RegExp(ignored.map(i => stringToRegexp(i)).join("|"));
		return x => regexp.test(x.replace(/\\/g, "/"));
	} else if (typeof ignored === "string") {
		const regexp = new RegExp(stringToRegexp(ignored));
		return x => regexp.test(x.replace(/\\/g, "/"));
	} else if (ignored instanceof RegExp) {
		return x => ignored.test(x.replace(/\\/g, "/"));
	} else if (ignored instanceof Function) {
		return ignored;
	} else if (ignored) {
		throw new Error(`Invalid option for 'ignored': ${ignored}`);
	} else {
		return () => false;
	}
};

const normalizeOptions = options => {
	return {
		followSymlinks: !!options.followSymlinks,
		ignored: ignoredToFunction(options.ignored),
		poll: options.poll
	};
};

const normalizeCache = new WeakMap();
const cachedNormalizeOptions = options => {
	const cacheEntry = normalizeCache.get(options);
	if (cacheEntry !== undefined) return cacheEntry;
	const normalized = normalizeOptions(options);
	normalizeCache.set(options, normalized);
	return normalized;
};

class WatchpackFileWatcher {
	constructor(watchpack, watcher, files) {
		this.files = Array.isArray(files) ? files : [files];
		this.watcher = watcher;
		watcher.on("initial-missing", type => {
			for (const file of this.files) {
				if (!watchpack._missing.has(file))
					watchpack._onRemove(file, file, type);
			}
		});
		watcher.on("change", (mtime, type) => {
			for (const file of this.files) {
				watchpack._onChange(file, mtime, file, type);
			}
		});
		watcher.on("remove", type => {
			for (const file of this.files) {
				watchpack._onRemove(file, file, type);
			}
		});
	}

	update(files) {
		if (!Array.isArray(files)) {
			if (this.files.length !== 1) {
				this.files = [files];
			} else if (this.files[0] !== files) {
				this.files[0] = files;
			}
		} else {
			this.files = files;
		}
	}

	close() {
		this.watcher.close();
	}
}

class WatchpackDirectoryWatcher {
	constructor(watchpack, watcher, directories) {
		this.directories = Array.isArray(directories) ? directories : [directories];
		this.watcher = watcher;
		watcher.on("initial-missing", type => {
			for (const item of this.directories) {
				watchpack._onRemove(item, item, type);
			}
		});
		watcher.on("change", (file, mtime, type) => {
			for (const item of this.directories) {
				watchpack._onChange(item, mtime, file, type);
			}
		});
		watcher.on("remove", type => {
			for (const item of this.directories) {
				watchpack._onRemove(item, item, type);
			}
		});
	}

	update(directories) {
		if (!Array.isArray(directories)) {
			if (this.directories.length !== 1) {
				this.directories = [directories];
			} else if (this.directories[0] !== directories) {
				this.directories[0] = directories;
			}
		} else {
			this.directories = directories;
		}
	}

	close() {
		this.watcher.close();
	}
}

class Watchpack extends EventEmitter {
	constructor(options) {
		super();
		if (!options) options = EMPTY_OPTIONS;
		this.options = options;
		this.aggregateTimeout =
			typeof options.aggregateTimeout === "number"
				? options.aggregateTimeout
				: 200;
		this.watcherOptions = cachedNormalizeOptions(options);
		this.watcherManager = getWatcherManager(this.watcherOptions);
		this.fileWatchers = new Map();
		this.directoryWatchers = new Map();
		this._missing = new Set();
		this.startTime = undefined;
		this.paused = false;
		this.aggregatedChanges = new Set();
		this.aggregatedRemovals = new Set();
		this.aggregateTimer = undefined;
		this._onTimeout = this._onTimeout.bind(this);
	}

	watch(arg1, arg2, arg3) {
		let files, directories, missing, startTime;
		if (!arg2) {
			({
				files = EMPTY_ARRAY,
				directories = EMPTY_ARRAY,
				missing = EMPTY_ARRAY,
				startTime
			} = arg1);
		} else {
			files = arg1;
			directories = arg2;
			missing = EMPTY_ARRAY;
			startTime = arg3;
		}
		this.paused = false;
		const fileWatchers = this.fileWatchers;
		const directoryWatchers = this.directoryWatchers;
		const ignored = this.watcherOptions.ignored;
		const filter = path => !ignored(path);
		const addToMap = (map, key, item) => {
			const list = map.get(key);
			if (list === undefined) {
				map.set(key, item);
			} else if (Array.isArray(list)) {
				list.push(item);
			} else {
				map.set(key, [list, item]);
			}
		};
		const fileWatchersNeeded = new Map();
		const directoryWatchersNeeded = new Map();
		const missingFiles = new Set();
		if (this.watcherOptions.followSymlinks) {
			const resolver = new LinkResolver();
			for (const file of files) {
				if (filter(file)) {
					for (const innerFile of resolver.resolve(file)) {
						if (file === innerFile || filter(innerFile)) {
							addToMap(fileWatchersNeeded, innerFile, file);
						}
					}
				}
			}
			for (const file of missing) {
				if (filter(file)) {
					for (const innerFile of resolver.resolve(file)) {
						if (file === innerFile || filter(innerFile)) {
							missingFiles.add(file);
							addToMap(fileWatchersNeeded, innerFile, file);
						}
					}
				}
			}
			for (const dir of directories) {
				if (filter(dir)) {
					let first = true;
					for (const innerItem of resolver.resolve(dir)) {
						if (filter(innerItem)) {
							addToMap(
								first ? directoryWatchersNeeded : fileWatchersNeeded,
								innerItem,
								dir
							);
						}
						first = false;
					}
				}
			}
		} else {
			for (const file of files) {
				if (filter(file)) {
					addToMap(fileWatchersNeeded, file, file);
				}
			}
			for (const file of missing) {
				if (filter(file)) {
					missingFiles.add(file);
					addToMap(fileWatchersNeeded, file, file);
				}
			}
			for (const dir of directories) {
				if (filter(dir)) {
					addToMap(directoryWatchersNeeded, dir, dir);
				}
			}
		}
		// Close unneeded old watchers
		// and update existing watchers
		for (const [key, w] of fileWatchers) {
			const needed = fileWatchersNeeded.get(key);
			if (needed === undefined) {
				w.close();
				fileWatchers.delete(key);
			} else {
				w.update(needed);
				fileWatchersNeeded.delete(key);
			}
		}
		for (const [key, w] of directoryWatchers) {
			const needed = directoryWatchersNeeded.get(key);
			if (needed === undefined) {
				w.close();
				directoryWatchers.delete(key);
			} else {
				w.update(needed);
				directoryWatchersNeeded.delete(key);
			}
		}
		// Create new watchers and install handlers on these watchers
		watchEventSource.batch(() => {
			for (const [key, files] of fileWatchersNeeded) {
				const watcher = this.watcherManager.watchFile(key, startTime);
				if (watcher) {
					fileWatchers.set(key, new WatchpackFileWatcher(this, watcher, files));
				}
			}
			for (const [key, directories] of directoryWatchersNeeded) {
				const watcher = this.watcherManager.watchDirectory(key, startTime);
				if (watcher) {
					directoryWatchers.set(
						key,
						new WatchpackDirectoryWatcher(this, watcher, directories)
					);
				}
			}
		});
		this._missing = missingFiles;
		this.startTime = startTime;
	}

	close() {
		this.paused = true;
		if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
		for (const w of this.fileWatchers.values()) w.close();
		for (const w of this.directoryWatchers.values()) w.close();
		this.fileWatchers.clear();
		this.directoryWatchers.clear();
	}

	pause() {
		this.paused = true;
		if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
	}

	getTimes() {
		const directoryWatchers = new Set();
		addWatchersToSet(this.fileWatchers.values(), directoryWatchers);
		addWatchersToSet(this.directoryWatchers.values(), directoryWatchers);
		const obj = Object.create(null);
		for (const w of directoryWatchers) {
			const times = w.getTimes();
			for (const file of Object.keys(times)) obj[file] = times[file];
		}
		return obj;
	}

	getTimeInfoEntries() {
		const map = new Map();
		this.collectTimeInfoEntries(map, map);
		return map;
	}

	collectTimeInfoEntries(fileTimestamps, directoryTimestamps) {
		const allWatchers = new Set();
		addWatchersToSet(this.fileWatchers.values(), allWatchers);
		addWatchersToSet(this.directoryWatchers.values(), allWatchers);
		const safeTime = { value: 0 };
		for (const w of allWatchers) {
			w.collectTimeInfoEntries(fileTimestamps, directoryTimestamps, safeTime);
		}
	}

	getAggregated() {
		if (this.aggregateTimer) {
			clearTimeout(this.aggregateTimer);
			this.aggregateTimer = undefined;
		}
		const changes = this.aggregatedChanges;
		const removals = this.aggregatedRemovals;
		this.aggregatedChanges = new Set();
		this.aggregatedRemovals = new Set();
		return { changes, removals };
	}

	_onChange(item, mtime, file, type) {
		file = file || item;
		if (!this.paused) {
			this.emit("change", file, mtime, type);
			if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
			this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout);
		}
		this.aggregatedRemovals.delete(item);
		this.aggregatedChanges.add(item);
	}

	_onRemove(item, file, type) {
		file = file || item;
		if (!this.paused) {
			this.emit("remove", file, type);
			if (this.aggregateTimer) clearTimeout(this.aggregateTimer);
			this.aggregateTimer = setTimeout(this._onTimeout, this.aggregateTimeout);
		}
		this.aggregatedChanges.delete(item);
		this.aggregatedRemovals.add(item);
	}

	_onTimeout() {
		this.aggregateTimer = undefined;
		const changes = this.aggregatedChanges;
		const removals = this.aggregatedRemovals;
		this.aggregatedChanges = new Set();
		this.aggregatedRemovals = new Set();
		this.emit("aggregated", changes, removals);
	}
}

module.exports = Watchpack;


watchpack

test: test

pretty-files: prettier "lib/**.*" "test/**/*.js" --write

lint: eslint lib

test:only: mocha

pretest: yarn lint

test: mocha

author: Tobias Koppers @sokra