Function.prototype.$asyncbind = function $asyncbind(self, catcher) {
  "use strict";

  if (!Function.prototype.$asyncbind) {
    Object.defineProperty(Function.prototype, "$asyncbind", {
      value: $asyncbind,
      enumerable: false,
      configurable: true,
      writable: true
    });
  }

  if (!$asyncbind.trampoline) {
    $asyncbind.trampoline = function trampoline(t, x, s, e, u) {
      return function b(q) {
        while (q) {
          if (q.then) {
            q = q.then(b, e);
            return u ? undefined : q;
          }

          try {
            if (q.pop) {
              if (q.length) return q.pop() ? x.call(t) : q;
              q = s;
            } else q = q.call(t);
          } catch (r) {
            return e(r);
          }
        }
      };
    };
  }

  if (!$asyncbind.LazyThenable) {
    $asyncbind.LazyThenable = function () {
      function isThenable(obj) {
        return obj && obj instanceof Object && typeof obj.then === "function";
      }

      function resolution(p, r, how) {
        try {
          var x = how ? how(r) : r;
          if (p === x) return p.reject(new TypeError("Promise resolution loop"));

          if (isThenable(x)) {
            x.then(function (y) {
              resolution(p, y);
            }, function (e) {
              p.reject(e);
            });
          } else {
            p.resolve(x);
          }
        } catch (ex) {
          p.reject(ex);
        }
      }

      function Chained() {}

      ;
      Chained.prototype = {
        resolve: _unchained,
        reject: _unchained,
        then: thenChain
      };

      function _unchained(v) {}

      function thenChain(res, rej) {
        this.resolve = res;
        this.reject = rej;
      }

      function then(res, rej) {
        var chain = new Chained();

        try {
          this._resolver(function (value) {
            return isThenable(value) ? value.then(res, rej) : resolution(chain, value, res);
          }, function (ex) {
            resolution(chain, ex, rej);
          });
        } catch (ex) {
          resolution(chain, ex, rej);
        }

        return chain;
      }

      function Thenable(resolver) {
        this._resolver = resolver;
        this.then = then;
      }

      ;

      Thenable.resolve = function (v) {
        return Thenable.isThenable(v) ? v : {
          then: function then(resolve) {
            return resolve(v);
          }
        };
      };

      Thenable.isThenable = isThenable;
      return Thenable;
    }();

    $asyncbind.EagerThenable = $asyncbind.Thenable = ($asyncbind.EagerThenableFactory = function (tick) {
      tick = tick || typeof process === "object" && process.nextTick || typeof setImmediate === "function" && setImmediate || function (f) {
        setTimeout(f, 0);
      };

      var soon = function () {
        var fq = [],
            fqStart = 0,
            bufferSize = 1024;

        function callQueue() {
          while (fq.length - fqStart) {
            try {
              fq[fqStart]();
            } catch (ex) {}

            fq[fqStart++] = undefined;

            if (fqStart === bufferSize) {
              fq.splice(0, bufferSize);
              fqStart = 0;
            }
          }
        }

        return function (fn) {
          fq.push(fn);
          if (fq.length - fqStart === 1) tick(callQueue);
        };
      }();

      function Zousan(func) {
        if (func) {
          var me = this;
          func(function (arg) {
            me.resolve(arg);
          }, function (arg) {
            me.reject(arg);
          });
        }
      }

      Zousan.prototype = {
        resolve: function resolve(value) {
          if (this.state !== undefined) return;
          if (value === this) return this.reject(new TypeError("Attempt to resolve promise with self"));
          var me = this;

          if (value && (typeof value === "function" || typeof value === "object")) {
            try {
              var first = 0;
              var then = value.then;

              if (typeof then === "function") {
                then.call(value, function (ra) {
                  if (!first++) {
                    me.resolve(ra);
                  }
                }, function (rr) {
                  if (!first++) {
                    me.reject(rr);
                  }
                });
                return;
              }
            } catch (e) {
              if (!first) this.reject(e);
              return;
            }
          }

          this.state = STATE_FULFILLED;
          this.v = value;
          if (me.c) soon(function () {
            for (var n = 0, l = me.c.length; n < l; n++) STATE_FULFILLED(me.c[n], value);
          });
        },
        reject: function reject(reason) {
          if (this.state !== undefined) return;
          this.state = STATE_REJECTED;
          this.v = reason;
          var clients = this.c;
          if (clients) soon(function () {
            for (var n = 0, l = clients.length; n < l; n++) STATE_REJECTED(clients[n], reason);
          });
        },
        then: function then(onF, onR) {
          var p = new Zousan();
          var client = {
            y: onF,
            n: onR,
            p: p
          };

          if (this.state === undefined) {
            if (this.c) this.c.push(client);else this.c = [client];
          } else {
            var s = this.state,
                a = this.v;
            soon(function () {
              s(client, a);
            });
          }

          return p;
        }
      };

      function STATE_FULFILLED(c, arg) {
        if (typeof c.y === "function") {
          try {
            var yret = c.y.call(undefined, arg);
            c.p.resolve(yret);
          } catch (err) {
            c.p.reject(err);
          }
        } else c.p.resolve(arg);
      }

      function STATE_REJECTED(c, reason) {
        if (typeof c.n === "function") {
          try {
            var yret = c.n.call(undefined, reason);
            c.p.resolve(yret);
          } catch (err) {
            c.p.reject(err);
          }
        } else c.p.reject(reason);
      }

      Zousan.resolve = function (val) {
        if (val && val instanceof Zousan) return val;
        var z = new Zousan();
        z.resolve(val);
        return z;
      };

      Zousan.reject = function (err) {
        if (err && err instanceof Zousan) return err;
        var z = new Zousan();
        z.reject(err);
        return z;
      };

      Zousan.version = "2.3.3-nodent";
      return Zousan;
    })();
  }

  var resolver = this;

  switch (catcher) {
    case true:
      return new $asyncbind.Thenable(boundThen);

    case 0:
      return new $asyncbind.LazyThenable(boundThen);

    case undefined:
      boundThen.then = boundThen;
      return boundThen;

    default:
      return function () {
        try {
          return resolver.apply(self, arguments);
        } catch (ex) {
          return catcher(ex);
        }
      };
  }

  function boundThen() {
    return resolver.apply(self, arguments);
  }
};

