text: import process from 'process'
  import { once } from 'events'
  import assert from 'webassert'
  import chokidar from 'chokidar'
  import { basename, relative } from 'path'
  import makeArray from 'make-array'
  import ignore from 'ignore'
  import cpx from 'cpx2'
  
  import { getCopyGlob } from './lib/build-static/index.js'
  import { build, watchBuild } from './lib/builder.js'
  
  export class Siteup {
    constructor (src, dest, cwd = process.cwd(), opts = {}) {
      assert(src, 'src is a required argument')
      assert(dest, 'dest is a required argument')
  
      const defaultIgnore = ['.*', 'node_modules', basename(dest)]
  
      opts.ignore = defaultIgnore.concat(makeArray(opts.ignore))
  
      this._src = src
      this._dest = dest
      this._cwd = cwd
  
      this.opts = opts
  
      this._watcher = null
      this._cpxWatcher = null
      this._building = false
    }
  
    get watching () {
      return Boolean(this._watcher)
    }
  
    build () {
      return build(this._src, this._dest, this.opts)
    }
  
    async watch () {
      // TODO: expose events and stuff to the caller instead.
      if (this.watching) throw new Error('Already watching.')
  
      let report
  
      try {
        report = await watchBuild(this._src, this._dest, this.opts)
        console.log('Initial JS, CSS and Page Build Complete')
      } catch (err) {
        console.error(err)
        if (err.report) report = err.report
      }
  
      this._cpxWatcher = cpx.watch(getCopyGlob(this._src), this._dest, { ignore: this.opts.ignore })
  
      this._cpxWatcher.on('copy', (e) => {
        console.log(`Copy ${e.srcPath} to ${e.dstPath}`)
      })
  
      this._cpxWatcher.on('remove', (e) => {
        console.log(`Remove ${e.path}`)
      })
  
      this._cpxWatcher.on('watch-ready', () => {
        console.log('Copy watcher ready')
      })
  
      this._cpxWatcher.on('watch-error', (err) => {
        console.log(`Copy error: ${err.message}`)
      })
  
      const ig = ignore().add(this.opts.ignore)
  
      const anymatch = name => ig.ignores(relname(this._src, name))
  
      const watcher = chokidar.watch(`${this._src}/**/*.+(js|css|html|md)`, {
        ignored: anymatch,
        persistent: true
      })
  
      this._watcher = watcher
  
      await once(watcher, 'ready')
  
      watcher.on('add', path => {
        console.log(`File ${path} has been added`)
        watchBuild(this._src, this._dest, this.opts).then(() => console.log('Site Rebuilt')).catch(console.error)
      })
      watcher.on('change', path => {
        console.log(`File ${path} has been changed`)
        watchBuild(this._src, this._dest, this.opts).then(() => console.log('Site Rebuilt')).catch(console.error)
      })
      watcher.on('unlink', path => {
        console.log(`File ${path} has been removed`)
        watchBuild(this._src, this._dest, this.opts).then(() => console.log('Site Rebuilt')).catch(console.error)
      })
      watcher.on('error', console.error)
  
      return report
    }
  
    async stopWatching () {
      if (!this.watching || !this._cpxWatcher) throw new Error('Not watching')
      await this._watcher.close()
      this._cpxWatcher.close()
      this._watcher = null
      this._cpxWatcher = null
    }
  }
  
  function relname (root, name) {
    return root === name ? basename(name) : relative(root, name)
  }
  