Comparing version 1.0.0-beta-8 to 1.0.0
@@ -19,3 +19,3 @@ # Contributing to Trails.js and Trailpacks | ||
1. Search for issues similar to yours in [GitHub search](https://github.com/trailsjs/trails/search?type=Issues) and [Google](https://www.google.nl/search?q=trails+js). | ||
2. Feature requests are welcome; see [Requesting Features](https://github.com/trailsjs/trails/blob/master/CONTRIBUTING.md#requesting-features) below for submission guidelines. | ||
2. Feature requests are welcome; see [Requesting Features](#requesting-features) below for submission guidelines. | ||
3. If there's an open issue, please contribute to that issue. | ||
@@ -22,0 +22,0 @@ 4. If there's a closed issue, open a new issue and link the url of the already closed issue(s). |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
exports.controllers = require('./controllers') | ||
@@ -2,0 +4,0 @@ exports.models = require('./models') |
@@ -1,1 +0,1 @@ | ||
exports.User = require('./User') | ||
'use strict' |
'use strict' | ||
const _ = require('lodash') | ||
const Service = require('trails-service') | ||
@@ -18,3 +17,13 @@ | ||
*/ | ||
getApplicationInfo () { | ||
getApplicationInfo() { | ||
const trailpacks = [] | ||
Object.keys(this.app.packs).forEach(packName => { | ||
if (packName != 'inspect') { | ||
const pack = this.app.packs[packName] | ||
trailpacks.push({ | ||
name: pack.name, | ||
version: pack.pkg.version | ||
}) | ||
} | ||
}) | ||
return { | ||
@@ -24,10 +33,5 @@ app: this.app.pkg.version, | ||
libs: process.versions, | ||
trailpacks: _.map(_.omit(this.app.packs, 'inspect'), pack => { | ||
return { | ||
name: pack.name, | ||
version: pack.pkg.version | ||
} | ||
}) | ||
trailpacks: trailpacks | ||
} | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
exports.DefaultService = require('./DefaultService') |
@@ -9,2 +9,5 @@ /** | ||
*/ | ||
'use strict' | ||
module.exports = { | ||
@@ -23,13 +26,19 @@ | ||
* Define a store called "local" which uses SQLite3 to persist data. | ||
* | ||
* To use this store, uncomment the "sqlitedev" store section below, and | ||
* run "npm install --save waterline-sqlite3" | ||
*/ | ||
sqlitedev: { | ||
/* | ||
dev: { | ||
adapter: require('waterline-sqlite3'), | ||
migrate: 'alter' | ||
} | ||
*/ | ||
}, | ||
models: { | ||
defaultStore: 'sqlitedev', | ||
defaultStore: 'dev', | ||
migrate: 'alter' | ||
} | ||
} |
@@ -1,3 +0,3 @@ | ||
module.exports = { | ||
'use strict' | ||
} | ||
module.exports = {} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
exports.development = require('./development') | ||
@@ -2,0 +4,0 @@ exports.staging = require('./staging') |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
const winston = require('winston') | ||
@@ -2,0 +4,0 @@ |
@@ -1,4 +0,3 @@ | ||
module.exports = { | ||
'use strict' | ||
} | ||
module.exports = {} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
module.exports = { | ||
@@ -8,4 +10,2 @@ | ||
} | ||
} | ||
@@ -12,2 +12,5 @@ /** | ||
*/ | ||
'use strict' | ||
module.exports = { | ||
@@ -14,0 +17,0 @@ |
@@ -5,2 +5,5 @@ /** | ||
*/ | ||
'use strict' | ||
exports.env = require('./env') | ||
@@ -7,0 +10,0 @@ exports.log = require('./log') |
@@ -7,2 +7,5 @@ /** | ||
*/ | ||
'use strict' | ||
const winston = require('winston') | ||
@@ -19,3 +22,3 @@ | ||
logger: new winston.Logger({ | ||
level: 'debug', | ||
level: 'info', | ||
exitOnError: false, | ||
@@ -22,0 +25,0 @@ transports: [ |
@@ -7,2 +7,5 @@ /** | ||
*/ | ||
'use strict' | ||
const path = require('path') | ||
@@ -9,0 +12,0 @@ |
@@ -12,2 +12,5 @@ /** | ||
*/ | ||
'use strict' | ||
module.exports = { | ||
@@ -14,0 +17,0 @@ |
@@ -9,2 +9,5 @@ /** | ||
*/ | ||
'use strict' | ||
module.exports = [ | ||
@@ -11,0 +14,0 @@ |
@@ -7,2 +7,5 @@ /** | ||
*/ | ||
'use strict' | ||
module.exports = { | ||
@@ -9,0 +12,0 @@ |
@@ -7,4 +7,7 @@ /** | ||
*/ | ||
'use strict' | ||
module.exports = { | ||
} |
@@ -0,3 +1,5 @@ | ||
'use strict' | ||
exports.pkg = require('./package') | ||
exports.config = require('./config') | ||
exports.api = require('./api') |
@@ -17,18 +17,10 @@ { | ||
"trails-service": "1.0.0-beta-2", | ||
"waterline-sqlite3": "^1.0.0", | ||
"winston": "^2.2" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^2.8", | ||
"eslint-config-trails": "latest", | ||
"eslint": "^2.8", | ||
"mocha": "^2.4", | ||
"supertest": "^1.2" | ||
}, | ||
"bundledDependencies": [ | ||
"trailpack-core", | ||
"trails", | ||
"trails-controller", | ||
"trails-policy", | ||
"trails-service" | ||
], | ||
"scripts": { | ||
@@ -35,0 +27,0 @@ "test": "eslint . && mocha" |
/** | ||
* @module server | ||
* | ||
* This code is part of the Trails framework. | ||
* Start up the Trails Application. | ||
*/ | ||
'use strict' | ||
const app = require('./') | ||
@@ -10,2 +13,2 @@ const TrailsApp = require('trails') | ||
server.start().catch(() => server.stop()) | ||
server.start().catch(err => server.stop(err)) |
111
index.js
@@ -25,19 +25,66 @@ /*eslint no-console: 0 */ | ||
} | ||
if (!app.pkg) { | ||
throw new lib.Errors.PackageNotDefinedError() | ||
} | ||
this.pkg = app.pkg | ||
this.config = lib.Trails.assignConfigDefaults(app.config) | ||
this.api = app.api | ||
this.bound = false | ||
this.started = false | ||
this.stopped = false | ||
this._trails = require('./package') | ||
lib.Trails.validateConfig(app.config) | ||
if (!this.config.log.logger) { | ||
console.error('A logger must be set at config.log.logger. Application cannot start.') | ||
console.error('e.g. new winston.Logger({ transports: [ new winston.transports.Console() ] })') | ||
console.error('For more info, see the config.log archetype: https://git.io/vVvUI') | ||
throw new lib.Errors.LoggerNotDefinedError() | ||
} | ||
Object.defineProperties(this, { | ||
env: { | ||
enumerable: false, | ||
value: Object.freeze(JSON.parse(JSON.stringify(process.env))) | ||
}, | ||
pkg: { | ||
enumerable: false, | ||
value: app.pkg | ||
}, | ||
config: { | ||
value: lib.Trails.buildConfig(app.config), | ||
configurable: true | ||
}, | ||
api: { | ||
value: app.api, | ||
writable: true, | ||
configurable: true | ||
}, | ||
_trails: { | ||
enumerable: false, | ||
value: require('./package') | ||
}, | ||
packs: { | ||
value: { } | ||
}, | ||
loadedPacks: { | ||
enumerable: false, | ||
writable: true, | ||
value: [ ] | ||
}, | ||
loadedModules: { | ||
enumerable: false, | ||
value: lib.Trails.getExternalModules(this.pkg) | ||
}, | ||
bound: { | ||
enumerable: false, | ||
writable: true, | ||
value: false | ||
}, | ||
started: { | ||
enumerable: false, | ||
writable: true, | ||
value: false | ||
}, | ||
stopped: { | ||
enumerable: false, | ||
writable: true, | ||
value: false | ||
}, | ||
timers: { | ||
enumerable: false, | ||
writable: true, | ||
value: { } | ||
} | ||
}) | ||
this.setMaxListeners(this.config.main.maxListeners) | ||
this.config.main.packs.forEach(Pack => new Pack(this)) | ||
} | ||
@@ -57,18 +104,11 @@ | ||
} | ||
this.api || (this.api = app && app.api) | ||
if (this.api && app && app.api) { | ||
this.log.info('Starting trails app with new API definition') | ||
} | ||
if (app && app.api) { | ||
this.api = app.api | ||
} | ||
const trailpacks = this.config.main.packs.map(Pack => new Pack(this)) | ||
this.packs = lib.Trailpack.getTrailpackMapping(trailpacks) | ||
this.loadedPacks = Object.keys(this.packs).map(name => this.packs[name]) | ||
lib.Trails.bindEvents(this) | ||
lib.Trailpack.bindTrailpackPhaseListeners(this, trailpacks) | ||
lib.Trailpack.bindTrailpackMethodListeners(this, trailpacks) | ||
lib.Trailpack.bindTrailpackPhaseListeners(this, this.loadedPacks) | ||
lib.Trailpack.bindTrailpackMethodListeners(this, this.loadedPacks) | ||
this.emit('trails:start') | ||
return this.after('trails:ready') | ||
@@ -86,2 +126,3 @@ .then(() => { | ||
stop (err) { | ||
this.stopped = true | ||
if (err) { | ||
@@ -91,21 +132,15 @@ this.log.error('\n', err.stack || '') | ||
if (!this.started) { | ||
this.log.error('\n', 'The application attempted to shut down, but is not', | ||
'in a started state. Either it is in the process of shutting down, or', | ||
'did not start successfully. Trails will not attempt to shut down twice.') | ||
this.log.error('\n', 'Try increasing the loglevel to "debug" to learn more') | ||
return Promise.resolve(this) | ||
this.log.error('The application did not boot successfully.') | ||
this.log.error('Try increasing the loglevel to "debug" to learn more') | ||
} | ||
this.emit('trails:stop') | ||
lib.Trails.unbindEvents(this) | ||
return Promise.all( | ||
Object.keys(this.packs || { }).map(packName => { | ||
this.log.debug('Unloading trailpack', packName) | ||
return this.packs[packName].unload() | ||
this.loadedPacks.map(pack => { | ||
this.log.debug('Unloading trailpack', pack.name, '...') | ||
return pack.unload() | ||
})) | ||
.then(() => { | ||
this.stopped = true | ||
this.log.debug('All trailpacks unloaded. Done.') | ||
return this | ||
@@ -121,3 +156,3 @@ }) | ||
this.log.debug('trails event:', event) | ||
super.emit.apply(this, arguments) | ||
return super.emit.apply(this, arguments) | ||
} | ||
@@ -124,0 +159,0 @@ |
'use strict' | ||
exports.ConfigNotDefinedError = class extends RangeError { | ||
constructor() { | ||
super(` | ||
"config" must be given to the Trails constructor, and it must contain | ||
an object called "main". Application cannot start. | ||
e.g. | ||
const app = new TrailsApp({ | ||
pkg: require('./package'), | ||
api: require('./api'), | ||
--> config: require('./config') | ||
}) | ||
For more info, see the Trails archetypes: | ||
- https://git.io/vw845 | ||
- https://git.io/vw84F | ||
`) | ||
} | ||
} | ||
exports.LoggerNotDefinedError = class extends RangeError { | ||
constructor() { | ||
super('Trails Logger is not defined') | ||
super(` | ||
A logger must be set at config.log.logger. Application cannot start. | ||
e.g. in config/log.js: | ||
const winston = require('./winston') | ||
module.exports = { | ||
logger: new winston.Logger({ | ||
transports: [ | ||
new winston.transports.Console() | ||
] | ||
}) | ||
} | ||
For more info, see the config.log archetype: https://git.io/vVvUI | ||
`) | ||
this.name = 'LoggerNotDefinedError' | ||
} | ||
@@ -11,4 +46,98 @@ } | ||
constructor() { | ||
super('Trails API is not defined') | ||
super(` | ||
"api" must be given to the Trails constructor, or to the start() method. | ||
Application cannot start. | ||
e.g. | ||
1) Send "api" to the constructor | ||
const app = new TrailsApp({ | ||
pkg: require('./package'), | ||
--> api: require('./api'), | ||
config: require('./config') | ||
}) | ||
-- OR -- | ||
2) Send "api" to the start() method: | ||
const app = new TrailsApp({ | ||
pkg: require('./package'), | ||
config: require('./config') | ||
}) | ||
app.start({ api: require('./api') }) | ||
For more info, see the Trails archetypes: | ||
- https://git.io/vw845 | ||
- https://git.io/vw84F | ||
`) | ||
this.name = 'ApiNotDefinedError' | ||
} | ||
} | ||
exports.ConfigValueError = class extends RangeError { | ||
constructor(msg) { | ||
super(msg) | ||
this.name = 'ConfigValueError' | ||
} | ||
} | ||
exports.PackageNotDefinedError = class extends RangeError { | ||
constructor() { | ||
super(` | ||
A "pkg" must be given to the Trails constructor. Application cannot start. | ||
e.g. | ||
const app = new TrailsApp({ | ||
--> pkg: require('./package'), | ||
api: require('./api'), | ||
config: require('./config') | ||
}) | ||
For more info, see the Trails archetypes: | ||
- https://git.io/vw845 | ||
- https://git.io/vw84F | ||
`) | ||
this.name = 'PackageNotDefinedError' | ||
} | ||
} | ||
exports.IllegalAccessError = class extends Error { | ||
constructor(msg) { | ||
super(msg) | ||
this.name = 'IllegalAccessError' | ||
} | ||
} | ||
exports.TimeoutError = class extends Error { | ||
constructor(phase, timeout) { | ||
super(` | ||
Timeout during "${phase}". Exceeded configured timeout of ${timeout}ms | ||
`) | ||
this.name = 'TimeoutError' | ||
} | ||
} | ||
exports.GraphCompletenessError = class extends RangeError { | ||
constructor (pack, stageName, eventName) { | ||
super(` | ||
The trailpack "${pack.name}" cannot load. | ||
During the "${stageName}" lifecycle stage, "${pack.name}" waits for | ||
the event "${eventName}". This event will not be emitted for one | ||
of the following reasons: | ||
1. The event "${eventName}" is emitted by a another Trailpack | ||
that, due to its configuration, paradoxically requires that | ||
"${pack.name}" loaded before it. | ||
2. The event "${eventName}" is not emitted by any other Trailpack, | ||
or it is not properly declared in the Trailpack's lifecycle | ||
config. | ||
Please check that you have all the Trailpacks correctly installed | ||
and configured. If you think this is a bug, please file an issue: | ||
https://github.com/trailsjs/trails/issues. | ||
`) | ||
this.name = 'GraphCompletenessError' | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict' | ||
exports.i18n = require('./i18n') | ||
@@ -5,1 +7,2 @@ exports.Trailpack = require('./trailpack') | ||
exports.Errors = require('./errors') | ||
exports.Pathfinder = require('./pathfinder') |
@@ -16,7 +16,7 @@ 'use strict' | ||
/** | ||
* Return all non-core trailpacks. As of v1.0, the only core trailpack is | ||
* Return all non-system trailpacks. As of v1.0, the only system trailpack is | ||
* "trailpack-core" | ||
*/ | ||
getUserlandTrailpacks (packs) { | ||
return packs.filter(pack => pack.name != 'core') | ||
return packs.filter(pack => pack.name !== 'core') | ||
}, | ||
@@ -34,9 +34,16 @@ | ||
app.after(configuredEvents).then(() => app.emit('trailpack:all:configured')) | ||
app.after(validatedEvents).then(() => app.emit('trailpack:all:validated')) | ||
app.after(configuredEvents) | ||
.then(() => app.emit('trailpack:all:configured')) | ||
.catch(err => app.stop(err)) | ||
app.after(initializedEvents).then(() => { | ||
app.emit('trailpack:all:initialized') | ||
app.emit('trails:ready') | ||
}) | ||
app.after(validatedEvents) | ||
.then(() => app.emit('trailpack:all:validated')) | ||
.catch(err => app.stop(err)) | ||
app.after(initializedEvents) | ||
.then(() => { | ||
app.emit('trailpack:all:initialized') | ||
app.emit('trails:ready') | ||
}) | ||
.catch(err => app.stop(err)) | ||
}, | ||
@@ -43,0 +50,0 @@ |
@@ -0,45 +1,146 @@ | ||
/*eslint no-console: 0 */ | ||
'use strict' | ||
const path = require('path') | ||
const lib = require('.') | ||
const TrailsUtil = module.exports = { | ||
module.exports = { | ||
assignConfigDefaults (config) { | ||
if (!config) { | ||
config = { } | ||
/** | ||
* Copy and merge the provided configuration into a new object, decorated with | ||
* necessary default and environment-specific values. | ||
*/ | ||
buildConfig (config) { | ||
const configTemplate = { | ||
main: { | ||
maxListeners: 128, | ||
packs: (config.main || { }).packs || [ ], | ||
paths: { | ||
root: path.resolve(path.dirname(require.main.filename)), | ||
temp: path.resolve(path.dirname(require.main.filename), '.tmp') | ||
}, | ||
timeouts: { | ||
start: 10000, | ||
stop: 10000 | ||
} | ||
}, | ||
log: { } | ||
} | ||
if (!config.env) { | ||
config.env = { } | ||
const envConfig = (config.env && config.env[process.env.NODE_ENV]) || { } | ||
// merge config.main.paths | ||
Object.assign( | ||
configTemplate.main.paths, (config.main || { }).paths, (envConfig.main || { }).paths | ||
) | ||
// merge config.main.timeouts | ||
Object.assign( | ||
configTemplate.main.timeouts, (config.main || { }).timeouts, (envConfig.main || { }).timeouts | ||
) | ||
// override config.main.packs with env config | ||
configTemplate.main.packs = (envConfig.main || { }).packs || (config.main || { }).packs || [ ] | ||
// merge application log | ||
Object.assign(configTemplate.log, config.log, envConfig.log) | ||
delete config.env | ||
// merge remaining environment-specific config properties | ||
return Object.assign({ }, config, envConfig, configTemplate) | ||
}, | ||
/** | ||
* Validate the structure and prerequisites of the configuration object. Throw | ||
* an Error if invalid; invalid configurations are unrecoverable and require | ||
* that programmer fix them. | ||
*/ | ||
validateConfig (config) { | ||
if (!config || !config.main) { | ||
throw new lib.Errors.ConfigNotDefinedError() | ||
} | ||
if (!config.env[process.env.NODE_ENV]) { | ||
config.env[process.env.NODE_ENV] = { } | ||
if (!config.log || !config.log.logger) { | ||
throw new lib.Errors.LoggerNotDefinedError() | ||
} | ||
if (!config.main) { | ||
config.main = { } | ||
} | ||
if (!config.main.packs) { | ||
config.main.packs = [ ] | ||
} | ||
if (!config.main.paths) { | ||
config.main.paths = { } | ||
} | ||
if (!config.main.maxListeners) { | ||
config.main.maxListeners = 128 | ||
} | ||
if (!config.log) { | ||
config.log = { } | ||
} | ||
if (!config.main.paths.root) { | ||
config.main.paths.root = path.resolve(process.cwd()) | ||
const nestedEnvs = lib.Trails.getNestedEnv(config) | ||
if (nestedEnvs.length) { | ||
throw new lib.Errors.ConfigValueError('Environment configs cannot contain an "env" property') | ||
} | ||
if (!config.main.paths.temp) { | ||
config.main.paths.temp = path.resolve(process.cwd(), '.tmp') | ||
if (config.env && config.env.env) { | ||
throw new lib.Errors.ConfigValueError('config.env cannot contain an "env" property') | ||
} | ||
}, | ||
return config | ||
/** | ||
* During config object inspection, we need to determine whether an arbitrary | ||
* object is an external module loaded from a require statement. For example, | ||
* the config object will contain trailpack modules, and we do not necessarily | ||
* want to deep freeze all of them. In general, messing directly with loaded | ||
* modules is not safe. | ||
*/ | ||
getExternalModules () { | ||
const rootPath = path.resolve(path.dirname(require.main.filename)) | ||
const modulePath = path.join(rootPath, 'node_modules') | ||
const requiredModules = Object.keys(require.cache).filter(mod => { | ||
return mod.indexOf(modulePath) >= 0 | ||
}) | ||
return requiredModules | ||
}, | ||
/** | ||
* Deep freeze application config object. Exceptions are made for required | ||
* modules that are listed as dependencies in the application's | ||
* package definition (package.json). | ||
* | ||
* @param config the configuration object to be frozen. | ||
* @param [pkg] the package definition to use for exceptions. optional. | ||
*/ | ||
freezeConfig (config, modules) { | ||
const propNames = Object.getOwnPropertyNames(config) | ||
propNames.forEach(name => { | ||
const prop = config[name] | ||
if (!prop || typeof prop !== 'object' || prop.constructor !== Object) { | ||
return | ||
} | ||
const ignoreModule = modules.find(moduleId => require.cache[moduleId].exports === prop) | ||
if (ignoreModule) { | ||
return | ||
} | ||
lib.Trails.freezeConfig(prop, modules) | ||
}) | ||
Object.freeze(config) | ||
}, | ||
/** | ||
* Copy the configuration into a normal, unfrozen object | ||
*/ | ||
unfreezeConfig (app) { | ||
Object.defineProperties(app, { | ||
config: { | ||
value: Object.assign({ }, app.config) | ||
} | ||
}) | ||
}, | ||
/** | ||
* Check to see if the user defined a property config.env[env].env | ||
*/ | ||
getNestedEnv (config) { | ||
const env = (config && config.env) | ||
const nestedEnvs = Object.keys(env || { }).filter(key => { | ||
return !!env[key].env | ||
}) | ||
return nestedEnvs | ||
}, | ||
/** | ||
* Bind listeners various application events | ||
@@ -54,3 +155,3 @@ */ | ||
TrailsUtil.bindApplicationEvents(app) | ||
lib.Trails.bindApplicationEvents(app) | ||
app.bound = true | ||
@@ -63,2 +164,7 @@ }, | ||
bindApplicationEvents (app) { | ||
app.once('error', err => app.stop(err)) | ||
app.once('trailpack:all:configured', () => { | ||
lib.Trails.freezeConfig(app.config, app.loadedModules) | ||
}) | ||
app.once('trails:stop', () => lib.Trails.unfreezeConfig(app)) | ||
app.once('trails:error:fatal', err => app.stop(err)) | ||
@@ -65,0 +171,0 @@ }, |
{ | ||
"name": "trails", | ||
"version": "1.0.0-beta-8", | ||
"version": "1.0.0", | ||
"description": "Modern Web Application Framework for Node.js", | ||
@@ -24,3 +24,4 @@ "keywords": [ | ||
"test": "eslint . && mocha", | ||
"coverage": "istanbul cover _mocha" | ||
"coverage": "istanbul cover _mocha", | ||
"ci": "cd .. && ci" | ||
}, | ||
@@ -47,7 +48,10 @@ "repository": { | ||
{ | ||
"name": "Linda Nichols", | ||
"email": "lynnaloo@gmail.com", | ||
"url": "https://github.com/lynnaloo" | ||
"name": "Jimmy Aumard", | ||
"url": "https://github.com/jaumard" | ||
}, | ||
{ | ||
"name": "Robert Rossmann", | ||
"url": "https://github.com/Alaneor" | ||
}, | ||
{ | ||
"name": "Mike Hostetler", | ||
@@ -64,7 +68,8 @@ "email": "mike@epicfirm.com" | ||
"devDependencies": { | ||
"eslint": "^2.0.0-beta.2", | ||
"eslint": "^2.5.3", | ||
"eslint-config-trails": "^1.0", | ||
"istanbul": "^0.4.2", | ||
"mocha": "^2.3.4", | ||
"trailpack": "^1.0.0-alpha-1", | ||
"smokesignals": "^1.2.0", | ||
"trailpack": "^1.0.1", | ||
"winston": "^2.1.1" | ||
@@ -74,3 +79,7 @@ }, | ||
"extends": "trails" | ||
}, | ||
"engines": { | ||
"node": ">= 4.0.0", | ||
"npm": ">= 2.14.2" | ||
} | ||
} |
@@ -5,5 +5,5 @@ [![Trails.js][trails-image]][trails-url] | ||
[![NPM version][npm-image]][npm-url] | ||
[![Build status][ci-image]][ci-url] | ||
[![Linux + OSX Build Status][ci-image]][ci-url] | ||
[![Windows Build Status][appveyor-image]][appveyor-url] | ||
[![Code Climate][codeclimate-image]][codeclimate-url] | ||
[![Issue Stats][issuestats-image]][issuestats-url] | ||
[![Follow @trailsjs on Twitter][twitter-image]][twitter-url] | ||
@@ -21,3 +21,3 @@ | ||
```sh | ||
$ npm install -g generator-trails | ||
$ npm install -g yo generator-trails | ||
$ yo trails | ||
@@ -81,3 +81,3 @@ ``` | ||
## RESOURCES | ||
## Resources | ||
@@ -128,2 +128,6 @@ #### Tutorials | ||
## Contributing | ||
We love contributions! Please check out our [Contributor's Guide](https://github.com/trailsjs/trails/blob/master/.github/CONTRIBUTING.md) for more | ||
information on how our projects are organized and how to get started. | ||
## License | ||
@@ -138,8 +142,8 @@ [MIT](https://github.com/trailsjs/trails/blob/master/LICENSE) | ||
[npm-url]: https://npmjs.org/package/trails | ||
[ci-image]: https://img.shields.io/travis/trailsjs/trails/master.svg?style=flat-square | ||
[ci-image]: https://img.shields.io/travis/trailsjs/trails.svg?style=flat-square&label=Linux%20/%20OSX | ||
[ci-url]: https://travis-ci.org/trailsjs/trails | ||
[appveyor-image]: https://img.shields.io/appveyor/ci/trailsjs/trails/master.svg?style=flat-square&label=Windows | ||
[appveyor-url]: https://ci.appveyor.com/project/trailsjs/trails | ||
[codeclimate-image]: https://img.shields.io/codeclimate/github/trailsjs/trails.svg?style=flat-square | ||
[codeclimate-url]: https://codeclimate.com/github/trailsjs/trails | ||
[issuestats-image]: http://issuestats.com/github/trailsjs/trails/badge/issue?style=flat-square | ||
[issuestats-url]: http://issuestats.com/github/trailsjs/trails | ||
[gitter-image]: http://img.shields.io/badge/+%20GITTER-JOIN%20CHAT%20%E2%86%92-1DCE73.svg?style=flat-square | ||
@@ -146,0 +150,0 @@ [gitter-url]: https://gitter.im/trailsjs/trails |
'use strict' | ||
const assert = require('assert') | ||
const smokesignals = require('smokesignals') | ||
const TrailsApp = require('..') | ||
@@ -77,28 +78,108 @@ const testAppDefinition = require('./testapp') | ||
describe('errors', () => { | ||
it('should throw LoggerNotDefinedError if logger is missing', () => { | ||
describe('@LoggerNotDefinedError', () => { | ||
it('should throw LoggerNotDefinedError if logger is missing', () => { | ||
const def = { | ||
pkg: { }, | ||
api: { }, | ||
config: { | ||
main: { | ||
paths: { root: __dirname } | ||
} | ||
} | ||
} | ||
assert.throws(() => new TrailsApp(def), lib.Errors.LoggerNotDefinedError) | ||
}) | ||
}) | ||
describe('@ApiNotDefinedError', () => { | ||
it('should throw ApiNotDefinedError if no api definition is provided', () => { | ||
const def = { | ||
pkg: { }, | ||
config: { | ||
main: { | ||
paths: { root: __dirname } | ||
}, | ||
log: { | ||
logger: new smokesignals.Logger('silent') | ||
} | ||
} | ||
} | ||
const app = new TrailsApp(def) | ||
assert.throws(() => app.start(), lib.Errors.ApiNotDefinedError) | ||
}) | ||
}) | ||
describe('@PackageNotDefinedError', () => { | ||
it('should throw PackageNotDefinedError if no pkg definition is provided', () => { | ||
const def = { | ||
config: { | ||
main: { | ||
paths: { root: __dirname } | ||
}, | ||
log: { | ||
logger: new smokesignals.Logger('silent') | ||
} | ||
} | ||
} | ||
assert.throws(() => new TrailsApp(def), lib.Errors.PackageNotDefinedError) | ||
}) | ||
}) | ||
it('should cache and freeze process.env', () => { | ||
process.env.FOO = 'bar' | ||
const def = { | ||
api: { }, | ||
config: { | ||
main: { }, | ||
log: { | ||
logger: new smokesignals.Logger('silent') | ||
} | ||
}, | ||
pkg: { } | ||
} | ||
const app = new TrailsApp(def) | ||
assert.equal(process.env.FOO, 'bar') | ||
assert.equal(app.env.FOO, 'bar') | ||
assert.throws(() => app.env.FOO = 1, TypeError) | ||
}) | ||
it('should freeze config object after trailpacks are loaded', () => { | ||
const def = { | ||
pkg: { }, | ||
api: { }, | ||
config: { | ||
main: { | ||
paths: { root: __dirname } | ||
} | ||
packs: [ smokesignals.Trailpack ] | ||
}, | ||
log: { logger: new smokesignals.Logger('silent') }, | ||
foo: 'bar' | ||
} | ||
} | ||
assert.throws(() => new TrailsApp(def), lib.Errors.LoggerNotDefinedError) | ||
const app = new TrailsApp(def) | ||
assert.equal(app.config.foo, 'bar') | ||
app.start() | ||
return app.after('trailpack:all:configured').then(() => { | ||
assert.equal(app.config.foo, 'bar') | ||
assert.throws(() => app.config.foo = 1, TypeError) | ||
return app.stop() | ||
}) | ||
}) | ||
it('should throw ApiNotDefinedError if no api definition is provided', () => { | ||
it('should disallow re-assignment of config object', () => { | ||
const def = { | ||
pkg: { }, | ||
api: { }, | ||
config: { | ||
main: { | ||
paths: { root: __dirname } | ||
packs: [ smokesignals.Trailpack ] | ||
}, | ||
log: { | ||
logger: { } | ||
} | ||
log: { logger: new smokesignals.Logger('silent') }, | ||
foo: 'bar' | ||
} | ||
} | ||
const app = new TrailsApp(def) | ||
assert.throws(() => app.start(), lib.Errors.ApiNotDefinedError) | ||
assert.equal(app.config.foo, 'bar') | ||
assert.throws(() => app.config = { }, Error) | ||
}) | ||
}) | ||
}) | ||
@@ -105,0 +186,0 @@ |
@@ -9,3 +9,3 @@ 'use strict' | ||
describe('Trailpack', () => { | ||
describe('lib.Trailpack', () => { | ||
const app = new TrailsApp(testAppDefinition) | ||
@@ -12,0 +12,0 @@ |
@@ -0,1 +1,3 @@ | ||
const smokesignals = require('smokesignals') | ||
module.exports = { | ||
@@ -11,3 +13,5 @@ api: { | ||
}, | ||
log: require('../archetype/config/log') | ||
log: { | ||
logger: new smokesignals.Logger('silent') | ||
} | ||
}, | ||
@@ -14,0 +18,0 @@ pkg: { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
77869
55
1775
0
148
7
14
1