Skip to content
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
merged 53 commits into from
Dec 27, 2016
Merged
Show file tree
Hide file tree
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 Nov 9, 2016
4b0bdec
[refactor] merged trailpack-core into trails
tjwebb Nov 14, 2016
c2054db
[refactor] added motd config
tjwebb Nov 15, 2016
3aef1ca
[refactor] remove events falsy check from onceAny
tjwebb Nov 15, 2016
8da326f
[refactor] after and onceAny
tjwebb Nov 15, 2016
7214fda
[refactor] validate config against joi schema
tjwebb Nov 15, 2016
bc9e91b
[fix] node4 syntax incompatibility
tjwebb Nov 16, 2016
f3cc086
2.0.0-rc0
tjwebb Nov 16, 2016
2d9d393
[refactor] check trails constructor "app" arg
tjwebb Nov 17, 2016
c2dbc5c
[pkg] include resource modules, peg versions
tjwebb Nov 19, 2016
d90c893
[fix] corrected stale config validation schema
tjwebb Nov 19, 2016
5f8d178
[refactor] configuration encapsulated in own class
tjwebb Nov 21, 2016
eb61390
[pkg] upgrade eslint module to 2.x series
tjwebb Nov 21, 2016
55f56e7
[fix] remove syntax unsupported by node4
tjwebb Nov 22, 2016
e7e53e3
[fix] nested path creation issue
tjwebb Nov 22, 2016
bc0b658
[refactor] remove unused method
tjwebb Nov 22, 2016
aaf94b2
[pkg] remove bundledDependencies
tjwebb Nov 25, 2016
2ee42b9
2.0.0-rc4
tjwebb Nov 25, 2016
0e776ed
[ux] improve trailpack logging
tjwebb Nov 26, 2016
db9423b
[fix] correct unintended functionality change
tjwebb Nov 27, 2016
aa27944
[fix] correct createPaths warning
tjwebb Nov 27, 2016
3a9e28d
2.0.0-rc5
tjwebb Nov 27, 2016
28d5474
[pkg] add publishConfig
tjwebb Nov 27, 2016
82512a6
2.0.0-rc6
tjwebb Nov 27, 2016
ba2ba13
[pkg] upgrade joi
tjwebb Nov 27, 2016
ba053ac
2.0.0-rc7
tjwebb Nov 27, 2016
838fe15
[archetype] upgrade to trails v2
tjwebb Nov 27, 2016
aed6d73
2.0.0-rc8
tjwebb Nov 27, 2016
83ad62e
[archetype] use v2 service require
tjwebb Nov 27, 2016
76f55a2
2.0.0-rc9
tjwebb Nov 27, 2016
ca946ae
[archetype] remove trailpack-core
tjwebb Nov 28, 2016
692e9b9
2.0.0-rc10
tjwebb Nov 28, 2016
5c91c57
[api] inject resource types into global ns
tjwebb Dec 6, 2016
b340afd
2.0.0-rc11
tjwebb Dec 6, 2016
0688784
[pkg] update devDependencies to v2-latest
tjwebb Dec 7, 2016
361420f
[test] removed smokesignals.Trailpack refs
tjwebb Dec 7, 2016
ec3eeb3
[refactor] use static getter for Error name prop
tjwebb Dec 8, 2016
3981bab
[test] update v8 4460 test
tjwebb Dec 8, 2016
89d23c1
[test] fix naked trailpack test issues
tjwebb Dec 8, 2016
2c949e7
[test] hardened getExternalModules test
tjwebb Dec 8, 2016
a305979
[fix] strict mode for node4
tjwebb Dec 8, 2016
967afc4
[doc] update README
tjwebb Dec 8, 2016
a05e228
[ci] integrate codeclimate coverage
tjwebb Dec 8, 2016
74430e5
[ci] quite down duplication warnings
tjwebb Dec 8, 2016
7576873
[archetype] remove whitespace
tjwebb Dec 9, 2016
9575778
[pkg] simplify test command
tjwebb Dec 9, 2016
2c78b38
[pkg] remove eslintignore, use gitignore
tjwebb Dec 9, 2016
8ad48ad
[pkg] try to work with windows
tjwebb Dec 13, 2016
25af2fd
Merge branch 'master' of github.com:trailsjs/trails into 2.0-rc
tjwebb Dec 21, 2016
587a10a
[pkg] keywords were getting out of hand
tjwebb Dec 21, 2016
bafa56a
[doc] add method documentation
tjwebb Dec 21, 2016
8d8edfe
[pkg] use bumped v2-series trails types
tjwebb Dec 22, 2016
62ee391
2.0.0
tjwebb Dec 27, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ node_js:
- 4
- 5
- 6
- 7
compiler:
- gcc
env:
Expand Down
128 changes: 93 additions & 35 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)) {
Copy link
Contributor

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 ?

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,
Expand All @@ -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: {
Expand Down Expand Up @@ -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(() => {
Expand All @@ -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 => {
Expand All @@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Member Author

Choose a reason for hiding this comment

The 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){
Expand All @@ -199,6 +252,7 @@ module.exports = class TrailsApp extends events.EventEmitter {
}
})
}))
.then(handlerWrapper)
}

/**
Expand All @@ -208,4 +262,8 @@ module.exports = class TrailsApp extends events.EventEmitter {
get log () {
return this.config.log.logger
}

get __ () {
return this.translate
}
}
98 changes: 98 additions & 0 deletions lib/core.js
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)
}
}
}

}
2 changes: 2 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ exports.Trailpack = require('./trailpack')
exports.Trails = require('./trails')
exports.Errors = require('./errors')
exports.Pathfinder = require('./pathfinder')
exports.Core = require('./core')
exports.Schemas = require('./schemas')
Loading