mirror of
https://github.com/documentationjs/documentation.git
synced 2026-01-18 14:17:30 +00:00
* style(prettier): Use prettier for code formatting This saves us style issues. Also adds husky and lint-staged for pre-commit testing Refs https://github.com/documentationjs/documentation/issues/709
141 lines
3.5 KiB
JavaScript
141 lines
3.5 KiB
JavaScript
/* @flow */
|
|
|
|
// This file triggers https://github.com/prettier/prettier/issues/1151
|
|
|
|
'use strict';
|
|
var http = require('http'),
|
|
mime = require('mime'),
|
|
pify = require('pify'),
|
|
EventEmitter = require('events').EventEmitter,
|
|
liveReload = require('tiny-lr'),
|
|
sep = require('path').sep;
|
|
|
|
/* ::
|
|
declare type ServerFile = {
|
|
relative: string,
|
|
contents: string
|
|
};
|
|
*/
|
|
|
|
/**
|
|
* A static file server designed to support documentation.js's --serve
|
|
* option. It serves from an array of Vinyl File objects (virtual files in
|
|
* memory) and exposes a `setFiles` method that both replaces the set
|
|
* of files and notifies any browsers using LiveReload to reload
|
|
* and display the new content.
|
|
* @class
|
|
* @param port server port to serve on.
|
|
*/
|
|
class Server extends EventEmitter {
|
|
/* :: _lr: Object; */
|
|
/* :: _port: number; */
|
|
/* :: _files: Array<ServerFile>; */
|
|
/* :: _http: http.Server; */
|
|
|
|
constructor(port /*: number*/) {
|
|
super();
|
|
if (typeof port !== 'number') {
|
|
throw new Error('port argument required to initialize a server');
|
|
}
|
|
this._port = port;
|
|
this._files = [];
|
|
}
|
|
|
|
/**
|
|
* Update the set of files exposed by this server and notify LiveReload
|
|
* clients
|
|
*
|
|
* @param files new content. replaces any previously-set content.
|
|
* @returns {Server} self
|
|
*/
|
|
setFiles(files /*: Array<ServerFile> */) {
|
|
this._files = files;
|
|
if (this._lr) {
|
|
this._lr.changed({ body: { files: '*' } });
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Internal handler for server requests. The server serves
|
|
* very few types of things: html, images, and so on, and it
|
|
* only handles GET requests.
|
|
*
|
|
* @param {http.Request} request content wanted
|
|
* @param {http.Response} response content returned
|
|
* @returns {undefined} nothing
|
|
* @private
|
|
*/
|
|
handler(
|
|
request /*: http.IncomingMessage */,
|
|
response /*: http.ServerResponse */
|
|
) {
|
|
var path = request.url.substring(1);
|
|
if (path === '') {
|
|
path = 'index.html';
|
|
}
|
|
|
|
for (var i = 0; i < this._files.length; i++) {
|
|
var file = this._files[i];
|
|
var filePath = file.relative.split(sep).join('/');
|
|
if (filePath === path) {
|
|
response.writeHead(200, { 'Content-Type': mime.lookup(path) });
|
|
response.end(file.contents);
|
|
return;
|
|
}
|
|
}
|
|
response.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
response.end('Not found');
|
|
}
|
|
|
|
// prettier-ignore
|
|
start()/*: Promise<boolean> */ {
|
|
/*
|
|
* Boot up the server's HTTP & LiveReload endpoints. This method
|
|
* can be called multiple times.
|
|
*
|
|
* @returns {Promise} resolved when server starts
|
|
*/
|
|
return new Promise(resolve => {
|
|
// idempotent
|
|
if (this._lr) {
|
|
return resolve(true);
|
|
}
|
|
|
|
this._lr = liveReload();
|
|
this._http = http.createServer(this.handler.bind(this));
|
|
|
|
return Promise.all([
|
|
pify(this._lr.listen.bind(this._lr))(35729),
|
|
pify(this._http.listen.bind(this._http))(this._port)
|
|
]).then(() => {
|
|
this.emit('listening');
|
|
return resolve(true);
|
|
});
|
|
});
|
|
}
|
|
|
|
// prettier-ignore
|
|
stop()/*: Promise<boolean> */ {
|
|
/*
|
|
* Shut down the server's HTTP & LiveReload endpoints. This method
|
|
* can be called multiple times.
|
|
*/
|
|
return new Promise(resolve => {
|
|
// idempotent
|
|
if (!this._lr) {
|
|
return resolve(true);
|
|
}
|
|
|
|
this._http.close(() => {
|
|
this._lr.close();
|
|
delete this._http;
|
|
delete this._lr;
|
|
resolve(true);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = Server;
|