const path = require("path");

const eject = require("@patternplate/client/eject");

const render = require("@patternplate/client/render");

const compiler = require("@patternplate/compiler");

const loadConfig = require("@patternplate/load-config");

const _require = require("@patternplate/load-docs"),
      loadDocsTree = _require.loadDocsTree;

const loadMeta = require("@patternplate/load-meta");

const ora = require("ora");

const sander = require("@marionebl/sander");

const fromString = require("require-from-string");

const unindent = require("unindent");

const stringHash = require("string-hash");

module.exports = build;
const BUNDLE_PATH = "/patternplate.node.components.js";
const RENDER_PATH = "/patternplate.node.render.js"; // TODO: provide a lib version of this that
// writes to a virtual fs / union fs

function build({
  flags
}) {
  return new Promise(function ($return, $error) {
    var cwd, out, rel, base, spinner, _ref, config, filepath, _config$entry, entry, docs, _ref2, patterns, errors, tree, schema, state, home, pool, bundleFs, getModule, renderComponent, bundles;

    cwd = flags.cwd || process.cwd();
    out = path.join(cwd, flags.out || "docs/patterns");
    rel = path.relative(cwd, out);
    base = flags.base === "/" ? flags.base : `/${typeof flags.base === "undefined" ? path.basename(out) : "/"}`;
    spinner = ora(`Building to "${rel}"`).start();
    return loadConfig({
      cwd
    }).then(function ($await_1) {
      _ref = $await_1, config = _ref.config, filepath = _ref.filepath;
      _config$entry = config.entry, entry = _config$entry === void 0 ? [] : _config$entry;
      return loadDocsTree({
        cwd,
        docs: config.docs,
        readme: config.readme
      }).then(function ($await_2) {
        docs = $await_2;
        return loadMeta({
          cwd,
          entry
        }).then(function ($await_3) {
          _ref2 = $await_3, patterns = _ref2.patterns, errors = _ref2.errors;
          tree = {
            id: "root",
            children: patterns
          };

          if (errors && errors.length > 0) {
            return $error(new Error(errors.map(error => error.message).join("\n")));
          }

          schema = {
            docs,
            meta: tree
          };
          state = {
            base,
            config,
            schema,
            isStatic: true
          };
          return sander.writeFile(out, 'api/state.json', JSON.stringify(schema)).then(function ($await_4) {
            return render(base, state).then(function ($await_5) {
              home = $await_5;
              return sander.writeFile(out, 'index.html', home).then(function ($await_6) {
                pool = [...flatten(docs.children), ...flatten(patterns)];
                return Promise.all(pool.map(item => new Promise(function ($return, $error) {
                  var full, html, target;
                  full = `${base}/${item.contentType}/${item.id}`;
                  return render(full, state).then(function ($await_7) {
                    html = $await_7;
                    target = path.join(out, item.contentType, item.id, 'index.html');
                    return sander.writeFile(target, html).then(function ($await_8) {
                      return $return();
                    }.$asyncbind(this, $error), $error);
                  }.$asyncbind(this, $error), $error);
                }.$asyncbind(this)))).then(function ($await_9) {
                  return eject().then(function ($await_10) {
                    return dump($await_10, "/static", out).then(function ($await_11) {
                      return bundle({
                        cwd,
                        target: "web"
                      }).then(function ($await_12) {
                        return dump($await_12, "/", path.join(out, 'api')).then(function ($await_13) {
                          return bundle({
                            cwd,
                            target: "node"
                          }).then(function ($await_14) {
                            bundleFs = $await_14;
                            getModule = fromFs(bundleFs);
                            renderComponent = getModule(RENDER_PATH);
                            bundles = getModule(BUNDLE_PATH);
                            return Promise.all(patterns.map(pattern => new Promise(function ($return, $error) {
                              var component, result;
                              component = getComponent(bundles, pattern);
                              result = renderComponent(component);
                              return sander.writeFile(out, 'api/demo', `${pattern.id}.html`, demo(result, pattern)).then(function ($await_15) {
                                return $return();
                              }.$asyncbind(this, $error), $error);
                            }.$asyncbind(this)))).then(function ($await_16) {
                              spinner.succeed(`Built to "${rel}"`);
                              return $return();
                            }.$asyncbind(this, $error), $error);
                          }.$asyncbind(this, $error), $error);
                        }.$asyncbind(this, $error), $error);
                      }.$asyncbind(this, $error), $error);
                    }.$asyncbind(this, $error), $error);
                  }.$asyncbind(this, $error), $error);
                }.$asyncbind(this, $error), $error);
              }.$asyncbind(this, $error), $error);
            }.$asyncbind(this, $error), $error);
          }.$asyncbind(this, $error), $error);
        }.$asyncbind(this, $error), $error);
      }.$asyncbind(this, $error), $error);
    }.$asyncbind(this, $error), $error);
  }.$asyncbind(this));
}

