const ejs = require('ejs')
const slash = require('slash')
const debug = require('debug')
const GeneratorAPI = require('./GeneratorAPI')
const sortObject = require('./util/sortObject')
const writeFileTree = require('./util/writeFileTree')
const configTransforms = require('./util/configTransforms')
const injectImportsAndOptions = require('./util/injectImportsAndOptions')
const { toShortPluginId, matchesPluginId } = require('@vue/cli-shared-utils')

const logger = require('@vue/cli-shared-utils/lib/logger')
const logTypes = {
  log: logger.log,
  info: logger.info,
  done: logger.done,
  warn: logger.warn,
  error: logger.error
}

module.exports = class Generator {
  constructor (context, {
    pkg = {},
    plugins = [],
    completeCbs = [],
    files = {},
    invoking = false
  } = {}) {
    this.context = context
    this.plugins = plugins
    this.originalPkg = pkg
    this.pkg = Object.assign({}, pkg)
    this.imports = {}
    this.rootOptions = {}
    this.completeCbs = completeCbs
    this.invoking = invoking

    // for conflict resolution
    this.depSources = {}
    // virtual file tree
    this.files = files
    this.fileMiddlewares = []
    this.postProcessFilesCbs = []
    // exit messages
    this.exitLogs = []

    const cliService = plugins.find(p => p.id === '@vue/cli-service')
    const rootOptions = cliService && cliService.options
    // apply generators from plugins
    plugins.forEach(({ id, apply, options }) => {
      const api = new GeneratorAPI(id, this, options, rootOptions || {})
      apply(api, options, rootOptions)
    })
  }

  async generate ({
    extractConfigFiles = false,
    checkExisting = false
  } = {}) {
    // save the file system before applying plugin for comparison
    const initialFiles = Object.assign({}, this.files)
    // extract configs from package.json into dedicated files.
    this.extractConfigFiles(extractConfigFiles, checkExisting)
    // wait for file resolve
    await this.resolveFiles()
    // set package.json
    this.sortPkg()
    this.files['package.json'] = JSON.stringify(this.pkg, null, 2)
    // write/update file tree to disk
    await writeFileTree(this.context, this.files, initialFiles)
  }

  extractConfigFiles (extractAll, checkExisting) {
    const extract = key => {
      if (
        configTransforms[key] &&
        this.pkg[key] &&
        // do not extract if the field exists in original package.json
        !this.originalPkg[key]
      ) {
        const value = this.pkg[key]
        const transform = configTransforms[key]
        const res = transform(
          value,
          checkExisting,
          this.context
        )
        const { content, filename } = res
        this.files[filename] = content
        delete this.pkg[key]
      }
    }
    if (extractAll) {
      for (const key in this.pkg) {
        extract(key)
      }
    } else {
      if (!process.env.VUE_CLI_TEST) {
        // by default, always extract vue.config.js
        extract('vue')
      }
      // always extract babel.config.js as this is the only way to apply
      // project-wide configuration even to dependencies.
      // TODO: this can be removed when Babel supports root: true in package.json
      extract('babel')
    }
  }

  sortPkg () {
    // ensure package.json keys has readable order
    this.pkg.dependencies = sortObject(this.pkg.dependencies)
    this.pkg.devDependencies = sortObject(this.pkg.devDependencies)
    this.pkg.scripts = sortObject(this.pkg.scripts, [
      'serve',
      'build',
      'test',
      'e2e',
      'lint',
      'deploy'
    ])
    this.pkg = sortObject(this.pkg, [
      'name',
      'version',
      'private',
      'scripts',
      'dependencies',
      'devDependencies',
      'vue',
      'babel',
      'eslintConfig',
      'prettier',
      'postcss',
      'browserslist',
      'jest'
    ])

    debug('vue:cli-pkg')(this.pkg)
  }

  async resolveFiles () {
    const files = this.files
    for (const middleware of this.fileMiddlewares) {
      await middleware(files, ejs.render)
    }
    Object.keys(files).forEach(file => {
      // normalize paths
      const normalized = slash(file)
      if (file !== normalized) {
        files[normalized] = files[file]
        delete files[file]
      }
      // handle imports and root option injections
      files[normalized] = injectImportsAndOptions(
        files[normalized],
        this.imports[normalized],
        this.rootOptions[normalized]
      )
    })
    for (const postProcess of this.postProcessFilesCbs) {
      await postProcess(files)
    }
    debug('vue:cli-files')(this.files)
  }

  hasPlugin (_id) {
    return [
      ...this.plugins.map(p => p.id),
      ...Object.keys(this.pkg.devDependencies || {}),
      ...Object.keys(this.pkg.dependencies || {})
    ].some(id => matchesPluginId(_id, id))
  }

  printExitLogs () {
    if (this.exitLogs.length) {
      this.exitLogs.forEach(({ id, msg, type }) => {
        const shortId = toShortPluginId(id)
        const logFn = logTypes[type]
        if (!logFn) {
          logger.error(`Invalid api.exitLog type '${type}'.`, shortId)
        } else {
          logFn(msg, msg && shortId)
        }
      })
      logger.log()
    }
  }
}


}
if (!api.hasPlugin('typescript')) {
if (api.hasPlugin('babel')) {

// A dev-only middleware that resets service workers for the current host:port
// This is for dealing with cases where a developer loads the dev and prod
// versions of an app on the same host:port combination, causing the prod
// service worker to hijack subsequent visists in dev mode.

// Note this doesn't always immediately fix the problem - if the server used
// to serve the production app has a long cache header for /service-worker.js,
// this noop service worker will not be able to take effect. In such cases,
// the developer will have to manually unregister the service worker in
// Chrome Devtools -> Application -> Service Workers

const fs = require('fs')
const path = require('path')
const resetScript = fs.readFileSync(path.resolve(__dirname, 'noopServiceWorker.js'), 'utf-8')

module.exports = function createNoopServiceWorkerMiddleware () {
  return function noopServiceWorkerMiddleware (req, res, next) {
    if (req.url === '/service-worker.js') {
      res.setHeader('Content-Type', 'text/javascript')
      res.send(resetScript)
    } else {
      next()
    }
  }
}


module.exports = api => {
  api.render('./template')
  api.extendPackage({
    scripts: {
      'test:unit': 'vue-cli-service test:unit'
    },
    devDependencies: {
      '@vue/test-utils': '^1.0.0-beta.16'
    }
  })

  const jestConfig = {
    'moduleFileExtensions': [
      'js',
      'jsx',
      'json',
      // tell Jest to handle *.vue files
      'vue'
    ],
    'transform': {
      // process *.vue files with vue-jest
      '^.+\\.vue$': 'vue-jest',
      '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub'
    },
    // support the same @ -> src alias mapping in source code
    'moduleNameMapper': {
      '^@/(.*)$': '<rootDir>/src/$1'
    },
    // serializer for snapshots
    'snapshotSerializers': [
      'jest-serializer-vue'
    ],
    'testMatch': [
      '<rootDir>/(tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx))'
    ]
  }

  if (!api.hasPlugin('typescript')) {
    if (api.hasPlugin('babel')) {
      jestConfig.transform['^.+\\.jsx?$'] = 'babel-jest'
      api.extendPackage({
        devDependencies: {
          'babel-jest': '^23.0.1',
          // this is for now necessary to force babel-jest and vue-jest to use babel 7
          'babel-core': '7.0.0-bridge.0'
        }
      })
    }
  } else {
    jestConfig.moduleFileExtensions.unshift('ts', 'tsx')
    jestConfig.transform['^.+\\.tsx?$'] = 'ts-jest'
    api.extendPackage({
      devDependencies: {
        'ts-jest': '^22.4.6'
      }
    })
    if (api.hasPlugin('babel')) {
      api.extendPackage({
        devDependencies: {
          // this is for now necessary to force ts-jest and vue-jest to use babel 7
          'babel-core': '7.0.0-bridge.0'
        }
      })
    }
  }

  api.extendPackage({ jest: jestConfig })

  if (api.hasPlugin('eslint')) {
    api.render(files => {
      files['tests/unit/.eslintrc.js'] = api.genJSConfig({
        env: { jest: true },
        rules: {
          'import/no-extraneous-dependencies': 'off'
        }
      })
    })
  }
}


const getModulePath = function (identifier) {
  return identifier.replace(/.*!/, '').replace(/\\/g, '/')
}

export function filterModules (modules) {
  return modules.filter(module => module.name.indexOf('(webpack)') === -1)
}

export function buildSortedModules (modules, sizeField) {
  let list = modules.slice()
  if (list.length) {
    list = list.map(module => {
      const size = module.size[sizeField]
      return {
        id: module.id,
        identifier: module.identifier,
        size
      }
    })
    list = list.sort((a, b) => b.size - a.size)
  }
  return list
}

export function buildDepModules (modules) {
  const deps = new Map()
  for (const module of modules) {
    const path = getModulePath(module.identifier)
    const pathParts = path.split('/node_modules/')
    if (pathParts.length === 2) {
      let name = pathParts[1]
      if (name.charAt(0) === '@') {
        // Scoped package
        name = name.substr(0, name.indexOf('/', name.indexOf('/') + 1))
      } else {
        name = name.substr(0, name.indexOf('/'))
      }
      let dep = deps.get(name)
      if (!dep) {
        dep = {
          name,
          size: 0
        }
        deps.set(name, dep)
      }
      dep.size += module.size
    }
  }
  let list = Array.from(deps.values())
  list = list.sort((a, b) => b.size - a.size)
  if (list.length) {
    const max = list[0].size
    for (const dep of list) {
      dep.ratio = dep.size / max
    }
  }
  return list
}

/*
{
  id: './node_modules',
  size: {
    stats: 1024,
    parsed: 0,
    gzip: 400
  }
  fullPath: '/node_modules',
  parent: undefined,
  children: [
    {
      id: 'vuex',
      identifier: '...',
      size: {
        stats: 42,
        parsed: 0,
        gzip: 12
      },
      // Total size of previous children in list
      previousSize: {
        stats: 0,
        parsed: 0,
        gzip: 0
      },
      fullPath: '/node_modules/vuex',
      children: [
        ...
      ],
      parent: ...
    },
    ...
  ]
}
*/

export function buildModulesTrees (modules) {
  const trees = {}

  for (const module of modules) {
    const path = getModulePath(module.identifier)
    if (path.indexOf('multi ') === 0) continue
    const parts = path.split('/')
    for (const treeId of module.chunks) {
      let subtree = trees[treeId]
      if (!subtree) {
        subtree = trees[treeId] = {
          id: treeId,
          size: {
            stats: 0,
            parsed: 0,
            gzip: 0
          },
          children: {}
        }
      }
      let fullPath = []
      for (let i = 0; i < parts.length; i++) {
        const part = parts[i]
        let child = subtree.children[part]
        if (!child) {
          fullPath.push(part)
          child = subtree.children[part] = {
            id: part,
            size: {
              stats: 0,
              parsed: 0,
              gzip: 0
            },
            fullPath: fullPath.join('/'),
            children: {},
            parent: subtree
          }
        }
        child.size.stats += module.size.stats
        child.size.parsed += module.size.parsed || 0
        child.size.gzip += module.size.gzip || 0
        // Leaf
        if (i === parts.length - 1) {
          child.identifier = module.identifier
        }
        subtree = child
      }
    }
  }

  for (const n in trees) {
    let tree = trees[n]
    let keys
    while ((keys = Object.keys(tree.children)).length !== 0 && keys.length === 1) {
      tree = tree.children[keys[0]]
    }
    walkTreeToSortChildren(tree)
    trees[n] = tree
  }

  return trees
}

function walkTreeToSortChildren (tree) {
  let size = {
    stats: 0,
    parsed: 0,
    gzip: 0
  }
  tree.children = Object.keys(tree.children).map(
    key => tree.children[key]
  ).sort((a, b) => b.size.stats - a.size.stats)
  for (const child of tree.children) {
    child.previousSize = {
      stats: size.stats,
      parsed: size.parsed,
      gzip: size.gzip
    }
    size.stats += child.size.stats
    size.parsed += child.size.parsed
    size.gzip += child.size.gzip
    walkTreeToSortChildren(child)
  }
}


module.exports = api => {
  const { setSharedData, removeSharedData } = api.namespace('webpack-dashboard-')

  function resetSharedData (key) {
    setSharedData(`${key}-status`, null)
    setSharedData(`${key}-progress`, 0)
    setSharedData(`${key}-operations`, null)
    setSharedData(`${key}-stats`, null)
    setSharedData(`${key}-sizes`, null)
    setSharedData(`${key}-problems`, null)
  }

  function onWebpackMessage ({ data: message }) {
    if (message.webpackDashboardData) {
      const type = message.webpackDashboardData.type
      for (const data of message.webpackDashboardData.value) {
        setSharedData(`${type}-${data.type}`, data.value)
      }
    }
  }

  // Init data
  api.onProjectOpen(() => {
    for (const key of ['serve', 'build']) {
      resetSharedData(key)
    }
  })

  // Tasks
  const views = {
    views: [
      {
        id: 'vue-webpack-dashboard',
        label: 'vue-webpack.dashboard.title',
        icon: 'dashboard',
        component: 'vue-webpack-dashboard'
      },
      {
        id: 'vue-webpack-analyzer',
        label: 'vue-webpack.analyzer.title',
        icon: 'donut_large',
        component: 'vue-webpack-analyzer'
      }
    ],
    defaultView: 'vue-webpack-dashboard'
  }
  api.describeTask({
    match: /vue-cli-service serve/,
    description: 'vue-webpack.tasks.serve.description',
    link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#serve',
    icon: '/_plugin/%40vue%2Fcli-service/webpack-logo.png',
    prompts: [
      {
        name: 'open',
        type: 'confirm',
        default: false,
        description: 'vue-webpack.tasks.serve.open'
      },
      {
        name: 'mode',
        type: 'list',
        default: 'development',
        choices: [
          {
            name: 'development',
            value: 'development'
          },
          {
            name: 'production',
            value: 'production'
          },
          {
            name: 'test',
            value: 'test'
          }
        ],
        description: 'vue-webpack.tasks.serve.mode'
      },
      {
        name: 'host',
        type: 'input',
        default: '0.0.0.0',
        description: 'vue-webpack.tasks.serve.host'
      },
      {
        name: 'port',
        type: 'input',
        default: 8080,
        description: 'vue-webpack.tasks.serve.port'
      },
      {
        name: 'https',
        type: 'confirm',
        default: false,
        description: 'vue-webpack.tasks.serve.https'
      }
    ],
    onBeforeRun: ({ answers, args }) => {
      // Args
      if (answers.open) args.push('--open')
      if (answers.mode) args.push('--mode', answers.mode)
      if (answers.host) args.push('--host', answers.host)
      if (answers.port) args.push('--port', answers.port)
      if (answers.https) args.push('--https')
      args.push('--dashboard')

      // Data
      resetSharedData('serve')
      removeSharedData('serve-url')
    },
    onRun: () => {
      api.ipcOn(onWebpackMessage)
    },
    onExit: () => {
      api.ipcOff(onWebpackMessage)
      removeSharedData('serve-url')
    },
    ...views
  })
  api.describeTask({
    match: /vue-cli-service build/,
    description: 'vue-webpack.tasks.build.description',
    link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#build',
    icon: '/_plugin/%40vue%2Fcli-service/webpack-logo.png',
    prompts: [
      {
        name: 'mode',
        type: 'list',
        default: 'production',
        choices: [
          {
            name: 'development',
            value: 'development'
          },
          {
            name: 'production',
            value: 'production'
          },
          {
            name: 'test',
            value: 'test'
          }
        ],
        description: 'vue-webpack.tasks.build.mode'
      },
      {
        name: 'dest',
        type: 'input',
        default: 'dist',
        description: 'vue-webpack.tasks.build.dest'
      },
      {
        name: 'target',
        type: 'list',
        default: 'app',
        choices: [
          {
            name: 'vue-webpack.tasks.build.target.app',
            value: 'app'
          },
          {
            name: 'vue-webpack.tasks.build.target.lib',
            value: 'lib'
          },
          {
            name: 'vue-webpack.tasks.build.target.wc',
            value: 'wc'
          },
          {
            name: 'vue-webpack.tasks.build.target.wc-async',
            value: 'wc-async'
          }
        ],
        description: 'vue-webpack.tasks.build.target.description'
      },
      {
        name: 'name',
        type: 'input',
        default: '',
        description: 'vue-webpack.tasks.build.name'
      },
      {
        name: 'watch',
        type: 'confirm',
        default: false,
        description: 'vue-webpack.tasks.build.watch'
      }
    ],
    onBeforeRun: ({ answers, args }) => {
      // Args
      if (answers.mode) args.push('--mode', answers.mode)
      if (answers.dest) args.push('--dest', answers.dest)
      if (answers.target) args.push('--target', answers.target)
      if (answers.name) args.push('--port', answers.name)
      if (answers.watch) args.push('--watch')
      args.push('--dashboard')

      // Data
      resetSharedData('build')
    },
    onRun: () => {
      api.ipcOn(onWebpackMessage)
    },
    onExit: () => {
      api.ipcOff(onWebpackMessage)
    },
    ...views
  })
  // vue inspect
  api.addTask({
    name: 'inspect',
    command: 'vue-cli-service inspect',
    description: 'vue-webpack.tasks.inspect.description',
    link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md#inspecting-the-projects-webpack-config',
    icon: '/_plugin/%40vue%2Fcli-service/webpack-inspect-logo.png',
    prompts: [
      {
        name: 'mode',
        type: 'list',
        default: 'production',
        choices: [
          {
            name: 'development',
            value: 'development'
          },
          {
            name: 'production',
            value: 'production'
          },
          {
            name: 'test',
            value: 'test'
          }
        ],
        description: 'vue-webpack.tasks.inspect.mode'
      },
      {
        name: 'verbose',
        type: 'confirm',
        default: false,
        description: 'vue-webpack.tasks.inspect.verbose'
      }
    ],
    onBeforeRun: ({ answers, args }) => {
      if (answers.mode) args.push('--mode', answers.mode)
      if (answers.verbose) args.push('--verbose')
    }
  })

  // Webpack dashboard
  api.addClientAddon({
    id: 'vue-webpack',
    path: '@vue/cli-ui-addon-webpack/dist'
  })

  // Open app button
  api.ipcOn(({ data }) => {
    if (data.vueServe) {
      setSharedData('serve-url', data.vueServe.url)
    }
  })
}


keep keep keep add keep keep keep keep keep

@vue/cli-plugin-unit-jest

unit-jest plugin for vue-cli


---
sidebarDepth: 3
---

# Plugin Development Guide

## Core Concepts

There are two major parts of the system:

- `@vue/cli`: globally installed, exposes the `vue create <app>` command;
- `@vue/cli-service`: locally installed, exposes the `vue-cli-service` commands.

Both utilize a plugin-based architecture.

### Creator

[Creator][creator-class] is the class created when invoking `vue create <app>`. Responsible for prompting for preferences, invoking generators and installing dependencies.

### Service

[Service][service-class] is the class created when invoking `vue-cli-service <command> [...args]`. Responsible for managing the internal webpack configuration, and exposes commands for serving and building the project.

### CLI Plugin

A CLI plugin is an npm package that can add additional features to a `@vue/cli` project. It should always contain a [Service Plugin](#service-plugin) as its main export, and can optionally contain a [Generator](#generator) and a [Prompt File](#prompts-for-3rd-party-plugins).

A typical CLI plugin's folder structure looks like the following:

```
.
├── README.md
├── generator.js  # generator (optional)
├── prompts.js    # prompts file (optional)
├── index.js      # service plugin
└── package.json
```

### Service Plugin

Service plugins are loaded automatically when a Service instance is created - i.e. every time the `vue-cli-service` command is invoked inside a project.

Note the concept of a "service plugin" we are discussing here is narrower than that of a "CLI plugin", which is published as an npm package. The former only refers to a module that will be loaded by `@vue/cli-service` when it's initialized, and is usually a part of the latter.

In addition, `@vue/cli-service`'s [built-in commands][commands] and [config modules][config] are also all implemented as service plugins.

A service plugin should export a function which receives two arguments:

- A [PluginAPI][plugin-api] instance

- An object containing project local options specified in `vue.config.js`, or in the `"vue"` field in `package.json`.

The API allows service plugins to extend/modify the internal webpack config for different environments and inject additional commands to `vue-cli-service`. Example:

``` js
module.exports = (api, projectOptions) => {
  api.chainWebpack(webpackConfig => {
    // modify webpack config with webpack-chain
  })

  api.configureWebpack(webpackConfig => {
    // modify webpack config
    // or return object to be merged with webpack-merge
  })

  api.registerCommand('test', args => {
    // register `vue-cli-service test`
  })
}
```

#### Specifying Mode for Commands

> Note: the way plugins set modes has been changed in beta.10.

If a plugin-registered command needs to run in a specific default mode,
the plugin needs to expose it via `module.exports.defaultModes` in the form
of `{ [commandName]: mode }`:

``` js
module.exports = api => {
  api.registerCommand('build', () => {
    // ...
  })
}

module.exports.defaultModes = {
  build: 'production'
}
```

This is because the command's expected mode needs to be known before loading environment variables, which in turn needs to happen before loading user options / applying the plugins.

#### Resolving Webpack Config in Plugins

A plugin can retrieve the resolved webpack config by calling `api.resolveWebpackConfig()`. Every call generates a fresh webpack config which can be further mutated as needed:

``` js
module.exports = api => {
  api.registerCommand('my-build', args => {
    const configA = api.resolveWebpackConfig()
    const configB = api.resolveWebpackConfig()

    // mutate configA and configB for different purposes...
  })
}

// make sure to specify the default mode for correct env variables
module.exports.defaultModes = {
  'my-build': 'production'
}
```

Alternatively, a plugin can also obtain a fresh [chainable config](https://github.com/mozilla-neutrino/webpack-chain) by calling `api.resolveChainableWebpackConfig()`:

``` js
api.registerCommand('my-build', args => {
  const configA = api.resolveChainableWebpackConfig()
  const configB = api.resolveChainableWebpackConfig()

  // chain-modify configA and configB for different purposes...

  const finalConfigA = configA.toConfig()
  const finalConfigB = configB.toConfig()
})
```

#### Custom Options for 3rd Party Plugins

The exports from `vue.config.js` will be [validated against a schema](https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-service/lib/options.js#L3) to avoid typos and wrong config values. However, a 3rd party plugin can still allow the user to configure its behavior via the `pluginOptions` field. For example, with the following `vue.config.js`:

``` js
module.exports = {
  pluginOptions: {
    foo: { /* ... */ }
  }
}
```

The 3rd party plugin can read `projectOptions.pluginOptions.foo` to determine conditional configurations.

### Generator

A CLI plugin published as a package can contain a `generator.js` or `generator/index.js` file. The generator inside a plugin will be invoked in two possible scenarios:

- During a project's initial creation, if the CLI plugin is installed as part of the project creation preset.

- When the plugin is installed after project's creation and invoked individually via `vue invoke`.

The [GeneratorAPI][generator-api] allows a generator to inject additional dependencies or fields into `package.json` and add files to the project.

A generator should export a function which receives three arguments:

1. A `GeneratorAPI` instance;

2. The generator options for this plugin. These options are resolved during the prompt phase of project creation, or loaded from a saved preset in `~/.vuerc`. For example, if the saved `~/.vuerc` looks like this:

    ``` json
    {
      "presets" : {
        "foo": {
          "plugins": {
            "@vue/cli-plugin-foo": { "option": "bar" }
          }
        }
      }
    }
    ```

    And if the user creates a project using the `foo` preset, then the generator of `@vue/cli-plugin-foo` will receive `{ option: 'bar' }` as its second argument.

    For a 3rd party plugin, the options will be resolved from the prompts or command line arguments when the user executes `vue invoke` (see [Prompts for 3rd Party Plugins](#prompts-for-3rd-party-plugins)).

3. The entire preset (`presets.foo`) will be passed as the third argument.

**Example:**

``` js
module.exports = (api, options, rootOptions) => {
  // modify package.json fields
  api.extendPackage({
    scripts: {
      test: 'vue-cli-service test'
    }
  })

  // copy and render all files in ./template with ejs
  api.render('./template')

  if (options.foo) {
    // conditionally generate files
  }
}
```

#### Generator Templating

When you call `api.render('./template')`, the generator will render files in `./template` (resolved relative to the generator file) with [EJS](https://github.com/mde/ejs).

In addition, you can inherit and replace parts of an existing template file (even from another package) using YAML front-matter:

``` ejs
---
extend: '@vue/cli-service/generator/template/src/App.vue'
replace: !!js/regexp /<script>[^]*?<\/script>/
---

<script>
export default {
  // Replace default script
}
</script>
```

It's also possible to do multiple replaces, although you will need to wrap your replace strings within `<%# REPLACE %>` and `<%# END_REPLACE %>` blocks:

``` ejs
---
extend: '@vue/cli-service/generator/template/src/App.vue'
replace:
  - !!js/regexp /Welcome to Your Vue\.js App/
  - !!js/regexp /<script>[^]*?<\/script>/
---

<%# REPLACE %>
Replace Welcome Message
<%# END_REPLACE %>

<%# REPLACE %>
<script>
export default {
  // Replace default script
}
</script>
<%# END_REPLACE %>
```

### Prompts

#### Prompts for Built-in Plugins

Only built-in plugins have the ability to customize the initial prompts when creating a new project, and the prompt modules are located [inside the `@vue/cli` package][prompt-modules].

A prompt module should export a function that receives a [PromptModuleAPI][prompt-api] instance. The prompts are presented using [inquirer](https://github.com/SBoudrias/Inquirer.js) under the hood:

``` js
module.exports = api => {
  // a feature object should be a valid inquirer choice object
  cli.injectFeature({
    name: 'Some great feature',
    value: 'my-feature'
  })

  // injectPrompt expects a valid inquirer prompt object
  cli.injectPrompt({
    name: 'someFlag',
    // make sure your prompt only shows up if user has picked your feature
    when: answers => answers.features.include('my-feature'),
    message: 'Do you want to turn on flag foo?',
    type: 'confirm'
  })

  // when all prompts are done, inject your plugin into the options that
  // will be passed on to Generators
  cli.onPromptComplete((answers, options) => {
    if (answers.features.includes('my-feature')) {
      options.plugins['vue-cli-plugin-my-feature'] = {
        someFlag: answers.someFlag
      }
    }
  })
}
```

#### Prompts for 3rd Party Plugins

3rd party plugins are typically installed manually after a project is already created, and the user will initialize the plugin by calling `vue invoke`. If the plugin contains a `prompts.js` in its root directory, it will be used during invocation. The file should export an array of [Questions](https://github.com/SBoudrias/Inquirer.js#question) that will be handled by Inquirer.js. The resolved answers object will be passed to the plugin's generator as options.

Alternatively, the user can skip the prompts and directly initialize the plugin by passing options via the command line, e.g.:

``` bash
vue invoke my-plugin --mode awesome
```

## Distributing the Plugin

For a CLI plugin to be usable by other developers, it must be published on npm following the name convention `vue-cli-plugin-<name>`. Following the name convention allows your plugin to be:

- Discoverable by `@vue/cli-service`;
- Discoverable by other developers via searching;
- Installable via `vue add <name>` or `vue invoke <name>`.

## Note on Development of Core Plugins

::: tip Note
This section only applies if you are working on a built-in plugin inside the `vuejs/vue-cli` repository itself.
:::

A plugin with a generator that injects additional dependencies other than packages in this repo (e.g. `chai` is injected by `@vue/cli-plugin-unit-mocha/generator/index.js`) should have those dependencies listed in its own `devDependencies` field. This ensures that:

1. the package always exist in this repo's root `node_modules` so that we don't have to reinstall them on every test.

2. `yarn.lock` stays consistent so that CI can better use it for inferring caching behavior.

[creator-class]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli/lib/Creator.js
[service-class]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-service/lib/Service.js
[generator-api]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli/lib/GeneratorAPI.js
[commands]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-service/lib/commands
[config]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-service/lib/config
[plugin-api]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli-service/lib/PluginAPI.js
[prompt-modules]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli/lib/promptModules
[prompt-api]: https://github.com/vuejs/vue-cli/tree/dev/packages/@vue/cli/lib/PromptModuleAPI.js


<%_ if (options.tsLint) { _%>
{
  "defaultSeverity": "warning",
  "extends": [
    "tslint:recommended"
  ],
  "linterOptions": {
    "exclude": [
      "node_modules/**"
    ]
  },
  "rules": {
    "quotemark": [true, "single"],
    "indent": [true, "spaces", 2],
    "interface-name": false,
    "ordered-imports": false,
    "object-literal-sort-keys": false,
    "no-consecutive-blank-lines": false
  }
}
<%_ } _%>


<!DOCTYPE html>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="shortcut icon" href="<%= webpackConfig.output.publicPath %>favicon.ico">
    <title>Vue CLI</title>

      We're sorry but cli-ui doesn't work properly without JavaScript enabled. Please enable it to continue.


keep keep keep keep add keep keep keep keep


<template>
  <div
    class="project-nav"
    :class="{
      wide: $responsive.wide
    }"
  >
    <div class="content">
      <VueGroup
        v-model="currentView"
        class="vertical small-indicator left-indicator primary"
        indicator
      >
        <ProjectNavButton
          v-for="view of views"
          :key="view.id"
          :view="view"
        />
      </VueGroup>

      <ProjectNavMore/>
    </div>
  </div>
</template>

<script>
import { isSameRoute, isIncludedRoute } from '../util/route'

import VIEWS from '../graphql/views.gql'
import VIEW_ADDED from '../graphql/viewAdded.gql'
import VIEW_REMOVED from '../graphql/viewRemoved.gql'
import VIEW_CHANGED from '../graphql/viewChanged.gql'

export default {
  data () {
    return {
      views: []
    }
  },

  apollo: {
    views: {
      query: VIEWS,
      subscribeToMore: [
        {
          document: VIEW_ADDED,
          updateQuery: (previousResult, { subscriptionData }) => {
            const view = subscriptionData.data.viewAdded
            if (!previousResult.views) {
              return {
                views: [ view ]
              }
            }
            if (previousResult.views.find(r => r.id === view.id)) return previousResult
            return {
              views: [
                ...previousResult.views,
                view
              ]
            }
          }
        },
        {
          document: VIEW_REMOVED,
          updateQuery: (previousResult, { subscriptionData }) => {
            const index = previousResult.views.findIndex(r => r.id === subscriptionData.data.viewRemoved.id)
            if (index === -1) return previousResult
            const views = previousResult.views.slice()
            views.splice(index, 1)
            return {
              views
            }
          }
        },
        {
          document: VIEW_CHANGED,
          updateQuery: (previousResult, { subscriptionData }) => {
            const view = subscriptionData.data.viewChanged
            const index = previousResult.views.findIndex(r => r.id === view.id)
            if (index === -1) return previousResult
            const views = previousResult.views.slice()
            views.splice(index, 1, view)
            return {
              views
            }
          }
        }
      ]
    }
  },

  computed: {
    currentView: {
      get () {
        const currentRoute = this.$route
        const view = this.views.find(
          item => isIncludedRoute(currentRoute, this.$router.resolve({ name: item.name }).route)
        )
        return view && view.name
      },
      set (name) {
        if (!isSameRoute(this.$route, this.$router.resolve({ name }).route)) {
          this.$router.push({ name })
        }
      }
    }
  }
}
</script>

<style lang="stylus" scoped>
@import "~@/style/imports"

.project-nav
  background $vue-ui-color-dark

  .content
    v-box()
    height 100%
    padding 8px 0
    box-sizing border-box

    .vue-ui-group
      flex auto 1 1
      height 0
      overflow hidden

    >>> .v-popover .trigger,
    >>> .vue-ui-dropdown
      display block !important

    >>> .vue-ui-button
      button-colors(rgba($vue-ui-color-light, .7), transparent)
      border-radius 0
      padding-left 0
      padding-right @padding-left
      h-box()
      box-center()
      width 100%

      &:hover, &:active
        $bg = darken($vue-ui-color-dark, 70%)
        button-colors($vue-ui-color-light, $bg)
        &.selected
          button-colors(lighten($vue-ui-color-primary, 40%), $bg)

  &.wide
    >>> .vue-ui-button
      justify-content flex-start
      padding-left $padding-item
      padding-right @padding-left
      > .content
        width 100%
        text-align left
        > .default-slot
          flex auto 1 1
          width 0
          ellipsis()
          padding 4px 0
</style>


const chalk = require('chalk')

const rules = [
  {
    type: 'cant-resolve-loader',
    re: /Can't resolve '(.*loader)'/,
    msg: (e, match) => (
      `Failed to resolve loader: ${chalk.yellow(match[1])}\n` +
      `You may need to install it.`
    )
  }
]

exports.transformer = error => {
  if (error.webpackError) {
    const message = typeof error.webpackError === 'string'
      ? error.webpackError
      : error.webpackError.message || ''
    for (const { re, msg, type } of rules) {
      const match = message.match(re)
      if (match) {
        return Object.assign({}, error, {
          // type is necessary to avoid being printed as defualt error
          // by friendly-error-webpack-plugin
          type,
          shortMessage: msg(error, match)
        })
      }
    }
    // no match, unknown webpack error withotu a message.
    // friendly-error-webpack-plugin fails to handle this.
    if (!error.message) {
      return Object.assign({}, error, {
        type: 'unknown-webpack-error',
        shortMessage: message
      })
    }
  }
  return error
}

exports.formatter = errors => {
  errors = errors.filter(e => e.shortMessage)
  if (errors.length) {
    return errors.map(e => e.shortMessage)
  }
}


jest.setTimeout(20000)

const create = require('@vue/cli-test-utils/createTestProject')

test('should work', async () => {
  const project = await create('unit-jest', {
    plugins: {
      '@vue/cli-plugin-babel': {},
      '@vue/cli-plugin-unit-jest': {}
    }
  })
  await project.run(`vue-cli-service test:unit`)
})

test('should respect jest testMatch config', async () => {
  const project = await create('unit-jest-package.json', {
    plugins: {
      '@vue/cli-plugin-babel': {},
      '@vue/cli-plugin-unit-jest': {}
    }
  })
  const config = JSON.parse(await project.read('package.json'))
  config.jest.testMatch = ['custom-test-directory/my.spec.js']

  await project.write('package.json', JSON.stringify(config))

  let result
  try {
    await project.run(`vue-cli-service test:unit`)
  } catch (e) {
    result = e
  }
  expect(result.stdout).toMatch('testMatch: custom-test-directory/my.spec.js')
  expect(result.stdout).toMatch('No tests found')
})

test('should respect jest.config.js testMatch config', async () => {
  const project = await create('unit-jest-jest.config.js', {
    plugins: {
      '@vue/cli-plugin-babel': {},
      '@vue/cli-plugin-unit-jest': {}
    },
    useConfigFiles: true
  })
  await project.write('jest.config.js', `
  module.exports = ${JSON.stringify({
    testMatch: ['custom-test-directory/my.spec.js']
  })}
  `)

  let result
  try {
    await project.run(`vue-cli-service test:unit`)
  } catch (e) {
    result = e
  }
  expect(result.stdout).toMatch('testMatch: custom-test-directory/my.spec.js')
  expect(result.stdout).toMatch('No tests found')
})


module.exports = api => {
  // Config file
  api.describeConfig({
    id: 'eslintrc',
    name: 'ESLint configuration',
    description: 'eslint.config.eslint.description',
    link: 'https://github.com/vuejs/eslint-plugin-vue',
    files: {
      json: ['.eslintrc', '.eslintrc.json'],
      js: ['.eslintrc.js'],
      package: 'eslintConfig'
    },
    onRead: ({ data }) => ({
      prompts: [
        {
          name: 'vue/attribute-hyphenation',
          type: 'list',
          message: 'Attribute hyphenation',
          group: 'eslint.config.eslint.groups.strongly-recommended',
          description: 'Enforce attribute naming style in template (`my-prop` or `myProp`)',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attribute-hyphenation.md',
          default: JSON.stringify('off'),
          choices: [
            {
              name: 'Off',
              value: JSON.stringify('off')
            },
            {
              name: 'Never',
              value: JSON.stringify(['error', 'never'])
            },
            {
              name: 'Always',
              value: JSON.stringify(['error', 'always'])
            }
          ],
          value: data.rules && JSON.stringify(data.rules['vue/attribute-hyphenation'])
        },
        {
          name: 'vue/html-end-tags',
          type: 'confirm',
          message: 'Template end tags style',
          group: 'eslint.config.eslint.groups.strongly-recommended',
          description: 'End tag on Void elements, end tags and self-closing opening tags',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-end-tags.md',
          default: false,
          value: data.rules && data.rules['vue/html-end-tags'] === 'error',
          filter: input => JSON.stringify(input ? 'error' : 'off'),
          transformer: input => input === JSON.stringify('error')
        },
        {
          name: 'vue/html-indent',
          type: 'list',
          message: 'Template indentation',
          group: 'eslint.config.eslint.groups.strongly-recommended',
          description: 'Enforce indentation in template',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-indent.md',
          default: JSON.stringify('off'),
          choices: [
            {
              name: 'Off',
              value: JSON.stringify('off')
            },
            {
              name: 'Tabs',
              value: JSON.stringify(['error', 'tab'])
            },
            {
              name: '2 spaces',
              value: JSON.stringify(['error', 2])
            },
            {
              name: '4 spaces',
              value: JSON.stringify(['error', 4])
            },
            {
              name: '8 spaces',
              value: JSON.stringify(['error', 8])
            }
          ],
          value: data.rules && JSON.stringify(data.rules['vue/html-indent'])
        },
        {
          name: 'vue/html-self-closing',
          type: 'confirm',
          message: 'Template tag self-closing style',
          group: 'eslint.config.eslint.groups.strongly-recommended',
          description: 'Self-close any component or non-Void element tags',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-self-closing.md',
          default: false,
          value: data.rules && data.rules['vue/html-self-closing'] === 'error',
          filter: input => JSON.stringify(input ? 'error' : 'off'),
          transformer: input => input === JSON.stringify('error')
        },
        {
          name: 'vue/require-default-prop',
          type: 'confirm',
          message: 'Require default in required props',
          group: 'eslint.config.eslint.groups.strongly-recommended',
          description: 'This rule requires default value to be set for each props that are not marked as `required`',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-default-prop.md',
          default: false,
          value: data.rules && data.rules['vue/require-default-prop'] === 'error',
          filter: input => JSON.stringify(input ? 'error' : 'off'),
          transformer: input => input === JSON.stringify('error')
        },
        {
          name: 'vue/require-prop-types',
          type: 'confirm',
          message: 'Require types for props',
          group: 'eslint.config.eslint.groups.strongly-recommended',
          description: 'In committed code, prop definitions should always be as detailed as possible, specifying at least type(s)',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-prop-types.md',
          default: false,
          value: data.rules && data.rules['vue/require-prop-types'] === 'error',
          filter: input => JSON.stringify(input ? 'error' : 'off'),
          transformer: input => input === JSON.stringify('error')
        },
        {
          name: 'vue/attributes-order',
          type: 'confirm',
          message: 'Attribute order',
          group: 'eslint.config.eslint.groups.recommended',
          description: 'This rule aims to enforce ordering of component attributes (the default order is specified in the Vue style guide)',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attributes-order.md',
          default: false,
          value: data.rules && data.rules['vue/attributes-order'] === 'error',
          filter: input => JSON.stringify(input ? 'error' : 'off'),
          transformer: input => input === JSON.stringify('error')
        },
        {
          name: 'vue/html-quotes',
          type: 'list',
          message: 'Attribute quote style',
          group: 'eslint.config.eslint.groups.recommended',
          description: 'Enforce style of the attribute quotes in templates',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/html-quotes.md',
          default: JSON.stringify('off'),
          choices: [
            {
              name: 'Off',
              value: JSON.stringify('off')
            },
            {
              name: 'Double quotes',
              value: JSON.stringify(['error', 'double'])
            },
            {
              name: 'Single quotes',
              value: JSON.stringify(['error', 'single'])
            }
          ],
          value: data.rules && JSON.stringify(data.rules['vue/html-quotes'])
        },
        {
          name: 'vue/order-in-components',
          type: 'confirm',
          message: 'Component options order',
          group: 'eslint.config.eslint.groups.recommended',
          description: 'This rule aims to enforce ordering of component options (the default order is specified in the Vue style guide)',
          link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/order-in-components.md',
          default: false,
          value: data.rules && data.rules['vue/order-in-components'] === 'error',
          filter: input => JSON.stringify(input ? 'error' : 'off'),
          transformer: input => input === JSON.stringify('error')
        }
      ]
    }),
    onWrite: async ({ api, prompts }) => {
      const result = {}
      for (const prompt of prompts) {
        result[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse)
      }
      api.setData(result)
    }
  })

  api.describeConfig({
    id: 'eslintrc-config',
    name: 'ESLint extra',
    description: 'eslint.config.eslint-extra.description',
    link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint#configuration',
    files: {
      js: ['vue.config.js']
    },
    onRead: ({ data }) => ({
      prompts: [
        {
          name: 'lintOnSave',
          type: 'confirm',
          message: 'eslint.config.eslint-extra.lintOnSave.message',
          description: 'eslint.config.eslint-extra.lintOnSave.description',
          link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint#configuration',
          default: true,
          value: data.lintOnSave
        }
      ]
    }),
    onWrite: async ({ api, prompts }) => {
      const result = {}
      for (const prompt of prompts) {
        result[prompt.id] = await api.getAnswer(prompt.id)
      }
      api.setData(result)
    }
  })

  // Tasks
  api.describeTask({
    match: /vue-cli-service lint/,
    description: 'eslint.tasks.lint.description',
    link: 'https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint#injected-commands',
    prompts: [
      {
        name: 'noFix',
        type: 'confirm',
        default: false,
        description: 'eslint.tasks.lint.noFix'
      }
    ],
    onBeforeRun: ({ answers, args }) => {
      if (answers.noFix) args.push('--no-fix')
    }
  })
}


#import "./viewFragment.gql"

subscription viewRemoved {
  viewRemoved {
    ...view
  }
}


| [options.include[].include] | Array.<Object | Model> | Load further nested related models |

| [options.order] | String | Array | Sequelize.fn | Specifies an ordering. If a string is provided, it will be escaped. Using an array, you can provide several columns / functions to order by. Each element can be further wrapped in a two-element array. The first element is the column / function to order by, the second is the direction. For example: `order: [['name', 'DESC']]`. In this way the column will be escaped, but the direction will not. |

| [options.transaction] | Transaction | Transaction to run query under |

| [options.lock] | String | Object | Lock the selected rows. Possible options are transaction.LOCK.UPDATE and transaction.LOCK.SHARE. Postgres also supports transaction.LOCK.KEY_SHARE, transaction.LOCK.NO_KEY_UPDATE and specific model locks with joins. See [transaction.LOCK for an example](api/transaction#lock) |

| [options.raw] | Boolean | Return raw result. See sequelize.query for more information. |

| [options.logging=false] | Function | A function that gets executed while running the query to log the sql. |

keep keep keep keep keep replace keep keep keep keep keep

| [options.lock] | String | Object | Lock the selected rows. Possible options are transaction.LOCK.UPDATE and transaction.LOCK.SHARE. Postgres also supports transaction.LOCK.KEY_SHARE, transaction.LOCK.NO_KEY_UPDATE and specific model locks with joins. See [transaction.LOCK for an example](transaction#lock) |

## Definition

To define mappings between a model and a table, use the `define` method. Sequelize will then automatically add the attributes `createdAt` and `updatedAt` to it. So you will be able to know when the database entry went into the db and when it was updated the last time. If you do not want timestamps on your models, only want some timestamps, or you are working with an existing database where the columns are named something else, jump straight on to [configuration ][0]to see how to do that.

```js
var Project = sequelize.define('Project', {
  title: Sequelize.STRING,
  description: Sequelize.TEXT
})

var Task = sequelize.define('Task', {
  title: Sequelize.STRING,
  description: Sequelize.TEXT,
  deadline: Sequelize.DATE
})
```

You can also set some options on each column:

```js
var Foo = sequelize.define('Foo', {
 // instantiating will automatically set the flag to true if not set
 flag: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true},

 // default values for dates => current time
 myDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },

 // setting allowNull to false will add NOT NULL to the column, which means an error will be
 // thrown from the DB when the query is executed if the column is null. If you want to check that a value
 // is not null before querying the DB, look at the validations section below.
 title: { type: Sequelize.STRING, allowNull: false},

 // Creating two objects with the same value will throw an error. The unique property can be either a
 // boolean, or a string. If you provide the same string for multiple columns, they will form a
 // composite unique key.
 someUnique: {type: Sequelize.STRING, unique: true},
 uniqueOne: { type: Sequelize.STRING,  unique: 'compositeIndex'},
 uniqueTwo: { type: Sequelize.INTEGER, unique: 'compositeIndex'}

 // Go on reading for further information about primary keys
 identifier: { type: Sequelize.STRING, primaryKey: true},

 // autoIncrement can be used to create auto_incrementing integer columns
 incrementMe: { type: Sequelize.INTEGER, autoIncrement: true },

 // Comments can be specified for each field for MySQL and PG
 hasComment: { type: Sequelize.INTEGER, comment: "I'm a comment!" },

 // You can specify a custom field name via the "field" attribute:
 fieldWithUnderscores: { type: Sequelize.STRING, field: "field_with_underscores" },

 // It is possible to create foreign keys:
 bar_id: {
   type: Sequelize.INTEGER,

   references: {
     // This is a reference to another model
     model: Bar,

     // This is the column name of the referenced model
     key: 'id',

     // This declares when to check the foreign key constraint. PostgreSQL only.
     deferrable: Sequelize.Deferrable.INITIALLY_IMMEDIATE
   }
 }
})
```

The comment option can also be used on a table, see [model configuration][0]

## Data types

Below are some of the datatypes supported by sequelize. For a full and updated list, see [DataTypes](api/datatypes).

```js
Sequelize.STRING                      // VARCHAR(255)
Sequelize.STRING(1234)                // VARCHAR(1234)
Sequelize.STRING.BINARY               // VARCHAR BINARY
Sequelize.TEXT                        // TEXT

Sequelize.INTEGER                     // INTEGER
Sequelize.BIGINT                      // BIGINT
Sequelize.BIGINT(11)                  // BIGINT(11)

Sequelize.FLOAT                       // FLOAT
Sequelize.FLOAT(11)                   // FLOAT(11)
Sequelize.FLOAT(11, 12)               // FLOAT(11,12)

Sequelize.REAL                        // REAL        PostgreSQL only.
Sequelize.REAL(11)                    // REAL(11)    PostgreSQL only.
Sequelize.REAL(11, 12)                // REAL(11,12) PostgreSQL only.

Sequelize.DOUBLE                      // DOUBLE
Sequelize.DOUBLE(11)                  // DOUBLE(11)
Sequelize.DOUBLE(11, 12)              // DOUBLE(11,12)

Sequelize.DECIMAL                     // DECIMAL
Sequelize.DECIMAL(10, 2)              // DECIMAL(10,2)

Sequelize.DATE                        // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres
Sequelize.BOOLEAN                     // TINYINT(1)

Sequelize.ENUM('value 1', 'value 2')  // An ENUM with allowed values 'value 1' and 'value 2'
Sequelize.ARRAY(Sequelize.TEXT)       // Defines an array. PostgreSQL only.

Sequelize.JSON                        // JSON column. PostgreSQL only.
Sequelize.JSONB                       // JSONB column. PostgreSQL only.

Sequelize.BLOB                        // BLOB (bytea for PostgreSQL)
Sequelize.BLOB('tiny')                // TINYBLOB (bytea for PostgreSQL. Other options are medium and long)

Sequelize.UUID                        // UUID datatype for PostgreSQL and SQLite, CHAR(36) BINARY for MySQL (use defaultValue: Sequelize.UUIDV1 or Sequelize.UUIDV4 to make sequelize generate the ids automatically)
```

The BLOB data type allows you to insert data both as strings and as buffers. When you do a find or findAll on a model which has a BLOB column. that data will always be returned as a buffer.

If you are working with the PostgreSQL TIMESTAMP WITHOUT TIME ZONE and you need to parse it to a different timezone, please use the pg library's own parser:

```js
require('pg').types.setTypeParser(1114, function(stringValue) {
  return new Date(stringValue + "+0000");
  // e.g., UTC offset. Use any offset that you would like.
});
```

In addition to the type mentioned above, integer, bigint, float and double also support unsigned and zerofill properties, which can be combined in any order:
Be aware that this does not apply for PostgreSQL!

```js
Sequelize.INTEGER.UNSIGNED              // INTEGER UNSIGNED
Sequelize.INTEGER(11).UNSIGNED          // INTEGER(11) UNSIGNED
Sequelize.INTEGER(11).ZEROFILL          // INTEGER(11) ZEROFILL
Sequelize.INTEGER(11).ZEROFILL.UNSIGNED // INTEGER(11) UNSIGNED ZEROFILL
Sequelize.INTEGER(11).UNSIGNED.ZEROFILL // INTEGER(11) UNSIGNED ZEROFILL
```

_The examples above only show integer, but the same can be done with bigint and float_

Usage in object notation:

```js
// for enums:
sequelize.define('model', {
  states: {
    type:   Sequelize.ENUM,
    values: ['active', 'pending', 'deleted']
  }
})
```

## Deferrable

When you specify a foreign key column it is optionally possible to declare the deferrable
type in PostgreSQL. The following options are available:

```js
// Defer all foreign key constraint check to the end of a transaction
Sequelize.Deferrable.INITIALLY_DEFERRED

// Immediately check the foreign key constraints
Sequelize.Deferrable.INITIALLY_IMMEDIATE

// Don't defer the checks at all
Sequelize.Deferrable.NOT
```

The last option is the default in PostgreSQL and won't allow you to dynamically change
the rule in a transaction. See [the transaction section](docs/transactions/#options) for further information.

## Getters & setters

It is possible to define 'object-property' getters and setter functions on your models, these can be used both for 'protecting' properties that map to database fields and for defining 'pseudo' properties.

Getters and Setters can be defined in 2 ways (you can mix and match these 2 approaches):

* as part of a single property definition
* as part of a model options

**N.B:** If a getter or setter is defined in both places then the function found in the relevant property definition will always take precedence.

### Defining as part of a property

```js
var Employee = sequelize.define('Employee', {
  name:  {
    type     : Sequelize.STRING,
    allowNull: false,
    get      : function()  {
      var title = this.getDataValue('title');
      // 'this' allows you to access attributes of the instance
      return this.getDataValue('name') + ' (' + title + ')';
    },
  },
  title: {
    type     : Sequelize.STRING,
    allowNull: false,
    set      : function(val) {
      this.setDataValue('title', val.toUpperCase());
    }
  }
});

Employee
  .create({ name: 'John Doe', title: 'senior engineer' })
  .then(function(employee) {
    console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
    console.log(employee.get('title')); // SENIOR ENGINEER
  })
```

### Defining as part of the model options

Below is an example of defining the getters and setters in the model options. The `fullName` getter,  is an example of how you can define pseudo properties on your models - attributes which are not actually part of your database schema. In fact, pseudo properties can be defined in two ways: using model getters, or by using a column with the [`VIRTUAL` datatype](api/datatypes#virtual). Virtual datatypes can have validations, while getters for virtual attributes cannot.

Note that the `this.firstname` and `this.lastname` references in the `fullName` getter function will trigger a call to the respective getter functions. If you do not want that then use the `getDataValue()` method to access the raw value (see below).

```js
var Foo = sequelize.define('Foo', {
  firstname: Sequelize.STRING,
  lastname: Sequelize.STRING
}, {
  getterMethods   : {
    fullName       : function()  { return this.firstname + ' ' + this.lastname }
  },

  setterMethods   : {
    fullName       : function(value) {
        var names = value.split(' ');

        this.setDataValue('firstname', names.slice(0, -1).join(' '));
        this.setDataValue('lastname', names.slice(-1).join(' '));
    },
  }
});
```

### Helper functions for use inside getter and setter definitions

* retrieving an underlying property value - always use `this.getDataValue()`

```js
/* a getter for 'title' property */
function() {
    return this.getDataValue('title');
}
```

* setting an underlying property value - always use `this.setDataValue()`

```js
/* a setter for 'title' property */
function(title) {
    return this.setDataValue('title', title.toString().toLowerCase());
}
```

**N.B:** It is important to stick to using the `setDataValue()` and `getDataValue()` functions (as opposed to accessing the underlying "data values" property directly) - doing so protects your custom getters and setters from changes in the underlying model implementations.

## Validations

Model validations, allow you to specify format/content/inheritance validations for each attribute of the model.

Validations are automatically run on `create`, `update` and `save`. You can also call `validate()` to manually validate an instance.

The validations are implemented by [validator][3].

```js
var ValidateMe = sequelize.define('Foo', {
  foo: {
    type: Sequelize.STRING,
    validate: {
      is: ["^[a-z]+$",'i'],     // will only allow letters
      is: /^[a-z]+$/i,          // same as the previous example using real RegExp
      not: ["[a-z]",'i'],       // will not allow letters
      isEmail: true,            // checks for email format (foo@bar.com)
      isUrl: true,              // checks for url format (http://foo.com)
      isIP: true,               // checks for IPv4 (129.89.23.1) or IPv6 format
      isIPv4: true,             // checks for IPv4 (129.89.23.1)
      isIPv6: true,             // checks for IPv6 format
      isAlpha: true,            // will only allow letters
      isAlphanumeric: true      // will only allow alphanumeric characters, so "_abc" will fail
      isNumeric: true           // will only allow numbers
      isInt: true,              // checks for valid integers
      isFloat: true,            // checks for valid floating point numbers
      isDecimal: true,          // checks for any numbers
      isLowercase: true,        // checks for lowercase
      isUppercase: true,        // checks for uppercase
      notNull: true,            // won't allow null
      isNull: true,             // only allows null
      notEmpty: true,           // don't allow empty strings
      equals: 'specific value', // only allow a specific value
      contains: 'foo',          // force specific substrings
      notIn: [['foo', 'bar']],  // check the value is not one of these
      isIn: [['foo', 'bar']],   // check the value is one of these
      notContains: 'bar',       // don't allow specific substrings
      len: [2,10],              // only allow values with length between 2 and 10
      isUUID: 4,                // only allow uuids
      isDate: true,             // only allow date strings
      isAfter: "2011-11-05",    // only allow date strings after a specific date
      isBefore: "2011-11-05",   // only allow date strings before a specific date
      max: 23,                  // only allow values
      min: 23,                  // only allow values >= 23
      isArray: true,            // only allow arrays
      isCreditCard: true,       // check for valid credit card numbers

      // custom validations are also possible:
      isEven: function(value) {
        if(parseInt(value) % 2 != 0) {
          throw new Error('Only even values are allowed!')
        // we also are in the model's context here, so this.otherField
        // would get the value of otherField if it existed
        }
      }
    }
  }
})
```

Note that where multiple arguments need to be passed to the built-in validation functions, the arguments to be passed must be in an array. But if a single array argument is to be passed, for instance an array of acceptable strings for `isIn`, this will be interpreted as multiple string arguments instead of one array argument. To work around this pass a single-length array of arguments, such as `[['one', 'two']]` as shown above.

To use a custom error message instead of that provided by node-validator, use an object instead of the plain value or array of arguments, for example a validator which needs no argument can be given a custom message with

```js
isInt: {
  msg: "Must be an integer number of pennies"
}
```

or if arguments need to also be passed add an`args`property:

```js
isIn: {
  args: [['en', 'zh']],
  msg: "Must be English or Chinese"
}
```

When using custom validator functions the error message will be whatever message the thrown`Error`object holds.

See [the node-validator project][4]for more details on the built in validation methods.

**Hint: **You can also define a custom function for the logging part. Just pass a function. The first parameter will be the string that is logged.

### Validators and `allowNull`

If a particular field of a model is set to allow null (with `allowNull: true`) and that value has been set to `null` , its validators do not run. This means you can, for instance, have a string field which validates its length to be at least 5 characters, but which also allows`null`.

### Model validations

Validations can also be defined to check the model after the field-specific validators. Using this you could, for example, ensure either neither of `latitude` and `longitude` are set or both, and fail if one but not the other is set.

Model validator methods are called with the model object's context and are deemed to fail if they throw an error, otherwise pass. This is just the same as with custom field-specific validators.

Any error messages collected are put in the validation result object alongside the field validation errors, with keys named after the failed validation method's key in the `validate` option object. Even though there can only be one error message for each model validation method at any one time, it is presented as a single string error in an array, to maximize consistency with the field errors. (Note that the structure of `validate()`'s output is scheduled to change in `v2.0`to avoid this awkward situation. In the mean time, an error is issued if a field exists with the same name as a custom model validation.)

An example:

```js
var Pub = Sequelize.define('Pub', {
  name: { type: Sequelize.STRING },
  address: { type: Sequelize.STRING },
  latitude: {
    type: Sequelize.INTEGER,
    allowNull: true,
    defaultValue: null,
    validate: { min: -90, max: 90 }
  },
  longitude: {
    type: Sequelize.INTEGER,
    allowNull: true,
    defaultValue: null,
    validate: { min: -180, max: 180 }
  },
}, {
  validate: {
    bothCoordsOrNone: function() {
      if ((this.latitude === null) !== (this.longitude === null)) {
        throw new Error('Require either both latitude and longitude or neither')
      }
    }
  }
})
```

In this simple case an object fails validation if either latitude or longitude is given, but not both. If we try to build one with an out-of-range latitude and nolongitude, `raging_bullock_arms.validate()` might return

```js
{
  'latitude': ['Invalid number: latitude'],
  'bothCoordsOrNone': ['Require either both latitude and longitude or neither']
}
```

## Configuration

You can also influence the way Sequelize handles your column names:

```js
var Bar = sequelize.define('Bar', { /* bla */ }, {
  // don't add the timestamp attributes (updatedAt, createdAt)
  timestamps: false,

  // don't delete database entries but set the newly added attribute deletedAt
  // to the current date (when deletion was done). paranoid will only work if
  // timestamps are enabled
  paranoid: true,

  // don't use camelcase for automatically added attributes but underscore style
  // so updatedAt will be updated_at
  underscored: true,

  // disable the modification of tablenames; By default, sequelize will automatically
  // transform all passed model names (first parameter of define) into plural.
  // if you don't want that, set the following
  freezeTableName: true,

  // define the table's name
  tableName: 'my_very_custom_table_name'
})
```

If you want sequelize to handle timestamps, but only want some of them, or want your timestamps to be called something else, you can override each column individually:

```js
var Foo = sequelize.define('Foo',  { /* bla */ }, {
  // don't forget to enable timestamps!
  timestamps: true,

  // I don't want createdAt
  createdAt: false,

  // I want updatedAt to actually be called updateTimestamp
  updatedAt: 'updateTimestamp'

  // And deletedAt to be called destroyTime (remember to enable paranoid for this to work)
  deletedAt: 'destroyTime',
  paranoid: true
})
```

You can also change the database engine, e.g. to MyISAM. InnoDB is the default.

```js
var Person = sequelize.define('Person', { /* attributes */ }, {
  engine: 'MYISAM'
})

// or globally
var sequelize = new Sequelize(db, user, pw, {
  define: { engine: 'MYISAM' }
})
```

Finaly you can specify a comment for the table in MySQL and PG

```js
var Person = sequelize.define('Person', { /* attributes */ }, {
  comment: "I'm a table comment!"
})
```

## Import

You can also store your model definitions in a single file using the `import` method. The returned object is exactly the same as defined in the imported file's function. Since `v1:5.0` of Sequelize the import is cached, so you won't run into troubles when calling the import of a file twice or more often.

```js
// in your server file - e.g. app.js
var Project = sequelize.import(__dirname + "/path/to/models/project")

// The model definition is done in /path/to/models/project.js
// As you might notice, the DataTypes are the very same as explained above
module.exports = function(sequelize, DataTypes) {
  return sequelize.define("Project", {
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  })
}
```

The `import` method can also accept a callback as an argument.

```js
sequelize.import('Project', function(sequelize, DataTypes) {
  return sequelize.define("Project", {
    name: DataTypes.STRING,
    description: DataTypes.TEXT
  })
})
```

## Database synchronization

When starting a new project you won't have a database structure and using Sequelize you won't need to. Just specify your model structures and let the library do the rest. Currently supported is the creation and deletion of tables:

```js
// Create the tables:
Project.sync()
Task.sync()

// Force the creation!
Project.sync({force: true}) // this will drop the table first and re-create it afterwards

// drop the tables:
Project.drop()
Task.drop()

// event handling:
Project.[sync|drop]().then(function() {
  // ok ... everything is nice!
}).catch(function(error) {
  // oooh, did you enter wrong database credentials?
})
```

Because synchronizing and dropping all of your tables might be a lot of lines to write, you can also let Sequelize do the work for you:

```js
// Sync all models that aren't already in the database
sequelize.sync()

// Force sync all modes
sequelize.sync({force: true})

// Drop all tables
sequelize.drop()

// emit handling:
sequelize.[sync|drop]().then(function() {
  // woot woot
}).catch(function(error) {
  // whooops
})
```

Because `.sync({ force: true })` is destructive operation, you can use `match` option as an additional safety check.
`match` option tells sequelize to match a regex against the database name before syncing - a safety check for cases
where `force: true` is used in tests but not live code.

```js
// This will run .sync() only if database name ends with '_test'
sequelize.sync({ force: true, match: /_test$/ });
```

## Expansion of models

Sequelize allows you to pass custom methods to a model and its instances. Just do the following:

```js
var Foo = sequelize.define('Foo', { /* attributes */}, {
  classMethods: {
    method1: function(){ return 'smth' }
  },
  instanceMethods: {
    method2: function() { return 'foo' }
  }
})

// Example:
Foo.method1()
Foo.build().method2()
```

Of course you can also access the instance's data and generate virtual getters:

```js
var User = sequelize.define('User', { firstname: Sequelize.STRING, lastname: Sequelize.STRING }, {
  instanceMethods: {
    getFullname: function() {
      return [this.firstname, this.lastname].join(' ')
    }
  }
})

// Example:
User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'
```

You can also set custom methods to all of your models during the instantiation:

```js
var sequelize = new Sequelize('database', 'username', 'password', {
  // Other options during the initialization could be here
  define: {
    classMethods: {
      method1: function() {},
      method2: function() {}
    },
    instanceMethods: {
      method3: function() {}
    }
  }
})

// Example:
var Foo = sequelize.define('Foo', { /* attributes */});
Foo.method1()
Foo.method2()
Foo.build().method3()
```

### Indexes
Sequelize supports adding indexes to the model definition which will be created during `Model.sync()` or `sequelize.sync`.

```js
sequelize.define('User', {}, {
  indexes: [
    // Create a unique index on email
    {
      unique: true,
      fields: ['email']
    },

    // Creates a gin index on data with the jsonb_path_ops operator
    {
      fields: ['data'],
      using: 'gin',
      operator: 'jsonb_path_ops'
    },

    // By default index name will be [table]_[fields]
    // Creates a multi column partial index
    {
      name: 'public_by_author',
      fields: ['author', 'status'],
      where: {
        status: 'public'
      }
    },

    // A BTREE index with a ordered field
    {
      name: 'title_index',
      method: 'BTREE',
      fields: ['author', {attribute: 'title', collate: 'en_US', order: 'DESC', length: 5}]
    }
  ]
})
```

[0]: #configuration
[3]: https://github.com/chriso/validator.js
[4]: https://github.com/chriso/node-validator
[5]: /docs/latest/misc#asynchronicity
[6]: https://github.com/petkaantonov/bluebird/blob/master/API.md#spreadfunction-fulfilledhandler--function-rejectedhandler----promise


'use strict';

/* jshint -W030 */
var chai = require('chai')
  , expect = chai.expect
  , Support   = require(__dirname + '/../support')
  , DataTypes = require(__dirname + '/../../../lib/data-types')
  , current   = Support.sequelize;

describe(Support.getTestDialectTeaser('Instance'), function() {
  describe('build', function () {
    it('should popuplate NOW default values', function () {
      var Model = current.define('Model', {
          created_time: {
            type: DataTypes.DATE,
            allowNull: true,
            defaultValue: DataTypes.NOW
          },
          updated_time: {
            type: DataTypes.DATE,
            allowNull: true,
            defaultValue: DataTypes.NOW
          },
          ip: {
            type: DataTypes.STRING,
            validate: {
              isIP: true
            }
          },
          ip2: {
            type: DataTypes.STRING,
            validate: {
              isIP: {
                msg: 'test'
              }
            }
          }
        }, {
          timestamp: false
        })
        , instance;

      instance = Model.build({ip: '127.0.0.1', ip2: '0.0.0.0'});

      expect(instance.get('created_time')).to.be.ok;
      expect(instance.get('created_time')).to.be.an.instanceof(Date);

      expect(instance.get('updated_time')).to.be.ok;
      expect(instance.get('updated_time')).to.be.an.instanceof(Date);

      return instance.validate().then(function(err) {
        expect(err).to.be.equal(undefined);
      });
    });

    it('should popuplate explicitely undefined UUID primary keys', function () {
      var Model = current.define('Model', {
        id: {
          type: DataTypes.UUID,
          primaryKey: true,
          allowNull: false,
          defaultValue: DataTypes.UUIDV4
        }
      })
        , instance;

      instance = Model.build({
        id: undefined
      });

      expect(instance.get('id')).not.to.be.undefined;
      expect(instance.get('id')).to.be.ok;
    });
  });
});


'use strict';

var _ = require('lodash');
var util = require('util');

function validateDeprecation (value, expectation, options) {
  if (!options.deprecated) {
    return;
  }

  var valid = value instanceof options.deprecated || Object.prototype.toString.call(value) === Object.prototype.toString.call(options.deprecated.call());

  if (valid) {
    var message = util.format('%s should not be of type "%s"', util.inspect(value), options.deprecated.name);

    console.log('DEPRECATION WARNING:', options.deprecationWarning || message);
  }

  return valid;
}

function validate (value, expectation) {
  // the second part of this check is a workaround to deal with an issue that occurs in node-webkit when
  // using object literals.  https://github.com/sequelize/sequelize/issues/2685
  if (value instanceof expectation || Object.prototype.toString.call(value) === Object.prototype.toString.call(expectation.call())) {
    return true;
  }

  throw new Error(util.format('The parameter (value: %s) is no %s.', value, expectation.name));
}

function check (value, expectation, options) {
  options = _.extend({
    deprecated: false,
    index: null,
    method: null,
    optional: false
  }, options || {});

  if (!value && options.optional) {
    return true;
  }

  if (value === undefined) {
    throw new Error('No value has been passed.');
  }

  if (expectation === undefined) {
    throw new Error('No expectation has been passed.');
  }

  return false
    || validateDeprecation(value, expectation, options)
    || validate(value, expectation, options);
}

module.exports = check;


'use strict';

var _ = require('lodash')
  , Abstract = require('../abstract')
  , ConnectionManager = require('./connection-manager')
  , Query = require('./query')
  , QueryGenerator = require('./query-generator')
  , DataTypes = require('./data-types');

var PostgresDialect = function(sequelize) {
  this.sequelize = sequelize;
  this.connectionManager = new ConnectionManager(this, sequelize);
  this.connectionManager.initPools();

  // parseDialectSpecificFields needs access to the pg lib in order to use its array parser. We cannot simply require pg in query.js since the user can specify another library path (such as pg-native etc)
  Query.prototype.parseDialectSpecificFields.lib = this.connectionManager.lib;

  this.QueryGenerator = _.extend({}, QueryGenerator, {
    options: sequelize.options,
    _dialect: this,
    sequelize: sequelize
  });
};

PostgresDialect.prototype.supports = _.merge(_.cloneDeep(Abstract.prototype.supports), {
  'DEFAULT VALUES': true,
  'EXCEPTION': true,
  'ON DUPLICATE KEY': false,
  'ORDER NULLS': true,
  returnValues: {
    returning: true
  },
  schemas: true,
  lock: true,
  lockOf: true,
  lockKey: true,
  lockOuterJoinFailure: true,
  forShare: 'FOR SHARE',
  index: {
    concurrently: true,
    using: 2,
    where: true
  },
  NUMERIC: true,
  ARRAY: true,
  JSON: true,
  JSONB: true,
  deferrableConstraints: true
});

PostgresDialect.prototype.Query = Query;
PostgresDialect.prototype.DataTypes = DataTypes;
PostgresDialect.prototype.name = 'postgres';
PostgresDialect.prototype.TICK_CHAR = '"';
PostgresDialect.prototype.TICK_CHAR_LEFT = PostgresDialect.prototype.TICK_CHAR;
PostgresDialect.prototype.TICK_CHAR_RIGHT = PostgresDialect.prototype.TICK_CHAR;

module.exports = PostgresDialect;


* `Size.setCSS` is a new method that will set the Size components width and height to the respective CSS style properties of the given element.

* `CSSFile` is a new Loader FileType that allows you to load css into the current document via the normal Phaser Loader, using the `load.css` method. As such, you can chain it with other load calls, load via config, use as part of a pack load or any other option available to all loader filetypes. The CSS is applied immediately to the document.

* `MultiScriptFile` is a new Loader FileType that allows you to load multiple script files into the document via the Phaser Loader, using the new `load.scripts` method. The difference between this and `load.script` is that you must pass an array of script file URLs to this method and they will be loaded in parallel but _processed_ (i.e. added to the document) in the exact order specified in the array. This allows you to load a bundle of scripts that have dependencies on each other.

* `Key.getDuration` is a new method that will return the duration, in ms, that the Key has been held down for. If the Key isn't down it will return zero.

* The `Container.setScrollFactor` method has a new optional argument `updateChildren`. If set, it will change the `scrollFactor` values of all the Container children as well as the Container. Fix #4466 #4475 (thanks @pinkkis @enriqueto)

* Removed all references to CocoonJS from the API, including in the Device.OS object and elsewhere, as Cocoon is no longer.

* The MouseManager and TouchManager now use separate handlers for the Window level input events, which check to see if the canvas is the target or not, and redirect processing accordingly.

keep keep keep keep add keep keep keep keep keep

* There is a new webpack config `FEATURE_SOUND` which is set to `true` by default, but if set to `false` it will exclude the Sound Manager and all of its systems into the build files. Fix #4428 (thanks @goldfire)

'use strict';

const webpack = require('webpack');
const exec = require('child_process').exec;

module.exports = {
    mode: 'development',

    context: `${__dirname}/src/`,

    entry: {
        phaser: './phaser.js'
    },

    output: {
        path: `${__dirname}/build/`,
        filename: 'phaser-facebook-instant-games.js',
        library: 'Phaser',
        libraryTarget: 'umd',
        sourceMapFilename: '[file].map',
        devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // string
        devtoolFallbackModuleFilenameTemplate: 'webpack:///[resource-path]?[hash]', // string
        umdNamedDefine: true
    },

    performance: { hints: false },

    plugins: [
        new webpack.DefinePlugin({
            "typeof CANVAS_RENDERER": JSON.stringify(true),
            "typeof WEBGL_RENDERER": JSON.stringify(true),
            "typeof EXPERIMENTAL": JSON.stringify(false),
            "typeof PLUGIN_CAMERA3D": JSON.stringify(false),
            "typeof PLUGIN_FBINSTANT": JSON.stringify(true)
        }),
        {
            apply: (compiler) => {
                compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
                    exec('node scripts/copy-to-examples-fb.js', (err, stdout, stderr) => {
                        if (stdout) process.stdout.write(stdout);
                        if (stderr) process.stderr.write(stderr);
                    });
                });
            }
        }
    ],

    devtool: 'source-map'
};


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

/**
 * The Scene Systems Shutdown Event.
 *
 * This event is dispatched by a Scene during the Scene Systems shutdown process.
 *
 * Listen to it from a Scene using `this.scene.events.on('shutdown', listener)`.
 *
 * You should free-up any resources that may be in use by your Scene in this event handler, on the understanding
 * that the Scene may, at any time, become active again. A shutdown Scene is not 'destroyed', it's simply not
 * currently active. Use the [DESTROY]{@linkcode Phaser.Scenes.Events#event:DESTROY} event to completely clear resources.
 *
 * @event Phaser.Scenes.Events#SHUTDOWN
 * @since 3.0.0
 *
 * @param {Phaser.Scenes.Systems} sys - A reference to the Scene Systems class of the Scene that emitted this event.
 * @param {any} [data] - An optional data object that was passed to this Scene when it was shutdown.
 */
module.exports = 'shutdown';


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

var PropertyValueInc = require('./PropertyValueInc');

/**
 * Takes an array of Game Objects, or any objects that have a public `x` property,
 * and then adds the given value to each of their `x` properties.
 *
 * The optional `step` property is applied incrementally, multiplied by each item in the array.
 *
 * To use this with a Group: `IncX(group.getChildren(), value, step)`
 *
 * @function Phaser.Actions.IncX
 * @since 3.0.0
 *
 * @generic {Phaser.GameObjects.GameObject[]} G - [items,$return]
 *
 * @param {(array|Phaser.GameObjects.GameObject[])} items - The array of items to be updated by this action.
 * @param {number} value - The amount to be added to the `x` property.
 * @param {number} [step=0] - This is added to the `value` amount, multiplied by the iteration counter.
 * @param {integer} [index=0] - An optional offset to start searching from within the items array.
 * @param {integer} [direction=1] - The direction to iterate through the array. 1 is from beginning to end, -1 from end to beginning.
 *
 * @return {(array|Phaser.GameObjects.GameObject[])} The array of objects that were passed to this Action.
 */
var IncX = function (items, value, step, index, direction)
{
    return PropertyValueInc(items, 'x', value, step, index, direction);
};

module.exports = IncX;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

/**
 * Elastic ease-in.
 *
 * @function Phaser.Math.Easing.Elastic.In
 * @since 3.0.0
 *
 * @param {number} v - The value to be tweened.
 * @param {number} [amplitude=0.1] - The amplitude of the elastic ease.
 * @param {number} [period=0.1] - Sets how tight the sine-wave is, where smaller values are tighter waves, which result in more cycles.
 *
 * @return {number} The tweened value.
 */
var In = function (v, amplitude, period)
{
    if (amplitude === undefined) { amplitude = 0.1; }
    if (period === undefined) { period = 0.1; }

    if (v === 0)
    {
        return 0;
    }
    else if (v === 1)
    {
        return 1;
    }
    else
    {
        var s = period / 4;

        if (amplitude < 1)
        {
            amplitude = 1;
        }
        else
        {
            s = period * Math.asin(1 / amplitude) / (2 * Math.PI);
        }

        return -(amplitude * Math.pow(2, 10 * (v -= 1)) * Math.sin((v - s) * (2 * Math.PI) / period));
    }
};

module.exports = In;


var PluginManager = require('../plugins/PluginManager');

var ScaleManager = require('../scale/ScaleManager');

var SceneManager = require('../scene/SceneManager');

var SoundManagerCreator = require('../sound/SoundManagerCreator');

var TextureEvents = require('../textures/events');

var TextureManager = require('../textures/TextureManager');

var VisibilityHandler = require('./VisibilityHandler');

keep keep keep replace keep keep keep keep

/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

require('./polyfills');

var CONST = require('./const');
var Extend = require('./utils/object/Extend');

/**
 * @namespace Phaser
 */

var Phaser = {

    Actions: require('./actions'),
    Animations: require('./animations'),
    Cache: require('./cache'),
    Cameras: require('./cameras'),
    Core: require('./core'),
    Class: require('./utils/Class'),
    Create: require('./create'),
    Curves: require('./curves'),
    Data: require('./data'),
    Display: require('./display'),
    DOM: require('./dom'),
    Events: require('./events'),
    Game: require('./core/Game'),
    GameObjects: require('./gameobjects'),
    Geom: require('./geom'),
    Input: require('./input'),
    Loader: require('./loader'),
    Math: require('./math'),
    Physics: require('./physics'),
    Plugins: require('./plugins'),
    Renderer: require('./renderer'),
    Scale: require('./scale'),
    Scene: require('./scene/Scene'),
    Scenes: require('./scene'),
    Sound: require('./sound'),
    Structs: require('./structs'),
    Textures: require('./textures'),
    Tilemaps: require('./tilemaps'),
    Time: require('./time'),
    Tweens: require('./tweens'),
    Utils: require('./utils')

};

//  Merge in the optional plugins

if (typeof PLUGIN_CAMERA3D)
{
    Phaser.Cameras.Sprite3D = require('../plugins/camera3d/src');
    Phaser.GameObjects.Sprite3D = require('../plugins/camera3d/src/sprite3d/Sprite3D');
    Phaser.GameObjects.Factories.Sprite3D = require('../plugins/camera3d/src/sprite3d/Sprite3DFactory');
    Phaser.GameObjects.Creators.Sprite3D = require('../plugins/camera3d/src/sprite3d/Sprite3DCreator');
}

if (typeof PLUGIN_FBINSTANT)
{
    Phaser.FacebookInstantGamesPlugin = require('../plugins/fbinstant/src/FacebookInstantGamesPlugin');
}

//   Merge in the consts

Phaser = Extend(false, Phaser, CONST);

//  Export it

module.exports = Phaser;

global.Phaser = Phaser;

/*
 * "Documentation is like pizza: when it is good, it is very, very good;
 * and when it is bad, it is better than nothing."
 *  -- Dick Brandon
 */


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

var StarRender = require('./StarRender');
var Class = require('../../../utils/Class');
var Earcut = require('../../../geom/polygon/Earcut');
var Shape = require('../Shape');

/**
 * @classdesc
 * The Star Shape is a Game Object that can be added to a Scene, Group or Container. You can
 * treat it like any other Game Object in your game, such as tweening it, scaling it, or enabling
 * it for input or physics. It provides a quick and easy way for you to render this shape in your
 * game without using a texture, while still taking advantage of being fully batched in WebGL.
 *
 * This shape supports both fill and stroke colors.
 *
 * As the name implies, the Star shape will display a star in your game. You can control several
 * aspects of it including the number of points that constitute the star. The default is 5. If
 * you change it to 4 it will render as a diamond. If you increase them, you'll get a more spiky
 * star shape.
 *
 * You can also control the inner and outer radius, which is how 'long' each point of the star is.
 * Modify these values to create more interesting shapes.
 *
 * @class Star
 * @extends Phaser.GameObjects.Shape
 * @memberof Phaser.GameObjects
 * @constructor
 * @since 3.13.0
 *
 * @param {Phaser.Scene} scene - The Scene to which this Game Object belongs. A Game Object can only belong to one Scene at a time.
 * @param {number} [x=0] - The horizontal position of this Game Object in the world.
 * @param {number} [y=0] - The vertical position of this Game Object in the world.
 * @param {number} [points=5] - The number of points on the star.
 * @param {number} [innerRadius=32] - The inner radius of the star.
 * @param {number} [outerRadius=64] - The outer radius of the star.
 * @param {number} [fillColor] - The color the star will be filled with, i.e. 0xff0000 for red.
 * @param {number} [fillAlpha] - The alpha the star will be filled with. You can also set the alpha of the overall Shape using its `alpha` property.
 */
var Star = new Class({

    Extends: Shape,

    Mixins: [
        StarRender
    ],

    initialize:

    function Star (scene, x, y, points, innerRadius, outerRadius, fillColor, fillAlpha)
    {
        if (x === undefined) { x = 0; }
        if (y === undefined) { y = 0; }
        if (points === undefined) { points = 5; }
        if (innerRadius === undefined) { innerRadius = 32; }
        if (outerRadius === undefined) { outerRadius = 64; }

        Shape.call(this, scene, 'Star', null);

        /**
         * Private internal value.
         * The number of points in the star.
         *
         * @name Phaser.GameObjects.Star#_points
         * @type {integer}
         * @private
         * @since 3.13.0
         */
        this._points = points;

        /**
         * Private internal value.
         * The inner radius of the star.
         *
         * @name Phaser.GameObjects.Star#_innerRadius
         * @type {number}
         * @private
         * @since 3.13.0
         */
        this._innerRadius = innerRadius;

        /**
         * Private internal value.
         * The outer radius of the star.
         *
         * @name Phaser.GameObjects.Star#_outerRadius
         * @type {number}
         * @private
         * @since 3.13.0
         */
        this._outerRadius = outerRadius;

        this.setPosition(x, y);
        this.setSize(outerRadius * 2, outerRadius * 2);

        if (fillColor !== undefined)
        {
            this.setFillStyle(fillColor, fillAlpha);
        }

        this.updateDisplayOrigin();
        this.updateData();
    },

    /**
     * Sets the number of points that make up the Star shape.
     * This call can be chained.
     *
     * @method Phaser.GameObjects.Star#setPoints
     * @since 3.13.0
     *
     * @param {integer} value - The amount of points the Star will have.
     *
     * @return {this} This Game Object instance.
     */
    setPoints: function (value)
    {
        this._points = value;

        return this.updateData();
    },

    /**
     * Sets the inner radius of the Star shape.
     * This call can be chained.
     *
     * @method Phaser.GameObjects.Star#setInnerRadius
     * @since 3.13.0
     *
     * @param {number} value - The amount to set the inner radius to.
     *
     * @return {this} This Game Object instance.
     */
    setInnerRadius: function (value)
    {
        this._innerRadius = value;

        return this.updateData();
    },

    /**
     * Sets the outer radius of the Star shape.
     * This call can be chained.
     *
     * @method Phaser.GameObjects.Star#setOuterRadius
     * @since 3.13.0
     *
     * @param {number} value - The amount to set the outer radius to.
     *
     * @return {this} This Game Object instance.
     */
    setOuterRadius: function (value)
    {
        this._outerRadius = value;

        return this.updateData();
    },

    /**
     * The number of points that make up the Star shape.
     *
     * @name Phaser.GameObjects.Star#points
     * @type {integer}
     * @default 5
     * @since 3.13.0
     */
    points: {

        get: function ()
        {
            return this._points;
        },

        set: function (value)
        {
            this._points = value;

            this.updateData();
        }

    },

    /**
     * The inner radius of the Star shape.
     *
     * @name Phaser.GameObjects.Star#innerRadius
     * @type {number}
     * @default 32
     * @since 3.13.0
     */
    innerRadius: {

        get: function ()
        {
            return this._innerRadius;
        },

        set: function (value)
        {
            this._innerRadius = value;

            this.updateData();
        }

    },

    /**
     * The outer radius of the Star shape.
     *
     * @name Phaser.GameObjects.Star#outerRadius
     * @type {number}
     * @default 64
     * @since 3.13.0
     */
    outerRadius: {

        get: function ()
        {
            return this._outerRadius;
        },

        set: function (value)
        {
            this._outerRadius = value;

            this.updateData();
        }

    },

    /**
     * Internal method that updates the data and path values.
     *
     * @method Phaser.GameObjects.Star#updateData
     * @private
     * @since 3.13.0
     *
     * @return {this} This Game Object instance.
     */
    updateData: function ()
    {
        var path = [];

        var points = this._points;
        var innerRadius = this._innerRadius;
        var outerRadius = this._outerRadius;

        var rot = Math.PI / 2 * 3;
        var step = Math.PI / points;

        //  So origin 0.5 = the center of the star
        var x = outerRadius;
        var y = outerRadius;

        path.push(x, y + -outerRadius);

        for (var i = 0; i < points; i++)
        {
            path.push(x + Math.cos(rot) * outerRadius, y + Math.sin(rot) * outerRadius);

            rot += step;

            path.push(x + Math.cos(rot) * innerRadius, y + Math.sin(rot) * innerRadius);

            rot += step;
        }

        path.push(x, y + -outerRadius);

        this.pathIndexes = Earcut(path);
        this.pathData = path;

        return this;
    }

});

module.exports = Star;


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

/**
 * The Sprite Animation Key Update Event.
 *
 * This event is dispatched by a Sprite when a specific animation playing on it updates. This happens when the animation changes frame,
 * based on the animation frame rate and other factors like `timeScale` and `delay`.
 *
 * Listen for it on the Sprite using `sprite.on('animationupdate-key', listener)` where `key` is the key of
 * the animation. For example, if you had an animation with the key 'explode' you should listen for `animationupdate-explode`.
 *
 * @event Phaser.Animations.Events#SPRITE_ANIMATION_KEY_UPDATE
 * @since 3.16.1
 *
 * @param {Phaser.Animations.Animation} animation - A reference to the Animation that has updated on the Sprite.
 * @param {Phaser.Animations.AnimationFrame} frame - The current Animation Frame of the Animation.
 * @param {Phaser.GameObjects.Sprite} gameObject - A reference to the Game Object on which the animation updated.
 */
module.exports = 'animationupdate-';


/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2019 Photon Storm Ltd.
 * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
 */

var CollisionInfo = require('./CollisionInfo');
var CONST = require('./const');

/**
 * Takes a CollisionInfo object and tests to see if the two bodies are still intersecting / touching.
 *
 * @function Phaser.Physics.Arcade.CheckOverlap
 * @since 3.17.0
 *
 * @param {Phaser.Physics.Arcade.Body} body1 - The first Body to separate.
 *
 * @return {boolean}
 */
var CheckOverlap = function (collisionInfo)
{
    collisionInfo = CollisionInfo.update(collisionInfo);

    var face = collisionInfo.face;
    var body1 = collisionInfo.body1;
    var body2 = collisionInfo.body2;

    // console.log('');
    // console.log('%c CheckOverlap ' + body1.world._frame + '                                                                                ', 'background-color: pink');
    // collisionInfo.dump();

    switch (face)
    {
        case CONST.FACING_LEFT:

            body1.setTouchingLeft();
            body2.setTouchingRight();

            body1.setBlockedLeft();
            body2.setBlockedRight();

            if (body1.isWorldBlockedRight())
            {
                body2.setHardBlockedRight();
            }

            if (body2.isWorldBlockedLeft())
            {
                body1.setHardBlockedLeft();
            }

            break;

        case CONST.FACING_RIGHT:

            body1.setTouchingRight();
            body2.setTouchingLeft();

            body1.setBlockedRight();
            body2.setBlockedLeft();

            if (body1.isWorldBlockedLeft())
            {
                body2.setHardBlockedLeft();
            }

            if (body2.isWorldBlockedRight())
            {
                body1.setHardBlockedRight();
            }

            break;

        case CONST.FACING_UP:

            body1.setTouchingUp();
            body2.setTouchingDown();

            body1.setBlockedUp();
            body2.setBlockedDown();

            if (body1.isWorldBlockedDown())
            {
                body2.setHardBlockedDown();
            }

            if (body2.isWorldBlockedUp())
            {
                body1.setHardBlockedUp();
            }

            break;

        case CONST.FACING_DOWN:

            body1.setTouchingDown();
            body2.setTouchingUp();

            body1.setBlockedDown();
            body2.setBlockedUp();

            if (body1.isWorldBlockedUp())
            {
                body2.setHardBlockedUp();
            }

            if (body2.isWorldBlockedDown())
            {
                body1.setHardBlockedDown();
            }

            break;
    }

    return collisionInfo.touching;
};

module.exports = CheckOverlap;