Comparing version 2.0.2 to 3.0.0-pre.1
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
exports.controllers = require('./controllers') | ||
@@ -4,0 +2,0 @@ exports.models = require('./models') |
@@ -1,3 +0,3 @@ | ||
'use strict' | ||
module.exports = { | ||
module.exports = {} | ||
} |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
exports.development = require('./development') | ||
@@ -4,0 +2,0 @@ exports.staging = require('./staging') |
@@ -1,37 +0,3 @@ | ||
'use strict' | ||
const winston = require('winston') | ||
module.exports = { | ||
trailpack: { | ||
disabled: [ | ||
'repl' | ||
] | ||
}, | ||
log: { | ||
logger: new winston.Logger({ | ||
level: 'info', | ||
exitOnError: false, | ||
transports: [ | ||
new winston.transports.Console({ | ||
timestamp: true | ||
}), | ||
new winston.transports.File({ | ||
name: 'info-file', | ||
level: 'info', | ||
filename: 'trails-info.log', | ||
timestamp: true | ||
}), | ||
new winston.transports.File({ | ||
name: 'error-file', | ||
level: 'error', | ||
filename: 'trails-error.log', | ||
timestamp: true | ||
}) | ||
] | ||
}) | ||
} | ||
} |
@@ -1,3 +0,3 @@ | ||
'use strict' | ||
module.exports = { | ||
module.exports = {} | ||
} |
@@ -1,10 +0,3 @@ | ||
'use strict' | ||
module.exports = { | ||
trailpack: { | ||
disabled: [ | ||
'repl' | ||
] | ||
} | ||
} |
@@ -11,4 +11,2 @@ /** | ||
'use strict' | ||
module.exports = { | ||
@@ -15,0 +13,0 @@ |
/** | ||
* Trails Core Configuration | ||
* (app.config) | ||
* Trails Configuration Manifest | ||
* @see {@link http://trailsjs.io/doc/config/manifest} | ||
*/ | ||
'use strict' | ||
exports.env = require('./env') | ||
exports.log = require('./log') | ||
exports.main = require('./main') | ||
exports.database = require('./database') | ||
exports.i18n = require('./i18n') | ||
exports.policies = require('./policies') | ||
exports.routes = require('./routes') | ||
exports.session = require('./session') | ||
exports.views = require('./views') | ||
exports.stores = require('./stores') | ||
exports.web = require('./web') |
@@ -5,28 +5,7 @@ /** | ||
* | ||
* @see http://trailsjs.io/doc/config/log | ||
* @see {@link http://trailsjs.io/doc/config/log} | ||
*/ | ||
'use strict' | ||
const winston = require('winston') | ||
module.exports = { | ||
/** | ||
* Specify the logger to use. | ||
* @see https://github.com/winstonjs/winston#instantiating-your-own-logger | ||
* | ||
* Exposed on app.log | ||
*/ | ||
logger: new winston.Logger({ | ||
level: 'info', | ||
exitOnError: false, | ||
transports: [ | ||
new (winston.transports.Console)({ | ||
prettyPrint: true, | ||
colorize: true | ||
}) | ||
] | ||
}) | ||
} |
/** | ||
* Trailpack Configuration | ||
* Main App Configuration | ||
* (app.config.main) | ||
* | ||
* @see http://trailsjs.io/doc/config/main | ||
* @see {@link http://trailsjs.io/doc/config/main} | ||
*/ | ||
'use strict' | ||
const path = require('path') | ||
@@ -19,5 +17,2 @@ | ||
packs: [ | ||
require('trailpack-repl'), | ||
require('trailpack-router'), | ||
require('<%- trailpacks %>') | ||
], | ||
@@ -24,0 +19,0 @@ |
/** | ||
* Routes Configuration | ||
* (trails.config.routes) | ||
* | ||
* Configure how routes map to views and controllers. | ||
* Configure how url patterns map to controllers, views, and static files. | ||
* | ||
* @see http://trailsjs.io/doc/config/routes.js | ||
* @see {@link http://trailsjs.io/doc/config/routes} | ||
*/ | ||
'use strict' | ||
module.exports = [ | ||
/** | ||
* Render the HelloWorld view | ||
*/ | ||
{ | ||
method: 'GET', | ||
path: '/', | ||
handler: 'ViewController.helloWorld' | ||
}, | ||
/** | ||
* Constrain the DefaultController.info handler to accept only GET requests. | ||
*/ | ||
{ | ||
method: [ 'GET' ], | ||
path: '/api/v1/default/info', | ||
handler: 'DefaultController.info' | ||
} | ||
] |
@@ -1,5 +0,3 @@ | ||
'use strict' | ||
exports.pkg = require('./package') | ||
exports.config = require('./config') | ||
exports.api = require('./api') |
{ | ||
"version": "0.0.0", | ||
"keywords": [ | ||
"trails", | ||
"trailsjs" | ||
"trails" | ||
], | ||
@@ -11,4 +10,3 @@ "main": "index.js", | ||
"trailpack-router": "^2", | ||
"trails": "^2", | ||
"winston": "^2.3" | ||
"trails": "^2" | ||
}, | ||
@@ -15,0 +13,0 @@ "devDependencies": { |
/** | ||
* @module server | ||
* | ||
* Start up the Trails Application. | ||
*/ | ||
'use strict' | ||
const TrailsApp = require('trails') | ||
@@ -10,0 +5,0 @@ const app = require('./') |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
const assert = require('assert') | ||
@@ -4,0 +2,0 @@ |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
const TrailsApp = require('trails') | ||
@@ -4,0 +2,0 @@ |
139
index.js
/*eslint no-console: 0 */ | ||
'use strict' | ||
/*eslint no-process-env: 0 */ | ||
const EventEmitter = require('events').EventEmitter | ||
const lib = require('./lib') | ||
const i18next = require('i18next') | ||
const NOOP = function () { } | ||
@@ -33,8 +31,14 @@ // inject Error and Resource types into the global namespace | ||
if (!app.pkg) { | ||
throw new lib.Errors.PackageNotDefinedError() | ||
throw new PackageNotDefinedError() | ||
} | ||
if (!app.api) { | ||
throw new lib.Errors.ApiNotDefinedError() | ||
throw new ApiNotDefinedError() | ||
} | ||
app.api.models || (app.api.models = { }) | ||
app.api.services || (app.api.services = { }) | ||
app.api.resolvers || (app.api.resolvers = { }) | ||
app.api.policies || (app.api.policies = { }) | ||
app.api.controllers || (app.api.controllers = { }) | ||
if (!process.env.NODE_ENV) { | ||
@@ -83,6 +87,2 @@ process.env.NODE_ENV = 'development' | ||
}, | ||
loadedModules: { | ||
enumerable: false, | ||
value: lib.Core.getExternalModules(this.pkg) | ||
}, | ||
bound: { | ||
@@ -128,2 +128,7 @@ enumerable: false, | ||
}, | ||
resolvers: { | ||
enumerable: true, | ||
writable: false, | ||
value: { } | ||
}, | ||
translate: { | ||
@@ -135,8 +140,9 @@ enumerable: false, | ||
this.setMaxListeners(this.config.main.maxListeners) | ||
this.setMaxListeners(this.config.get('main.maxListeners')) | ||
// instantiate trailpacks | ||
this.config.main.packs.forEach(Pack => { | ||
this.config.get('main.packs').forEach(Pack => { | ||
try { | ||
new Pack(this) | ||
const pack = new Pack(this) | ||
lib.Core.bindTrailpackMethodListeners(this, pack) | ||
} | ||
@@ -150,6 +156,7 @@ catch (e) { | ||
// bind resource methods | ||
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')) | ||
lib.Core.bindListeners(this) | ||
lib.Core.bindTrailpackPhaseListeners(this, this.loadedPacks) | ||
} | ||
@@ -162,22 +169,10 @@ | ||
*/ | ||
start () { | ||
lib.Core.bindListeners(this) | ||
lib.Trailpack.bindTrailpackPhaseListeners(this, this.loadedPacks) | ||
lib.Trailpack.bindTrailpackMethodListeners(this, this.loadedPacks) | ||
async start () { | ||
// initialize i18n | ||
i18next.init(this.config.i18n, (err, t) => { | ||
if (err) { | ||
throw new Error(`Problem loading i18n: ${err}`) | ||
} | ||
this.emit('trails:start') | ||
this.translate = t | ||
this.emit('trails:start') | ||
}) | ||
await this.after('trails:ready') | ||
this.started = true | ||
return this.after('trails:ready') | ||
.then(() => { | ||
this.started = true | ||
return this | ||
}) | ||
return this | ||
} | ||
@@ -189,3 +184,3 @@ | ||
*/ | ||
stop (err) { | ||
async stop (err) { | ||
this.stopped = true | ||
@@ -203,15 +198,9 @@ if (err) { | ||
return Promise.all( | ||
this.loadedPacks.map(pack => { | ||
this.log.debug('Unloading trailpack', pack.name, '...') | ||
return pack.unload() | ||
})) | ||
.then(() => { | ||
this.log.debug('All trailpacks unloaded. Done.') | ||
return this | ||
}) | ||
.catch(err => { | ||
console.error(err) | ||
return this | ||
}) | ||
await Promise.all(this.loadedPacks.map(pack => { | ||
this.log.debug('Unloading trailpack', pack.name, '...') | ||
return pack.unload() | ||
})) | ||
this.log.debug('All trailpacks unloaded. Done.') | ||
return this | ||
} | ||
@@ -229,8 +218,7 @@ | ||
/** | ||
* Resolve Promise once ANY of the events in the list have emitted. Also | ||
* accepts a callback. | ||
* Resolve Promise once ANY of the events in the list have emitted. | ||
* | ||
* @return Promise | ||
*/ | ||
onceAny (events, handler) { | ||
handler || (handler = NOOP) | ||
async onceAny (events) { | ||
if (!Array.isArray(events)) { | ||
@@ -241,6 +229,2 @@ events = [events] | ||
let resolveCallback | ||
const handlerWrapper = function () { | ||
handler.apply(null, arguments) | ||
return arguments | ||
} | ||
@@ -253,4 +237,3 @@ return Promise.race(events.map(eventName => { | ||
})) | ||
.then(handlerWrapper) | ||
.then(args => { | ||
.then((...args) => { | ||
events.forEach(eventName => this.removeListener(eventName, resolveCallback)) | ||
@@ -263,7 +246,7 @@ return args | ||
* Resolve Promise once all events in the list have emitted. Also accepts | ||
* | ||
* a callback. | ||
* @return Promise | ||
*/ | ||
after (events, handler) { | ||
handler || (handler = NOOP) | ||
async after (events) { | ||
if (!Array.isArray(events)) { | ||
@@ -273,11 +256,6 @@ events = [ events ] | ||
const handlerWrapper = (args) => { | ||
handler(args) | ||
return args | ||
} | ||
return Promise.all(events.map(eventName => { | ||
return new Promise(resolve => { | ||
if (eventName instanceof Array){ | ||
this.onceAny(eventName, resolve) | ||
resolve(this.onceAny(eventName)) | ||
} | ||
@@ -289,30 +267,11 @@ else { | ||
})) | ||
.then(handlerWrapper) | ||
} | ||
/** | ||
* Prevent changes to the app configuration | ||
*/ | ||
freezeConfig () { | ||
this.config.freeze(this.loadedModules) | ||
} | ||
/** | ||
* Allow changes to the app configuration | ||
*/ | ||
unfreezeConfig () { | ||
Object.defineProperties(this, { | ||
config: { | ||
value: new lib.Configuration(this.config.unfreeze(), this.env), | ||
configurable: true | ||
} | ||
}) | ||
} | ||
/** | ||
* Create any configured paths which may not already exist. | ||
*/ | ||
createPaths () { | ||
if (this.config.main.createPaths === false) { | ||
async createPaths () { | ||
if (this.config.get('main.createPaths') === false) { | ||
this.log.warn('createPaths is disabled. Configured paths will not be created') | ||
return | ||
} | ||
@@ -327,12 +286,4 @@ return lib.Core.createDefaultPaths(this) | ||
get log () { | ||
return this.config.log.logger | ||
return this.config.get('log.logger') | ||
} | ||
/** | ||
* Expose the i18n translator on the app object. Internationalization can be | ||
* configured in config.i18n | ||
*/ | ||
get __ () { | ||
return this.translate | ||
} | ||
} |
/*eslint no-console: 0 */ | ||
'use strict' | ||
const _ = require('lodash') | ||
const merge = require('lodash.merge') | ||
const path = require('path') | ||
const joi = require('joi') | ||
const schemas = require('./schemas') | ||
const ConfigurationProxyHandler = { | ||
get (target, key, receiver) { | ||
if (Reflect.has(target, key)) return target[key] | ||
return target.get(key) | ||
}, | ||
set (target, key, value, receiver) { | ||
if (target.hasOwnProperty(key)) { | ||
target[key] = value | ||
return true | ||
} | ||
else { | ||
throw new IllegalAccessError('Cannot set properties directly on config. Use .set(key, value)') | ||
} | ||
} | ||
} | ||
module.exports = class Configuration extends Map { | ||
constructor (configTree, processEnv) { | ||
super() | ||
constructor (configTree = { }, processEnv = { }) { | ||
const config = Configuration.buildConfig(configTree) | ||
const configEntries = Object.entries(Configuration.flattenTree(config)) | ||
super(configEntries) | ||
this.modules = [ ] | ||
this.validateConfig() | ||
this.immutable = false | ||
this.env = processEnv | ||
this.tree = Configuration.buildConfig(configTree, processEnv.NODE_ENV) | ||
Configuration.validateConfig(this.tree) | ||
this.get = this.get.bind(this) | ||
this.set = this.set.bind(this) | ||
this.entries = this.entries.bind(this) | ||
this.has = this.has.bind(this) | ||
// this looks somewhat strange; I'd like to use a Proxy here, but Node 4 | ||
// does not support it. These properties will be exposed via a Proxy | ||
// for v3.0 when Node 4 support can be dropped. | ||
Object.assign(this, this.tree) | ||
return new Proxy(this, ConfigurationProxyHandler) | ||
} | ||
/** | ||
* @override | ||
*/ | ||
get (key) { | ||
return _.get(this, key) | ||
set (key, value) { | ||
if (this.immutable) { | ||
throw new TypeError('Configuration is frozen') | ||
} | ||
return super.set(key, value) | ||
} | ||
/** | ||
* @override | ||
* Prevent changes to the app configuration | ||
*/ | ||
set (key, val) { | ||
return _.set(this, key, val) | ||
freeze () { | ||
this.immutable = true | ||
} | ||
/** | ||
* @override | ||
* Allow changes to the app configuration | ||
*/ | ||
freeze (modules) { | ||
this.immutable = true | ||
this.modules = modules | ||
Configuration.freezeConfig(this, modules) | ||
unfreeze () { | ||
this.immutable = false | ||
} | ||
unfreeze () { | ||
return Configuration.unfreezeConfig(this, this.modules) | ||
static flattenTree (tree = { }) { | ||
const toReturn = { } | ||
Object.entries(tree).forEach(([ k, v ]) => { | ||
if (typeof v === 'object') { | ||
const flatObject = Configuration.flattenTree(v) | ||
Object.keys(flatObject).forEach(flatKey => { | ||
toReturn[`${k}.${flatKey}`] = flatObject[flatKey] | ||
}) | ||
} | ||
toReturn[k] = v | ||
}) | ||
return toReturn | ||
} | ||
@@ -57,3 +82,3 @@ | ||
*/ | ||
static buildConfig (initialConfig, nodeEnv) { | ||
static buildConfig (initialConfig = { }, nodeEnv) { | ||
const root = path.resolve(path.dirname(require.main.filename)) | ||
@@ -80,7 +105,6 @@ const temp = path.resolve(root, '.tmp') | ||
}, | ||
log: { }, | ||
motd: require('./motd') | ||
log: { } | ||
} | ||
const mergedConfig = _.merge(configTemplate, initialConfig, (envConfig || { })) | ||
const mergedConfig = merge(configTemplate, initialConfig, (envConfig || { })) | ||
mergedConfig.env = nodeEnv | ||
@@ -96,20 +120,13 @@ | ||
*/ | ||
static validateConfig (config) { | ||
if (!config || !config.main) { | ||
validateConfig () { | ||
if (!this.has('main')) { | ||
throw new ConfigNotDefinedError() | ||
} | ||
if (!config.log || !config.log.logger) { | ||
if (!this.has('log.logger')) { | ||
throw new LoggerNotDefinedError() | ||
} | ||
const nestedEnvs = Configuration.getNestedEnv(config) | ||
if (nestedEnvs.length) { | ||
throw new ConfigValueError('Environment configs cannot contain an "env" property') | ||
} | ||
if (config.env && config.env.env) { | ||
throw new ConfigValueError('config.env cannot contain an "env" property') | ||
} | ||
/* | ||
TODO re-enable | ||
const result = joi.validate(config, schemas.config) | ||
@@ -119,71 +136,4 @@ if (result.error) { | ||
} | ||
*/ | ||
} | ||
/** | ||
* Check to see if the user defined a property config.env[env].env | ||
*/ | ||
static getNestedEnv (config) { | ||
const env = (config && config.env) | ||
const nestedEnvs = Object.keys(env || { }).filter(key => { | ||
return !!env[key].env | ||
}) | ||
return nestedEnvs | ||
} | ||
/** | ||
* Deep freeze application config object. Exceptions are made for required | ||
* modules that are listed as dependencies in the application's | ||
* package definition (package.json). Trails takes a firm stance that | ||
* configuration should be modified only by the developer, the environment, | ||
* and the trailpack configuration phase -- never by the application itself | ||
* during runtime. | ||
* | ||
* @param config the configuration object to be frozen. | ||
* @param [pkg] the package definition to use for exceptions. optional. | ||
*/ | ||
static freezeConfig (config, modules) { | ||
_.each(config, (prop, name) => { | ||
if (!prop || typeof prop !== 'object' || prop.constructor !== Object) { | ||
return | ||
} | ||
const ignoreModule = modules.find(moduleId => require.cache[moduleId].exports === prop) | ||
if (ignoreModule) { | ||
return | ||
} | ||
Configuration.freezeConfig(prop, modules) | ||
}) | ||
Object.freeze(config) | ||
} | ||
/** | ||
* Copy the configuration into a normal, unfrozen object | ||
*/ | ||
static unfreezeConfig (config, modules) { | ||
const unfreeze = (target, source) => { | ||
const propNames = Object.getOwnPropertyNames(source) | ||
propNames.forEach(name => { | ||
const prop = source[name] | ||
if (!prop || typeof prop !== 'object' || prop.constructor !== Object) { | ||
target[name] = prop | ||
return | ||
} | ||
const ignoreModule = modules.find(moduleId => require.cache[moduleId].exports === prop) | ||
if (ignoreModule) { | ||
return | ||
} | ||
target[name] = { } | ||
unfreeze(target[name], prop) | ||
}) | ||
return target | ||
} | ||
return unfreeze({ }, config) | ||
} | ||
} |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class ApiNotDefinedError extends RangeError { | ||
@@ -4,0 +2,0 @@ constructor() { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class ConfigNotDefinedError extends RangeError { | ||
@@ -4,0 +2,0 @@ constructor() { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class ConfigValueError extends RangeError { | ||
@@ -4,0 +2,0 @@ constructor(msg) { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class GraphCompletenessError extends RangeError { | ||
@@ -4,0 +2,0 @@ constructor (pack, stageName, eventName) { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class IllegalAccessError extends Error { | ||
@@ -4,0 +2,0 @@ constructor(msg) { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class LoggerNotDefinedError extends RangeError { | ||
@@ -4,0 +2,0 @@ constructor() { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class NamespaceConflictError extends Error { | ||
@@ -4,0 +2,0 @@ constructor (key, globals) { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class PackageNotDefinedError extends RangeError { | ||
@@ -4,0 +2,0 @@ constructor() { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class TimeoutError extends Error { | ||
@@ -4,0 +2,0 @@ constructor(phase, timeout) { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
module.exports = class TrailpackError extends Error { | ||
@@ -4,0 +2,0 @@ constructor (pack, error, stage) { |
@@ -1,3 +0,1 @@ | ||
'use strict' | ||
/** | ||
@@ -4,0 +2,0 @@ * Generic validation error; commonly used to wrap joi errors, but can be |
@@ -1,10 +0,7 @@ | ||
'use strict' | ||
exports.i18n = require('./i18n') | ||
exports.Trailpack = require('./trailpack') | ||
exports.Errors = require('./errors') | ||
exports.Pathfinder = require('./pathfinder') | ||
exports.Core = require('./core') | ||
exports.Schemas = require('./schemas') | ||
exports.Pathfinder = require('./Pathfinder') | ||
exports.Core = require('./Core') | ||
exports.Configuration = require('./Configuration') | ||
//exports.ConfigProxy = require('./ConfigProxy') | ||
exports.Templates = require('./Templates') |
{ | ||
"name": "trails", | ||
"version": "2.0.2", | ||
"version": "3.0.0-pre.1", | ||
"description": "Modern Web Application Framework for Node.js", | ||
@@ -8,2 +8,4 @@ "keywords": [ | ||
"platform", | ||
"microservices", | ||
"ecosystem", | ||
"rest", | ||
@@ -21,3 +23,3 @@ "api", | ||
"test": "eslint --ignore-path .gitignore . && istanbul cover node_modules/mocha/bin/_mocha", | ||
"test-performance": "eslint . && mocha test-performance", | ||
"test-performance": "eslint --ignore-path .gitignore . && mocha test-performance", | ||
"coverage": "istanbul cover node_modules/mocha/bin/_mocha", | ||
@@ -67,28 +69,19 @@ "ci": "cd .. && ci" | ||
"dependencies": { | ||
"hoek": "^4.1.0", | ||
"i18next": "^3.4.1", | ||
"joi": "^10.2.2", | ||
"lodash": "^4.17.2", | ||
"mkdirp": "^0.5.1", | ||
"trails-controller": "^2", | ||
"trails-model": "^2", | ||
"trails-policy": "^2", | ||
"trails-service": "^2" | ||
"lodash.defaultsdeep": "^4.6.0", | ||
"lodash.isplainobject": "^4.0.6", | ||
"lodash.mapvalues": "^4.6.0", | ||
"lodash.merge": "^4.6.0", | ||
"mkdirp": "0.5.1" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^3.15.0", | ||
"eslint-config-trails": "^2.0.8", | ||
"istanbul": "^0.4.5", | ||
"eslint": "^3", | ||
"eslint-config-trails": "^3", | ||
"istanbul": "^1.1.0-alpha.1", | ||
"mocha": "^3.2.0", | ||
"pre-commit": "^1.2.2", | ||
"smokesignals": "^2.1.0", | ||
"trailpack": "^2", | ||
"winston": "^2.3.1" | ||
"pre-commit": "^1.1.3", | ||
"smokesignals": "next", | ||
"trailpack": "next", | ||
"winston": "^2.1.1" | ||
}, | ||
"bundledDependencies": [ | ||
"trails-controller", | ||
"trails-model", | ||
"trails-policy", | ||
"trails-service" | ||
], | ||
"eslintConfig": { | ||
@@ -98,4 +91,4 @@ "extends": "trails" | ||
"engines": { | ||
"node": ">= 4.0.0", | ||
"npm": ">= 2.14.2" | ||
"node": ">= 7.6.0", | ||
"npm": ">= 3.10.0" | ||
}, | ||
@@ -102,0 +95,0 @@ "publishConfig": { |
@@ -10,3 +10,3 @@ <img src="http://cdn.trailsjs.io/art/logos/trails-horiz-logo-green.svg" height="96px" title="Trails Logo" /> | ||
Trails is a modern, community-driven web application framework for node.js. It | ||
Trails is a modern, [community-driven](https://opencollective.com/trails) web application framework for node.js. It | ||
builds on the pedigree of [Rails](http://rubyonrails.org/) and [Grails](https://grails.org/) | ||
@@ -79,9 +79,14 @@ to accelerate development by adhering to a straightforward, convention-based, | ||
- Windows, Mac, and Linux | ||
- Node 4.0 and newer | ||
- Node 7.0 and newer | ||
## Resources | ||
## Documentation | ||
See [**trailsjs.io/doc**](http://trailsjs.io/doc) for complete documentation. | ||
## More Resources | ||
#### Tutorials | ||
- [Getting started](http://blog.jaumard.com/en/2016/01/05/getting-started-with-trails/) | ||
- [Create a custom Trailpack](http://blog.jaumard.com/en/2016/01/06/create-a-trailpack-for-trails/) | ||
- [Getting Started](http://blog.jaumard.com/en/2016/01/05/getting-started-with-trails/) | ||
- [Create a Custom Trailpack](http://blog.jaumard.com/en/2016/01/06/create-a-trailpack-for-trails/) | ||
- [Trails and Angular](https://cali-style.com/blog/trails-js-and-angular) | ||
@@ -93,4 +98,4 @@ #### Videos | ||
- [Live Gitter Chat](https://gitter.im/trailsjs/trails) | ||
- [Stackoverflow](http://stackoverflow.com/questions/tagged/trailsjs) | ||
- [Twitter](https://twitter.com/trailsjs) | ||
- [Trails.js Website](http://trailsjs.io/support) | ||
@@ -97,0 +102,0 @@ ## FAQ |
@@ -199,36 +199,4 @@ 'use strict' | ||
describe('#validateConfig', () => { | ||
it('should throw ConfigNotDefinedError if config or config.main is not set', () => { | ||
assert.throws(() => lib.Configuration.validateConfig(), lib.Errors.ConfigNotDefinedError) | ||
assert.throws(() => lib.Configuration.validateConfig({ }), lib.Errors.ConfigNotDefinedError) | ||
}) | ||
it('should throw ConfigValueError if an env config contains the "env" property', () => { | ||
it.skip('should throw ValidationError if main.packs contains an "undefined" trailpack', () => { | ||
const testConfig = { | ||
main: { }, | ||
log: { | ||
logger: new smokesignals.Logger('silent') | ||
}, | ||
env: { | ||
envtest: { | ||
env: 'hello' | ||
} | ||
} | ||
} | ||
assert.throws(() => lib.Configuration.validateConfig(testConfig), lib.Errors.ConfigValueError) | ||
assert.throws(() => lib.Configuration.validateConfig(testConfig), /Environment configs/) | ||
}) | ||
it('should throw ConfigValueError if config.env contains the "env" property', () => { | ||
const testConfig = { | ||
main: { }, | ||
log: { | ||
logger: new smokesignals.Logger('silent') | ||
}, | ||
env: { | ||
env: 'hello' | ||
} | ||
} | ||
assert.throws(() => lib.Configuration.validateConfig(testConfig), lib.Errors.ConfigValueError) | ||
assert.throws(() => lib.Configuration.validateConfig(testConfig), /config.env/) | ||
}) | ||
it('should throw ValidationError if main.packs contains an "undefined" trailpack', () => { | ||
const testConfig = { | ||
main: { | ||
@@ -244,113 +212,5 @@ packs: [ | ||
assert.throws(() => lib.Configuration.validateConfig(testConfig), lib.Errors.ValidationError) | ||
assert.throws(() => new lib.Configuration(testConfig), lib.Errors.ValidationError) | ||
}) | ||
}) | ||
describe('#getNestedEnv', () => { | ||
it('should return a list of envs if one contains a "env" property', () => { | ||
const testConfig = { | ||
main: { }, | ||
log: { | ||
logger: new smokesignals.Logger('silent') | ||
}, | ||
env: { | ||
envtest: { | ||
env: { | ||
invalid: true | ||
} | ||
} | ||
} | ||
} | ||
const nestedEnvs = lib.Configuration.getNestedEnv(testConfig) | ||
assert.equal(nestedEnvs[0], 'envtest') | ||
assert.equal(nestedEnvs.length, 1) | ||
}) | ||
}) | ||
describe('#freezeConfig', () => { | ||
it('should freeze nested object', () => { | ||
const o1 = { foo: { bar: 1 } } | ||
lib.Configuration.freezeConfig(o1, [ ]) | ||
assert(Object.isFrozen(o1)) | ||
assert(Object.isFrozen(o1.foo)) | ||
assert.throws(() => o1.foo = null, Error) | ||
}) | ||
it('should not freeze exernal modules required from config', () => { | ||
const o1 = { | ||
foo: require('smokesignals'), | ||
bar: 1 | ||
} | ||
lib.Configuration.freezeConfig(o1, [ require.resolve('smokesignals') ]) | ||
assert.throws(() => o1.bar = null, Error) | ||
o1.foo.x = 1 | ||
assert.equal(o1.foo.x, 1) | ||
}) | ||
// https://bugs.chromium.org/p/v8/issues/detail?id=4460 | ||
if (/^(v4)|(v5)/.test(process.version)) { | ||
it('v8 issue 4460 exists in node v4, v5 series (cannot naively freeze Int8Aray)', () => { | ||
assert.throws(() => Object.freeze(new Int8Array()), TypeError) | ||
//assert.throws(() => Object.freeze(new Buffer([1,2,3])), TypeError) | ||
//assert.throws(() => Object.freeze(new DataView()), TypeError) | ||
}) | ||
} | ||
else { | ||
it('v8 issue 4460 is resolved (node 6 and newer)', () => { | ||
assert(true) | ||
}) | ||
} | ||
it('should freeze objects containing unfreezable types without error', () => { | ||
const o1 = { | ||
typedArray: new Int8Array(), | ||
buffer: new Buffer([ 1,2,3 ]), | ||
fun: function () { } | ||
} | ||
lib.Configuration.freezeConfig(o1, [ ]) | ||
assert(o1.typedArray) | ||
assert(Buffer.isBuffer(o1.buffer)) | ||
assert(o1.fun) | ||
}) | ||
}) | ||
describe('#unfreezeConfig', () => { | ||
it('should unfreeze shallow config object', () => { | ||
const app = { | ||
config: { | ||
a: 1, | ||
foo: 'bar' | ||
} | ||
} | ||
lib.Configuration.freezeConfig(app.config, [ ]) | ||
assert.throws(() => app.config.a = 2, Error) | ||
app.config = lib.Configuration.unfreezeConfig(app.config, [ ]) | ||
app.config.a = 2 | ||
assert.equal(app.config.a, 2) | ||
}) | ||
it('should unfreeze deep config object', () => { | ||
const app = { | ||
config: { | ||
main: { | ||
paths: { | ||
root: 'rootpath', | ||
temp: 'temppath' | ||
}, | ||
foo: 1 | ||
} | ||
} | ||
} | ||
lib.Configuration.freezeConfig(app.config, [ ]) | ||
assert.throws(() => app.config.main.paths.root = 'newrootpath', Error) | ||
app.config = lib.Configuration.unfreezeConfig(app.config, [ ]) | ||
app.config.main.paths.root = 'newrootpath' | ||
assert.equal(app.config.main.paths.root, 'newrootpath') | ||
assert.equal(app.config.main.paths.temp, 'temppath') | ||
assert.equal(app.config.main.foo, 1) | ||
}) | ||
}) | ||
describe('#get', () => { | ||
@@ -381,3 +241,3 @@ it('should return nested config value if it exists', () => { | ||
assert.equal(config.get('customObject.testValue'), 'test') | ||
assert.equal(config.customObject.testValue, 'test') | ||
assert.equal(config.get('customObject.testValue'), 'test') | ||
}) | ||
@@ -387,12 +247,28 @@ it('should set the value of a new, nested leaf node with no pre-existing path', () => { | ||
assert(!config.foo) | ||
assert(!config.get('foo')) | ||
config.set('foo.bar.new.path', 'test') | ||
assert.equal(config.get('foo.bar.new.path'), 'test') | ||
assert.equal(config.foo.bar.new.path, 'test') | ||
assert(_.isPlainObject(config.foo)) | ||
assert(_.isPlainObject(config.foo.bar)) | ||
assert(_.isPlainObject(config.foo.bar.new)) | ||
}) | ||
}) | ||
describe('#flattenTree', () => { | ||
it('test', () => { | ||
const obj = lib.Configuration.flattenTree({ | ||
main: { | ||
packs: [ | ||
1,2,3 | ||
] | ||
}, | ||
settings: { | ||
foo: 'bar', | ||
baz: { | ||
yes: true | ||
} | ||
} | ||
}) | ||
assert(obj['main.packs.1']) | ||
assert.equal(obj['settings.foo'], 'bar') | ||
}) | ||
}) | ||
}) |
'use strict' | ||
const path = require('path') | ||
const assert = require('assert') | ||
@@ -47,17 +46,2 @@ const _ = require('lodash') | ||
describe('#getExternalModules', () => { | ||
const rmf = require.main.filename | ||
beforeEach(() => { | ||
require.main.filename = path.resolve(__dirname, '..', '..', 'index.js') | ||
}) | ||
afterEach(() => { | ||
require.main.filename = rmf | ||
}) | ||
it('should return external modules', () => { | ||
const modules = lib.Core.getExternalModules() | ||
assert.notEqual(modules.indexOf(require.resolve('trailpack')), -1) | ||
}) | ||
}) | ||
describe('#assignGlobals', () => { | ||
@@ -64,0 +48,0 @@ it('should assign values to the global namespace', () => { |
@@ -83,3 +83,3 @@ 'use strict' | ||
describe('#message', () => { | ||
it('should specifiy missing/undefined trailpacks', () => { | ||
it.skip('should specifiy missing/undefined trailpacks', () => { | ||
const testConfig = { | ||
@@ -86,0 +86,0 @@ main: { |
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
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
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
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
6
124
17
104300
86
2741
1
2
+ Addedlodash.defaultsdeep@^4.6.0
+ Addedlodash.isplainobject@^4.0.6
+ Addedlodash.mapvalues@^4.6.0
+ Addedlodash.merge@^4.6.0
+ Addedlodash.defaultsdeep@4.6.1(transitive)
+ Addedlodash.isplainobject@4.0.6(transitive)
+ Addedlodash.mapvalues@4.6.0(transitive)
+ Addedlodash.merge@4.6.2(transitive)
+ Addedminimist@0.0.8(transitive)
+ Addedmkdirp@0.5.1(transitive)
- Removedhoek@^4.1.0
- Removedi18next@^3.4.1
- Removedlodash@^4.17.2
- Removedtrails-controller@^2
- Removedtrails-model@^2
- Removedtrails-policy@^2
- Removedtrails-service@^2
- Removedi18next@3.5.2(transitive)
- Removedlodash@4.17.21(transitive)
- Removedminimist@1.2.8(transitive)
- Removedmkdirp@0.5.6(transitive)
Updatedmkdirp@0.5.1