-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
2.0 rc #257
Merged
2.0 rc #257
Changes from 6 commits
Commits
Show all changes
53 commits
Select commit
Hold shift + click to select a range
7d6bbc5
[ci] test node 7
tjwebb 4b0bdec
[refactor] merged trailpack-core into trails
tjwebb c2054db
[refactor] added motd config
tjwebb 3aef1ca
[refactor] remove events falsy check from onceAny
tjwebb 8da326f
[refactor] after and onceAny
tjwebb 7214fda
[refactor] validate config against joi schema
tjwebb bc9e91b
[fix] node4 syntax incompatibility
tjwebb f3cc086
2.0.0-rc0
tjwebb 2d9d393
[refactor] check trails constructor "app" arg
tjwebb c2dbc5c
[pkg] include resource modules, peg versions
tjwebb d90c893
[fix] corrected stale config validation schema
tjwebb 5f8d178
[refactor] configuration encapsulated in own class
tjwebb eb61390
[pkg] upgrade eslint module to 2.x series
tjwebb 55f56e7
[fix] remove syntax unsupported by node4
tjwebb e7e53e3
[fix] nested path creation issue
tjwebb bc0b658
[refactor] remove unused method
tjwebb aaf94b2
[pkg] remove bundledDependencies
tjwebb 2ee42b9
2.0.0-rc4
tjwebb 0e776ed
[ux] improve trailpack logging
tjwebb db9423b
[fix] correct unintended functionality change
tjwebb aa27944
[fix] correct createPaths warning
tjwebb 3a9e28d
2.0.0-rc5
tjwebb 28d5474
[pkg] add publishConfig
tjwebb 82512a6
2.0.0-rc6
tjwebb ba2ba13
[pkg] upgrade joi
tjwebb ba053ac
2.0.0-rc7
tjwebb 838fe15
[archetype] upgrade to trails v2
tjwebb aed6d73
2.0.0-rc8
tjwebb 83ad62e
[archetype] use v2 service require
tjwebb 76f55a2
2.0.0-rc9
tjwebb ca946ae
[archetype] remove trailpack-core
tjwebb 692e9b9
2.0.0-rc10
tjwebb 5c91c57
[api] inject resource types into global ns
tjwebb b340afd
2.0.0-rc11
tjwebb 0688784
[pkg] update devDependencies to v2-latest
tjwebb 361420f
[test] removed smokesignals.Trailpack refs
tjwebb ec3eeb3
[refactor] use static getter for Error name prop
tjwebb 3981bab
[test] update v8 4460 test
tjwebb 89d23c1
[test] fix naked trailpack test issues
tjwebb 2c949e7
[test] hardened getExternalModules test
tjwebb a305979
[fix] strict mode for node4
tjwebb 967afc4
[doc] update README
tjwebb a05e228
[ci] integrate codeclimate coverage
tjwebb 74430e5
[ci] quite down duplication warnings
tjwebb 7576873
[archetype] remove whitespace
tjwebb 9575778
[pkg] simplify test command
tjwebb 2c78b38
[pkg] remove eslintignore, use gitignore
tjwebb 8ad48ad
[pkg] try to work with windows
tjwebb 25af2fd
Merge branch 'master' of github.com:trailsjs/trails into 2.0-rc
tjwebb 587a10a
[pkg] keywords were getting out of hand
tjwebb bafa56a
[doc] add method documentation
tjwebb 8d8edfe
[pkg] use bumped v2-series trails types
tjwebb 62ee391
2.0.0
tjwebb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ node_js: | |
- 4 | ||
- 5 | ||
- 6 | ||
- 7 | ||
compiler: | ||
- gcc | ||
env: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ | |
|
||
const events = require('events') | ||
const lib = require('./lib') | ||
const i18next = require('i18next') | ||
const NOOP = function () { } | ||
|
||
/** | ||
* The Trails Application. Merges the configuration and API resources | ||
|
@@ -12,26 +14,32 @@ module.exports = class TrailsApp extends events.EventEmitter { | |
|
||
/** | ||
* @param pkg The application package.json | ||
* @param app.api The application api (api/ folder) | ||
* @param app.config The application configuration (config/ folder) | ||
* | ||
* Initialize the Trails Application and its EventEmitter parentclass. Set | ||
* some necessary default configuration. | ||
*/ | ||
constructor (app) { | ||
super() | ||
|
||
if (!process.env.NODE_ENV) { | ||
process.env.NODE_ENV = 'development' | ||
} | ||
if (!app.pkg) { | ||
throw new lib.Errors.PackageNotDefinedError() | ||
} | ||
if (!app.api && !(app && app.api)) { | ||
throw new lib.Errors.ApiNotDefinedError() | ||
} | ||
|
||
lib.Trails.validateConfig(app.config) | ||
if (!process.env.NODE_ENV) { | ||
process.env.NODE_ENV = 'development' | ||
} | ||
|
||
const processEnv = Object.freeze(JSON.parse(JSON.stringify(process.env))) | ||
|
||
Object.defineProperties(this, { | ||
env: { | ||
enumerable: false, | ||
value: Object.freeze(JSON.parse(JSON.stringify(process.env))) | ||
value: processEnv | ||
}, | ||
pkg: { | ||
enumerable: false, | ||
|
@@ -44,7 +52,7 @@ module.exports = class TrailsApp extends events.EventEmitter { | |
value: process.versions | ||
}, | ||
config: { | ||
value: lib.Trails.buildConfig(app.config), | ||
value: lib.Trails.buildConfig(app.config, processEnv), | ||
configurable: true | ||
}, | ||
api: { | ||
|
@@ -87,34 +95,64 @@ module.exports = class TrailsApp extends events.EventEmitter { | |
enumerable: false, | ||
writable: true, | ||
value: { } | ||
}, | ||
models: { | ||
enumerable: true, | ||
writable: false, | ||
value: { } | ||
}, | ||
services: { | ||
enumerable: true, | ||
writable: false, | ||
value: { } | ||
}, | ||
controllers: { | ||
enumerable: true, | ||
writable: false, | ||
value: { } | ||
}, | ||
policies: { | ||
enumerable: true, | ||
writable: false, | ||
value: { } | ||
}, | ||
translate: { | ||
enumerable: false, | ||
writable: true | ||
} | ||
}) | ||
|
||
lib.Trails.validateConfig(app.config) | ||
lib.Core.createDefaultPaths(this) | ||
this.setMaxListeners(this.config.main.maxListeners) | ||
|
||
Object.assign(this.models, lib.Core.bindMethods(this, 'models')) | ||
Object.assign(this.services, lib.Core.bindMethods(this, 'services')) | ||
Object.assign(this.controllers, lib.Core.bindMethods(this, 'controllers')) | ||
Object.assign(this.policies, lib.Core.bindMethods(this, 'policies')) | ||
|
||
this.config.main.packs.forEach(Pack => new Pack(this)) | ||
delete this.config.env // Delete env config, now it has been merge | ||
this.loadedPacks = Object.keys(this.packs).map(name => this.packs[name]) | ||
|
||
delete this.config.env | ||
} | ||
|
||
/** | ||
* Start the App. Load all Trailpacks. The "api" property is required, here, | ||
* if not provided to the constructor. | ||
* Start the App. Load all Trailpacks. | ||
* | ||
* @param app.api The application api (api/ folder) | ||
* @param app.config The application configuration (config/ folder) | ||
* @return Promise | ||
*/ | ||
start (app) { | ||
if (!this.api && !(app && app.api)) { | ||
throw new lib.Errors.ApiNotDefinedError() | ||
} | ||
this.api || (this.api = app && app.api) | ||
|
||
this.loadedPacks = Object.keys(this.packs).map(name => this.packs[name]) | ||
lib.Trails.bindEvents(this) | ||
start () { | ||
lib.Trails.bindListeners(this) | ||
lib.Trailpack.bindTrailpackPhaseListeners(this, this.loadedPacks) | ||
lib.Trailpack.bindTrailpackMethodListeners(this, this.loadedPacks) | ||
|
||
this.emit('trails:start') | ||
i18next.init(this.config.i18n, (err, t) => { | ||
if (err) throw err | ||
|
||
this.translate = t | ||
this.emit('trails:start') | ||
}) | ||
|
||
return this.after('trails:ready') | ||
.then(() => { | ||
|
@@ -138,7 +176,7 @@ module.exports = class TrailsApp extends events.EventEmitter { | |
} | ||
|
||
this.emit('trails:stop') | ||
lib.Trails.unbindEvents(this) | ||
lib.Trails.unbindListeners(this) | ||
|
||
return Promise.all( | ||
this.loadedPacks.map(pack => { | ||
|
@@ -161,34 +199,49 @@ module.exports = class TrailsApp extends events.EventEmitter { | |
} | ||
|
||
/** | ||
* Extend the once emiter reader for accept multi valid events | ||
* Resolve Promise once ANY of the events in the list have emitted. Also | ||
* accepts a callback. | ||
* @return Promise | ||
*/ | ||
onceAny (events, handler) { | ||
const self = this | ||
|
||
if (!events) | ||
return | ||
if (!Array.isArray(events)) | ||
onceAny (events, handler = NOOP) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will not work for node < 6 :( default value are comping with node 6 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, tests are failing, I'll fix. |
||
if (!Array.isArray(events)) { | ||
events = [events] | ||
} | ||
|
||
function cb (e) { | ||
self.removeListener(e, cb) | ||
handler.apply(this, Array.prototype.slice.call(arguments, 0)) | ||
let resolveCallback | ||
const handlerWrapper = (...args) => { | ||
handler(args) | ||
return args | ||
} | ||
|
||
events.forEach(e => { | ||
this.addListener(e, cb) | ||
return Promise.race(events.map(eventName => { | ||
return new Promise(resolve => { | ||
resolveCallback = resolve | ||
this.once(eventName, resolveCallback) | ||
}) | ||
})) | ||
.then(handlerWrapper) | ||
.then(args => { | ||
events.forEach(eventName => this.removeListener(eventName, resolveCallback)) | ||
return args | ||
}) | ||
} | ||
|
||
/** | ||
* Resolve Promise once all events in the list have emitted | ||
* Resolve Promise once all events in the list have emitted. Also accepts | ||
* a callback. | ||
* @return Promise | ||
*/ | ||
after (events) { | ||
after (events, handler = NOOP) { | ||
if (!Array.isArray(events)) { | ||
events = [ events ] | ||
} | ||
|
||
const handlerWrapper = (args) => { | ||
handler(args) | ||
return args | ||
} | ||
|
||
return Promise.all(events.map(eventName => { | ||
return new Promise(resolve => { | ||
if (eventName instanceof Array){ | ||
|
@@ -199,6 +252,7 @@ module.exports = class TrailsApp extends events.EventEmitter { | |
} | ||
}) | ||
})) | ||
.then(handlerWrapper) | ||
} | ||
|
||
/** | ||
|
@@ -208,4 +262,8 @@ module.exports = class TrailsApp extends events.EventEmitter { | |
get log () { | ||
return this.config.log.logger | ||
} | ||
|
||
get __ () { | ||
return this.translate | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
'use strict' | ||
|
||
const fs = require('fs') | ||
const isPlainObject = require('lodash.isplainobject') | ||
const mapValues = require('lodash.mapvalues') | ||
const forEach = require('lodash.foreach') | ||
const includes = require('lodash.includes') | ||
const isFunction = require('lodash.isFunction') | ||
|
||
const Core = module.exports = { | ||
|
||
reservedMethods: [ | ||
'app', | ||
'api', | ||
'log', | ||
'__', | ||
'constructor', | ||
'undefined', | ||
'methods', | ||
'config', | ||
'schema' | ||
], | ||
|
||
/** | ||
* Bind the context of API resource methods. | ||
*/ | ||
bindMethods (app, resource) { | ||
return mapValues(app.api[resource], (Resource, resourceName) => { | ||
if (isPlainObject(Resource)) { | ||
throw new Error(`${resourceName} should be a class. It is a regular object`) | ||
} | ||
|
||
const obj = new Resource(app) | ||
|
||
obj.methods = Core.getClassMethods(obj) | ||
forEach(obj.methods, method => { | ||
obj[method] = obj[method].bind(obj) | ||
}) | ||
return obj | ||
}) | ||
}, | ||
|
||
/** | ||
* Traverse protoype chain and aggregate all class method names | ||
*/ | ||
getClassMethods (obj) { | ||
const props = [ ] | ||
const objectRoot = new Object() | ||
|
||
while (!obj.isPrototypeOf(objectRoot)) { | ||
Object.getOwnPropertyNames(obj).forEach(prop => { | ||
if (props.indexOf(prop) === -1 && | ||
!includes(Core.reservedMethods, prop) && | ||
isFunction(obj[prop])) { | ||
|
||
props.push(prop) | ||
} | ||
}) | ||
obj = Object.getPrototypeOf(obj) | ||
} | ||
|
||
return props | ||
}, | ||
|
||
/** | ||
* create paths if they don't exist | ||
*/ | ||
createDefaultPaths (app) { | ||
const paths = app.config.main.paths | ||
|
||
return Promise.all(Object.keys(paths).map(pathName => { | ||
const dir = paths[pathName] | ||
if (Array.isArray(dir)) { | ||
dir.map(item => { | ||
pathCreate(item.path, pathName) | ||
}) | ||
} | ||
else { | ||
pathCreate(dir, pathName) | ||
} | ||
})) | ||
function pathCreate(dir, pathName) { | ||
try { | ||
const stats = fs.statSync(dir) | ||
|
||
if (!stats.isDirectory()) { | ||
app.log.error('The path "', pathName, '" is not a directory.') | ||
app.log.error('config.main.paths should only contain paths to directories') | ||
return Promise.reject() | ||
} | ||
} | ||
catch (e) { | ||
fs.mkdirSync(dir) | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One seems useless here right ?