function bundle({
  cwd,
  target
}) {
  return compiler({
    cwd,
    target
  }).then(c => new Promise((resolve, reject) => {
    c.run((err, stats) => {
      if (err) {
        return reject(err);
      }

      if (stats.compilation.errors && stats.compilation.errors.length > 0) {
        stats.compilation.errors.forEach(error => {
          console.error(error);
        });
        return reject(stats.compilation.errors);
      }

      resolve(c.outputFileSystem);
    });
  }));
} // TODO: Duplicate of function in @patternplate/api/demo.js,
// move to own package


function demo(content, payload) {
  const data = encodeURIComponent(JSON.stringify(payload));
  return unindent(`
    <!doctype html>
    <html lang="en">
      <head>
        <!-- content.head -->
        ${content.head || ""}
        <!-- content.css -->
        ${content.css || ""}
      </head>
      <body>
        <textarea style="display: none;" data-patternplate-vault="data-patternplate-vault">${data}</textarea>
        <!-- content.before -->
        ${content.before || ""}
        <!-- content.html -->
        <div data-patternplate-mount="data-patternplate-mount">${content.html || ""}</div>
        <!-- content.after -->
        ${content.after || ""}
        <!-- ../ -> /api/ -->
        <script src="../patternplate.web.vendors.js"></script>
        <script src="../patternplate.web.components.js"></script>
        <script src="../patternplate.web.probe.js"></script>
        <script src="../patternplate.web.mount.js"></script>
        <script src="../patternplate.web.demo.js"></script>
      </body>
    </html>
  `);
}

function dump(fs, base, target) {
  return new Promise(function ($return, $error) {
    const files = list(fs, base);
    return $return(Promise.all(files.map(file => new Promise(function ($return, $error) {
      sander.writeFile(target, file.slice(1), fs.readFileSync(file));
      return $return();
    }.$asyncbind(this)))));
  }.$asyncbind(this));
}

function list(fs, base) {
  return fs.readdirSync(base).reduce((acc, name) => {
    const p = path.join(base, name);
    const stat = fs.statSync(p);

    if (stat.isFile()) {
      acc.push(p);
    } else {
      acc = acc.concat(list(fs, p));
    }

    return acc;
  }, []);
} // TODO: Duplicate of function in @patternplate/api/demo.js,
// move to own package


function getComponent(components, data) {
  const top = components[data.artifact];

  if (top[data.source]) {
    return top[data.source];
  }

  return top;
} // TODO: Duplicate of function in @patternplate/api/demo.js,
// move to own package


function fromFs(fs) {
  return filename => {
    const componentBundleSource = String(fs.readFileSync(filename));
    return getExports(componentBundleSource, filename);
  };
} // TODO: Duplicate of function in @patternplate/api/demo.js,
// move to own package


const exportsCache = new Map();

function getExports(source, {
  filename
}) {
  const hash = stringHash(source);

  if (!exportsCache.has(hash)) {
    exportsCache.set(hash, fromString(source, filename));
  }

  return exportsCache.get(hash);
} // TODO: Duplicate from @patternplate/client/selectors/pool


function flatten(tree, initial = []) {
  return tree.reduce((acc, item) => {
    acc.push(item);

    if (Array.isArray(item.children)) {
      flatten(item.children, acc);
    }

    return acc;
  }, initial);
}
//# sourceMappingURL=index.js.map