@ -9,37 +9,6 @@ const ansi = require('ansi-escape-sequences')
* @ module local - web - server
* @ module local - web - server
* /
* /
class CliView {
constructor ( options ) {
this . options = options || { }
}
show ( key , value ) {
if ( key && value ) {
const ansi = require ( 'ansi-escape-sequences' )
const tableLayout = require ( 'table-layout' )
const output = tableLayout ( { key : ansi . format ( key , 'bold' ) , value : value } , {
padding : { left : '' , right : ' ' } ,
columns : [
{ name : 'key' , width : 18 } ,
{ name : 'value' , nowrap : true }
]
} )
process . stderr . write ( output )
} else {
console . error ( key )
}
}
verbose ( key , value ) {
if ( this . options . verbose ) {
this . show ( key , value )
}
}
error ( msg ) {
console . error ( ansi . format ( msg , 'red' ) )
}
}
/ * *
/ * *
* @ alias module : local - web - server
* @ alias module : local - web - server
* @ extends module : middleware - stack
* @ extends module : middleware - stack
@ -55,9 +24,14 @@ class LocalWebServer {
initOptions = initOptions || { }
initOptions = initOptions || { }
const commandLineArgs = require ( 'command-line-args' )
const commandLineArgs = require ( 'command-line-args' )
const commandLineUsage = require ( 'command-line-usage' )
const commandLineUsage = require ( 'command-line-usage' )
const CliView = require ( './cli-view' )
const cli = require ( '../lib/cli-data' )
const cli = require ( '../lib/cli-data' )
this . view = new CliView ( )
/ * *
* Current view .
* @ type { View }
* /
this . view = new CliView ( this )
/* get stored config */
/* get stored config */
const loadConfig = require ( 'config-master' )
const loadConfig = require ( 'config-master' )
@ -66,11 +40,14 @@ class LocalWebServer {
/* read the config and command-line for feature paths */
/* read the config and command-line for feature paths */
const featurePaths = parseFeaturePaths ( initOptions . stack || stored . stack )
const featurePaths = parseFeaturePaths ( initOptions . stack || stored . stack )
/* load features and build the middleware stack */
const features = this . _buildFeatureStack ( featurePaths )
/ * *
* Loaded feature modules
* @ type { Feature [ ] }
* /
this . features = this . _buildFeatureStack ( featurePaths )
/* gather feature optionDefinitions and parse the command line */
/* gather feature optionDefinitions and parse the command line */
const featureOptionDefinitions = features
const featureOptionDefinitions = this . features
. filter ( mw => mw . optionDefinitions )
. filter ( mw => mw . optionDefinitions )
. map ( mw => mw . optionDefinitions ( ) )
. map ( mw => mw . optionDefinitions ( ) )
. reduce ( flatten , [ ] )
. reduce ( flatten , [ ] )
@ -95,7 +72,7 @@ class LocalWebServer {
return ` name: ${ def . name } ${ def . alias ? ', alias: ' + def . alias : '' } `
return ` name: ${ def . name } ${ def . alias ? ', alias: ' + def . alias : '' } `
} ) . join ( '\n' ) )
} ) . join ( '\n' ) )
}
}
this . view . show ( usage )
this . view . info ( usage )
process . exit ( 1 )
process . exit ( 1 )
}
}
}
}
@ -110,41 +87,39 @@ class LocalWebServer {
options . misc
options . misc
)
)
this . view . options . verbose = options . verbose
/ * *
/ * *
* Config
* Config
* @ type { object }
* @ type { object }
* /
* /
this . options = options
this . options = options
this . features = features
features
. filter ( mw => mw . on )
. forEach ( mw => {
mw . on ( 'verbose' , this . view . verbose . bind ( this . view ) )
mw . on ( 'debug' , this . view . verbose . bind ( this . view ) )
} )
if ( options . view ) {
const View = loadModule ( options . view )
this . view = new View ( this )
}
/* --config */
/* --config */
if ( options . config ) {
if ( options . config ) {
this . view . show ( JSON . stringify ( options , null , ' ' ) )
this . view . info ( JSON . stringify ( options , null , ' ' ) )
process . exit ( 0 )
process . exit ( 0 )
/* --version */
/* --version */
} else if ( options . version ) {
} else if ( options . version ) {
const pkg = require ( path . resolve ( __dirname , '..' , 'package.json' ) )
const pkg = require ( path . resolve ( __dirname , '..' , 'package.json' ) )
this . view . show ( pkg . version )
this . view . info ( pkg . version )
process . exit ( 0 )
process . exit ( 0 )
/* --help */
/* --help */
} else if ( options . help ) {
} else if ( options . help ) {
this . view . show ( usage )
this . view . info ( usage )
process . exit ( 0 )
process . exit ( 0 )
}
}
}
}
/ * *
* Returns a middleware application suitable for passing to ` http.createServer ` . The application is a function with three args ( req , res and next ) which can be created by express , Koa or hand - rolled .
* @ returns { function }
* /
getApplication ( ) {
getApplication ( ) {
const Koa = require ( 'koa' )
const Koa = require ( 'koa' )
const app = new Koa ( )
const app = new Koa ( )
@ -153,7 +128,7 @@ class LocalWebServer {
const middlewareStack = this . features
const middlewareStack = this . features
. filter ( mw => mw . middleware )
. filter ( mw => mw . middleware )
. map ( mw => mw . middleware ( this . options ) )
. map ( mw => mw . middleware ( this . options , this ) )
. reduce ( flatten , [ ] )
. reduce ( flatten , [ ] )
. filter ( mw => mw )
. filter ( mw => mw )
. map ( convert )
. map ( convert )
@ -162,9 +137,13 @@ class LocalWebServer {
app . on ( 'error' , err => {
app . on ( 'error' , err => {
console . error ( ansi . format ( err . stack , 'red' ) )
console . error ( ansi . format ( err . stack , 'red' ) )
} )
} )
return app
return app . callback ( )
}
}
/ * *
* Returns a listening server which processes requests using the middleware supplied .
* @ returns { Server }
* /
getServer ( onListening ) {
getServer ( onListening ) {
const app = this . getApplication ( )
const app = this . getApplication ( )
const options = this . options
const options = this . options
@ -186,11 +165,11 @@ class LocalWebServer {
}
}
const https = require ( 'https' )
const https = require ( 'https' )
server = https . createServer ( serverOptions , app . callback ( ) )
server = https . createServer ( serverOptions , app )
server . isHttps = true
server . isHttps = true
} else {
} else {
const http = require ( 'http' )
const http = require ( 'http' )
server = http . createServer ( app . callback ( ) )
server = http . createServer ( app )
}
}
server . listen ( options . port )
server . listen ( options . port )
@ -200,10 +179,15 @@ class LocalWebServer {
const ipList = getIPList ( )
const ipList = getIPList ( )
. map ( iface => ` [underline]{ ${ server . isHttps ? 'https' : 'http' } :// ${ iface . address } : ${ options . port } } ` )
. map ( iface => ` [underline]{ ${ server . isHttps ? 'https' : 'http' } :// ${ iface . address } : ${ options . port } } ` )
. join ( ', ' )
. join ( ', ' )
this . view . show ( 'Serving at' , ansi . format ( ipList ) )
this . view . info ( 'Serving at' , ansi . format ( ipList ) )
} )
} )
}
}
/ * *
* Node . js server
* @ type { Server }
* /
this . server = server
return server
return server
}
}
@ -211,32 +195,25 @@ class LocalWebServer {
return featurePaths
return featurePaths
. map ( featurePath => loadStack ( featurePath ) )
. map ( featurePath => loadStack ( featurePath ) )
. map ( Feature => new Feature ( ) )
. map ( Feature => new Feature ( ) )
. map ( modul e => {
if ( modul e. stack ) {
const featureStack = modul e. stack ( )
. map ( featur e => {
if ( featur e. stack ) {
const featureStack = featur e. stack ( )
. map ( Feature => new Feature ( ) )
. map ( Feature => new Feature ( ) )
. map ( feature => {
if ( feature . on ) {
feature . on ( 'verbose' , this . view . verbose . bind ( this . view ) )
feature . on ( 'debug' , this . view . verbose . bind ( this . view ) )
}
return feature
} )
module . optionDefinitions = function ( ) {
feature . optionDefinitions = function ( ) {
return featureStack
return featureStack
. map ( feature => feature . optionDefinitions && feature . optionDefinitions ( ) )
. map ( feature => feature . optionDefinitions && feature . optionDefinitions ( ) )
. filter ( definitions => definitions )
. filter ( definitions => definitions )
. reduce ( flatten , [ ] )
. reduce ( flatten , [ ] )
}
}
modul e. middleware = function ( options ) {
feature . middleware = function ( options , view ) {
return featureStack
return featureStack
. map ( feature => feature . middleware ( options ) )
. map ( feature => feature . middleware ( options , view ) )
. reduce ( flatten , [ ] )
. reduce ( flatten , [ ] )
. filter ( mw => mw )
. filter ( mw => mw )
}
}
}
}
return modul e
return featur e
} )
} )
}
}
}
}
@ -246,8 +223,26 @@ class LocalWebServer {
* @ returns { object }
* @ returns { object }
* /
* /
function loadStack ( modulePath ) {
function loadStack ( modulePath ) {
let module
const isModule = modu le => module . prototype && ( module . prototype . middleware || module . prototype . stack )
if ( isModule ( modulePath ) ) return modulePath
if ( isModule ( modulePath ) ) return modulePath
const module = loadModule ( modulePath )
if ( module ) {
if ( ! isModule ( module ) ) {
const insp = require ( 'util' ) . inspect ( module , { depth : 3 , colors : true } )
const msg = ` Not valid Middleware at: ${ insp } `
console . error ( msg )
process . exit ( 1 )
}
} else {
const msg = ` No module found at: \n ${ tried . join ( '\n' ) } `
console . error ( msg )
process . exit ( 1 )
}
return module
}
function loadModule ( modulePath ) {
let module
const tried = [ ]
const tried = [ ]
if ( modulePath ) {
if ( modulePath ) {
try {
try {
@ -268,22 +263,9 @@ function loadStack (modulePath) {
}
}
}
}
}
}
if ( module ) {
if ( ! isModule ( module ) ) {
const insp = require ( 'util' ) . inspect ( module , { depth : 3 , colors : true } )
const msg = ` Not valid Middleware at: ${ insp } `
tool . halt ( new Error ( msg ) )
}
} else {
const msg = ` No module found at: \n ${ tried . join ( '\n' ) } `
tool . halt ( new Error ( msg ) )
}
return module
return module
}
}
function isModule ( module ) {
return module . prototype && ( module . prototype . middleware || module . prototype . stack )
}
function getIPList ( ) {
function getIPList ( ) {
const flatten = require ( 'reduce-flatten' )
const flatten = require ( 'reduce-flatten' )