Comparing version 2.1.1 to 2.1.2
2.2.0 / 2017-02-27 | ||
================== | ||
* fix: improve getPathName (#62) | ||
* feat: FileLoader support caseStyle (#59) | ||
* fix: improve require es module (#61) | ||
2.1.1 / 2017-02-17 | ||
@@ -3,0 +10,0 @@ ================== |
@@ -20,2 +20,3 @@ 'use strict'; | ||
const ROUTER = Symbol('EggCore#router'); | ||
const EGG_LOADER = Symbol.for('egg#loader'); | ||
@@ -45,3 +46,4 @@ class EggCore extends KoaApplication { | ||
/** | ||
* @member {Object} EggCore#options | ||
* @member {Object} EggCore#_options | ||
* @private | ||
* @since 1.0.0 | ||
@@ -54,2 +56,3 @@ */ | ||
* @member {Logger} EggCore#console | ||
* @private | ||
* @since 1.0.0 | ||
@@ -63,5 +66,2 @@ */ | ||
/** | ||
* BaseContextClass is a base class extended by classes(like service and controller), | ||
* it will be instantiated every request, and assign ctx and app to this. | ||
* | ||
* @member {BaseContextClass} EggCore#BaseContextClass | ||
@@ -72,21 +72,42 @@ * @since 1.0.0 | ||
/** | ||
* return base controller | ||
* Base controller to be extended by controller in `app.controller` | ||
* @class Controller | ||
* @extends BaseContextClass | ||
* @example | ||
* class UserController extends app.Controller {} | ||
*/ | ||
const Controller = this.BaseContextClass; | ||
/** | ||
* Retreive base controller | ||
* @member {Controller} EggCore#Controller | ||
* @since 1.0.0 | ||
*/ | ||
this.Controller = BaseContextClass; | ||
this.Controller = Controller; | ||
/** | ||
* return base service | ||
* Base service to be extended by services in `app.service` | ||
* @class Service | ||
* @extends BaseContextClass | ||
* @example | ||
* class UserService extends app.Service {} | ||
*/ | ||
const Service = this.BaseContextClass; | ||
/** | ||
* Retreive base service | ||
* @member {Service} EggCore#Service | ||
* @since 1.0.0 | ||
*/ | ||
this.Service = this.BaseContextClass; | ||
this.Service = Service; | ||
/** | ||
* The loader instance, the default class is {@link EggLoader}. | ||
* If you want define | ||
* @member {EggLoader} EggCore#loader | ||
* @since 1.0.0 | ||
*/ | ||
const Loader = this[Symbol.for('egg#loader')]; | ||
const Loader = this[EGG_LOADER]; | ||
assert(Loader, 'Symbol.for(\'egg#loader\') is required'); | ||
@@ -100,3 +121,2 @@ this.loader = new Loader({ | ||
this._initReady(); | ||
@@ -106,5 +126,4 @@ } | ||
/** | ||
* override koa's app.use | ||
* support async function | ||
* @param {Function} fn middleware | ||
* override koa's app.use, support async function | ||
* @param {Function} fn - middleware | ||
* @return {Application} app | ||
@@ -121,3 +140,3 @@ * @since 1.0.0 | ||
/** | ||
* alias to options.type | ||
* Whether `application` or `agent` | ||
* @member {String} | ||
@@ -131,4 +150,5 @@ * @since 1.0.0 | ||
/** | ||
* alias to options.baseDir | ||
* The current directory of application | ||
* @member {String} | ||
* @see {@link AppInfo#baseDir} | ||
* @since 1.0.0 | ||
@@ -141,4 +161,4 @@ */ | ||
/** | ||
* Alias to {@link https://npmjs.com/package/depd} | ||
* @member {Function} | ||
* @see https://npmjs.com/package/depd | ||
* @since 1.0.0 | ||
@@ -155,4 +175,5 @@ */ | ||
/** | ||
* name in package.json | ||
* The name of application | ||
* @member {String} | ||
* @see {@link AppInfo#name} | ||
* @since 1.0.0 | ||
@@ -165,3 +186,3 @@ */ | ||
/** | ||
* alias to {EggCore#loader} | ||
* Retreive enabled plugins | ||
* @member {Object} | ||
@@ -175,3 +196,3 @@ * @since 1.0.0 | ||
/** | ||
* alias to {EggCore#loader} | ||
* The configuration of application | ||
* @member {Config} | ||
@@ -185,3 +206,3 @@ * @since 1.0.0 | ||
/** | ||
* excute scope after loaded and before app start | ||
* Excute scope after loaded and before app start | ||
* | ||
@@ -208,3 +229,3 @@ * @param {Function|GeneratorFunction|AsyncFunction} scope function will excute before app start | ||
/** | ||
* close all, it wil close | ||
* Close all, it wil close | ||
* - callbacks registered by beforeClose | ||
@@ -216,3 +237,2 @@ * - emit `close` event | ||
* It will also reject after following call. | ||
* @member {Function} | ||
* @return {Promise} promise | ||
@@ -241,5 +261,4 @@ * @since 1.0.0 | ||
/** | ||
* register a function that will be called when app close | ||
* Register a function that will be called when app close | ||
* @param {Function} fn - the function that can be generator function or async function | ||
* @return {Boolean} status - whether registered or not | ||
*/ | ||
@@ -249,3 +268,2 @@ beforeClose(fn) { | ||
this[CLOSESET].add(fn); | ||
return true; | ||
} | ||
@@ -260,4 +278,11 @@ | ||
* register an callback function that will be invoked when application is ready. | ||
* @member {Function} EggCore#ready | ||
* @method {Function} EggCore#ready | ||
* @see https://github.com/node-modules/ready | ||
* @since 1.0.0 | ||
* @example | ||
* const app = new Application(...); | ||
* app.ready(err => { | ||
* if (err) throw err; | ||
* console.log('done'); | ||
* }); | ||
*/ | ||
@@ -270,9 +295,9 @@ | ||
* It will log when the callback is not invoked after 10s | ||
* @member {Function} EggCore#readyCallback | ||
* | ||
* Recommend to use {@link EggCore#beforeStart} | ||
* @method {Function} EggCore#readyCallback | ||
* @since 1.0.0 | ||
* @example | ||
* ```js | ||
* const done = app.readyCallback('mysql'); | ||
* mysql.ready(done); | ||
* ``` | ||
*/ | ||
@@ -293,2 +318,3 @@ require('ready-callback')({ timeout: 10000 }).mixin(this); | ||
* @member {Router} EggCore#router | ||
* @since 1.0.0 | ||
*/ | ||
@@ -319,2 +345,6 @@ get router() { | ||
} | ||
get [EGG_LOADER]() { | ||
return require('./loader/egg_loader'); | ||
} | ||
} | ||
@@ -334,2 +364,3 @@ | ||
const _ = new Error(); | ||
/* istanbul ignore next */ | ||
const line = _.stack.split('\n')[3] || ''; | ||
@@ -336,0 +367,0 @@ const parsed = line.match(/\((.*?)\)/); |
@@ -36,4 +36,14 @@ 'use strict'; | ||
/** | ||
* Same as {@link FileLoader}, but it will attach file to `inject[fieldClass]`. The exports will be lazy loaded, such as `ctx.group.repository`. | ||
* @extends FileLoader | ||
* @since 1.0.0 | ||
*/ | ||
class ContextLoader extends FileLoader { | ||
/** | ||
* @constructor | ||
* @param {Object} options - options same as {@link FileLoader} | ||
* @param {String} options.fieldClass - determine the field name of inject object. | ||
*/ | ||
constructor(options) { | ||
@@ -40,0 +50,0 @@ assert(options.property, 'options.property is required'); |
@@ -11,4 +11,4 @@ 'use strict'; | ||
const utils = require('../utils'); | ||
const EggCore = require('../egg'); | ||
class EggLoader { | ||
@@ -20,3 +20,3 @@ | ||
* @param {String} options.baseDir - the directory of application | ||
* @param {Object} options.app - Application instance | ||
* @param {EggCore} options.app - Application instance | ||
* @param {Logger} options.logger - logger | ||
@@ -37,2 +37,3 @@ * @param {Object} [options.plugins] - custom plugins | ||
* @member {Object} EggLoader#pkg | ||
* @see {@link AppInfo#pkg} | ||
* @since 1.0.0 | ||
@@ -43,5 +44,25 @@ */ | ||
/** | ||
* All framework directories. | ||
* | ||
* You can extend Application of egg, the entrypoint is options.app, | ||
* | ||
* loader will find all directories from the prototype of Application, | ||
* you should define `Symbol.for('egg#eggPath')` property. | ||
* | ||
* ``` | ||
* // lib/example.js | ||
* const egg = require('egg'); | ||
* class ExampleApplication extends egg.Application { | ||
* constructor(options) { | ||
* super(options); | ||
* } | ||
* | ||
* get [Symbol.for('egg#eggPath')]() { | ||
* return path.join(__dirname, '..'); | ||
* } | ||
* } | ||
* ``` | ||
* @member {Array} EggLoader#eggPaths | ||
* @see EggLoader#getEggPaths | ||
* @since 1.0.0 | ||
* @see EggLoader#getEggPaths | ||
*/ | ||
@@ -53,4 +74,4 @@ this.eggPaths = this.getEggPaths(); | ||
* @member {String} EggLoader#serverEnv | ||
* @see AppInfo#env | ||
* @since 1.0.0 | ||
* @see EggLoader#getServerEnv | ||
*/ | ||
@@ -61,5 +82,4 @@ this.serverEnv = this.getServerEnv(); | ||
/** | ||
* @member {String} EggLoader#appInfo | ||
* @member {AppInfo} EggLoader#appInfo | ||
* @since 1.0.0 | ||
* @see EggLoader#getServerEnv | ||
*/ | ||
@@ -70,17 +90,6 @@ this.appInfo = this.getAppInfo(); | ||
/** | ||
* Get environment of Egg, **it's not NODE_ENV** | ||
* | ||
* 1. from `$baseDir/config/env` | ||
* 2. from EGG_SERVER_ENV | ||
* 3. from NODE_ENV | ||
* | ||
* env | description | ||
* --- | --- | ||
* default | default environment | ||
* test | system integration testing | ||
* prod | production | ||
* local | local on your own computer | ||
* unittest | unit test | ||
* | ||
* Get {@link AppInfo#env} | ||
* @return {String} env | ||
* @see AppInfo#env | ||
* @private | ||
* @since 1.0.0 | ||
@@ -114,5 +123,5 @@ */ | ||
/** | ||
* Get appname from pkg.name | ||
* | ||
* Get {@link AppInfo#name} | ||
* @return {String} appname | ||
* @private | ||
* @since 1.0.0 | ||
@@ -131,3 +140,3 @@ */ | ||
* Get app info | ||
* @return {String} appInfo | ||
* @return {AppInfo} appInfo | ||
* @since 1.0.0 | ||
@@ -139,9 +148,59 @@ */ | ||
const baseDir = this.options.baseDir; | ||
/** | ||
* Meta infomation of the application | ||
* @class AppInfo | ||
*/ | ||
return { | ||
/** | ||
* The name of the application, retreive from the name property in `package.json`. | ||
* @member {String} AppInfo#name | ||
*/ | ||
name: this.getAppname(), | ||
/** | ||
* The current directory, where the application code is. | ||
* @member {String} AppInfo#baseDir | ||
*/ | ||
baseDir, | ||
/** | ||
* The environment of the application, **it's not NODE_ENV** | ||
* | ||
* 1. from `$baseDir/config/env` | ||
* 2. from EGG_SERVER_ENV | ||
* 3. from NODE_ENV | ||
* | ||
* env | description | ||
* --- | --- | ||
* test | system integration testing | ||
* prod | production | ||
* local | local on your own computer | ||
* unittest | unit test | ||
* | ||
* @member {String} AppInfo#env | ||
* @see https://eggjs.org/zh-cn/basics/env.html | ||
*/ | ||
env, | ||
/** | ||
* The use directory, same as `process.env.HOME` | ||
* @member {String} AppInfo#HOME | ||
*/ | ||
HOME: home, | ||
/** | ||
* parsed from `package.json` | ||
* @member {Object} AppInfo#pkg | ||
*/ | ||
pkg: this.pkg, | ||
// keep root directory in baseDir when local and unittest | ||
/** | ||
* The directory whether is baseDir or HOME depend on env. | ||
* it's good for test when you want to write some file to HOME, | ||
* but don't want to write to the real directory, | ||
* so use root to write file to baseDir instead of HOME when unitest. | ||
* keep root directory in baseDir when local and unittest | ||
* @member {String} AppInfo#root | ||
*/ | ||
root: env === 'local' || env === 'unittest' ? baseDir : home, | ||
@@ -152,30 +211,15 @@ }; | ||
/** | ||
* Get all framework directories. | ||
* | ||
* You can extend Application of egg, the entrypoint is options.app, | ||
* | ||
* loader will find all directories from the prototype of Application, | ||
* you should define `Symbol.for('egg#eggPath')` property. | ||
* | ||
* ``` | ||
* // lib/xx.js | ||
* const egg = require('egg'); | ||
* class XxApplication extends egg.Application { | ||
* constructor(options) { | ||
* super(options); | ||
* } | ||
* | ||
* get [Symbol.for('egg#eggPath')]() { | ||
* return path.join(__dirname, '..'); | ||
* } | ||
* } | ||
* ``` | ||
* | ||
* Get {@link EggLoader#eggPaths} | ||
* @return {Array} framework directories | ||
* @see {@link EggLoader#eggPaths} | ||
* @private | ||
* @since 1.0.0 | ||
*/ | ||
getEggPaths() { | ||
// avoid require recursively | ||
const EggCore = require('../egg'); | ||
const eggPaths = []; | ||
let proto = this.app; | ||
// Loop for the prototype chain | ||
@@ -268,3 +312,3 @@ while (proto) { | ||
// 应用目录 | ||
// application | ||
dirs.push({ | ||
@@ -279,2 +323,9 @@ path: this.options.baseDir, | ||
/** | ||
* Load files using {@link FileLoader}, inject to {@link Application} | ||
* @param {String|Array} directory - see {@link FileLoader} | ||
* @param {String} property - see {@link FileLoader} | ||
* @param {Object} opt - see {@link FileLoader} | ||
* @since 1.0.0 | ||
*/ | ||
loadToApp(directory, property, opt) { | ||
@@ -290,2 +341,9 @@ const target = this.app[property] = {}; | ||
/** | ||
* Load files using {@link ContextLoader} | ||
* @param {String|Array} directory - see {@link ContextLoader} | ||
* @param {String} property - see {@link ContextLoader} | ||
* @param {Object} opt - see {@link ContextLoader} | ||
* @since 1.0.0 | ||
*/ | ||
loadToContext(directory, property, opt) { | ||
@@ -300,2 +358,6 @@ opt = Object.assign({}, { | ||
/** | ||
* @member {FileLoader} EggLoader#FileLoader | ||
* @since 1.0.0 | ||
*/ | ||
get FileLoader() { | ||
@@ -305,2 +367,6 @@ return FileLoader; | ||
/** | ||
* @member {ContextLoader} EggLoader#ContextLoader | ||
* @since 1.0.0 | ||
*/ | ||
get ContextLoader() { | ||
@@ -307,0 +373,0 @@ return ContextLoader; |
@@ -9,2 +9,3 @@ 'use strict'; | ||
const is = require('is-type-of'); | ||
const deprecate = require('depd')('egg'); | ||
const utils = require('../utils'); | ||
@@ -19,2 +20,3 @@ const FULLPATH = Symbol('EGG_LOADER_ITEM_FULLPATH'); | ||
lowercaseFirst: false, | ||
caseStyle: 'camel', | ||
initializer: null, | ||
@@ -26,4 +28,20 @@ call: true, | ||
/** | ||
* Load files from directory to target object. | ||
* @since 1.0.0 | ||
*/ | ||
class FileLoader { | ||
/** | ||
* @constructor | ||
* @param {Object} options - options | ||
* @param {String|Array} options.directory - directories to be loaded | ||
* @param {Object} options.target - attach the target object from loaded files | ||
* @param {String} options.ignore - ignore the files when load, support glob | ||
* @param {Function} options.initializer - custom file exports, receive two parameters, first is the inject object, second is an `options` object that contain `path` | ||
* @param {Boolean} options.call - determine whether invoke when exports is function | ||
* @param {Boolean} options.override - determine whether override the property when get the same name | ||
* @param {Object} options.inject - an object that be the argument when invoke the function | ||
* @param {String|Function} options.caseStyle - set property's case when converting a filepath to property list. | ||
*/ | ||
constructor(options) { | ||
@@ -33,4 +51,16 @@ assert(options.directory, 'options.directory is required'); | ||
this.options = Object.assign({}, defaults, options); | ||
// compatible old options _lowercaseFirst_ | ||
if (this.options.lowercaseFirst === true) { | ||
deprecate('lowercaseFirst is deprecated, use caseStyle instead'); | ||
this.options.caseStyle = 'lower'; | ||
} | ||
} | ||
/** | ||
* attach items to target object. Mapping the directory to properties. | ||
* `app/controller/group/repository.js` => `target.group.repository` | ||
* @return {Object} target | ||
* @since 1.0.0 | ||
*/ | ||
load() { | ||
@@ -66,2 +96,28 @@ const items = this.parse(); | ||
/** | ||
* Parse files from given directories, then return an items list, each item contains properties and exports. | ||
* | ||
* For exmple, parse `app/controller/group/repository.js` | ||
* | ||
* ``` | ||
* module.exports = app => { | ||
* return class RepositoryController extends app.Controller {}; | ||
* } | ||
* ``` | ||
* | ||
* It returns a item | ||
* | ||
* ``` | ||
* { | ||
* properties: [ 'group', 'repository' ], | ||
* exports: app => { ... }, | ||
* } | ||
* ``` | ||
* | ||
* `Properties` is an array that contains the directory of a filepath. | ||
* | ||
* `Exports` depends on type, if exports is a function, it will be called. if initializer is specified, it will be called with exports for customizing. | ||
* @return {Array} items | ||
* @since 1.0.0 | ||
*/ | ||
parse() { | ||
@@ -84,11 +140,13 @@ const files = [ '**/*.js' ]; | ||
const fullpath = path.join(directory, filepath); | ||
if (!fs.statSync(fullpath).isFile()) { | ||
continue; | ||
} | ||
const properties = getProperties(filepath, this.options.lowercaseFirst); | ||
const exports = getExports(fullpath, this.options.initializer, this.options.call, this.options.inject); | ||
if (!fs.statSync(fullpath).isFile()) continue; | ||
// get properties | ||
// app/service/foo/bar.js => [ 'foo', 'bar' ] | ||
const properties = getProperties(filepath, this.options); | ||
// app/service/foo/bar.js => service.foo.bar | ||
const pathName = directory.split(/\/|\\/).slice(-1) + '.' + properties.join('.'); | ||
// get exports from the file | ||
const exports = getExports(fullpath, this.options, pathName); | ||
if (exports == null) continue; | ||
if (this.options.inject && is.class(exports)) { | ||
exports.prototype.pathName = utils.getPathName(fullpath, this.options.inject); | ||
} | ||
if (is.class(exports)) exports.prototype.pathName = pathName; | ||
items.push({ fullpath, properties, exports }); | ||
@@ -108,17 +166,13 @@ debug('parse %s, properties %j, export %j', fullpath, properties, exports); | ||
// convert file path to an array of properties | ||
// a/b/c.js => ['a', 'b', 'c'] | ||
function getProperties(filepath, lowercaseFirst) { | ||
return filepath | ||
.replace('.js', '') | ||
.split('/') | ||
.map(property => { | ||
if (!/^[a-z][a-z0-9_-]*$/i.test(property)) { | ||
throw new Error(`${property} is not match 'a-z0-9_-' in ${filepath}`); | ||
} | ||
let result = property.replace(/[_-][a-z]/ig, s => s.substring(1).toUpperCase()); | ||
if (lowercaseFirst) { | ||
result = result[0].toLowerCase() + result.substring(1); | ||
} | ||
function getProperties(filepath, { caseStyle }) { | ||
// if caseStyle is function, return the result of function | ||
if (is.function(caseStyle)) { | ||
const result = caseStyle(filepath); | ||
assert(is.array(result), `caseStyle expect an array, but got ${result}`); | ||
return result; | ||
}); | ||
} | ||
// use default camelize | ||
return defaultCamelize(filepath, caseStyle); | ||
} | ||
@@ -128,3 +182,3 @@ | ||
// If exports is null/undefined, it will be ignored | ||
function getExports(fullpath, initializer, isCall, inject) { | ||
function getExports(fullpath, { initializer, call, inject }, pathName) { | ||
let exports = utils.loadFile(fullpath); | ||
@@ -134,3 +188,3 @@ | ||
if (initializer) { | ||
exports = initializer(exports, { path: fullpath }); | ||
exports = initializer(exports, { path: fullpath, pathName }); | ||
} | ||
@@ -152,3 +206,3 @@ | ||
// } | ||
if (isCall && is.function(exports)) { | ||
if (call && is.function(exports)) { | ||
exports = exports(inject); | ||
@@ -163,1 +217,30 @@ if (exports != null) { | ||
} | ||
function defaultCamelize(filepath, caseStyle) { | ||
const properties = filepath.replace(/\.js$/, '').split('/'); | ||
return properties.map(property => { | ||
if (!/^[a-z][a-z0-9_-]*$/i.test(property)) { | ||
throw new Error(`${property} is not match 'a-z0-9_-' in ${filepath}`); | ||
} | ||
// use default camelize, will capitalize the first letter | ||
// foo_bar.js > FooBar | ||
// fooBar.js > FooBar | ||
// FooBar.js > FooBar | ||
// FooBar.js > FooBar | ||
// FooBar.js > fooBar (if lowercaseFirst is true) | ||
property = property.replace(/[_-][a-z]/ig, s => s.substring(1).toUpperCase()); | ||
let first = property[0]; | ||
switch (caseStyle) { | ||
case 'lower': | ||
first = first.toLowerCase(); | ||
break; | ||
case 'upper': | ||
first = first.toUpperCase(); | ||
break; | ||
case 'camel': | ||
default: | ||
} | ||
return first + property.substring(1); | ||
}); | ||
} |
@@ -6,3 +6,2 @@ 'use strict'; | ||
const utility = require('utility'); | ||
const utils = require('../../utils'); | ||
@@ -18,3 +17,3 @@ module.exports = { | ||
opt = Object.assign({ | ||
lowercaseFirst: true, | ||
caseStyle: 'lower', | ||
initializer: (obj, opt) => { | ||
@@ -36,3 +35,3 @@ // return class if it exports a function | ||
if (is.class(obj)) { | ||
obj.prototype.pathName = utils.getPathName(opt.path, this.app); | ||
obj.prototype.pathName = opt.pathName; | ||
return wrapClass(obj); | ||
@@ -39,0 +38,0 @@ } |
'use strict'; | ||
const path = require('path'); | ||
const interopRequire = require('interop-require'); | ||
const debug = require('debug')('egg-core:extend'); | ||
@@ -88,32 +87,21 @@ const utils = require('../../utils'); | ||
let ext; | ||
try { | ||
ext = interopRequire(filepath); | ||
} catch (err) { | ||
err.message = `[egg-core] load file ${require.resolve(filepath)} error: ${err.message}`; | ||
throw err; | ||
} | ||
const ext = utils.loadFile(filepath); | ||
const names = Object.getOwnPropertyNames(ext) | ||
const properties = Object.getOwnPropertyNames(ext) | ||
.concat(Object.getOwnPropertySymbols(ext)); | ||
if (names.length === 0) { | ||
continue; | ||
} | ||
for (const name of names) { | ||
if (mergeRecord.has(name)) { | ||
for (const property of properties) { | ||
if (mergeRecord.has(property)) { | ||
debug('Property: "%s" already exists in "%s",it will be redefined by "%s"', | ||
name, mergeRecord.get(name), filepath); | ||
property, mergeRecord.get(property), filepath); | ||
} | ||
// Copy descriptor | ||
const descriptor = Object.getOwnPropertyDescriptor(ext, name); | ||
Object.defineProperty(proto, name, descriptor); | ||
mergeRecord.set(name, filepath); | ||
const descriptor = Object.getOwnPropertyDescriptor(ext, property); | ||
Object.defineProperty(proto, property, descriptor); | ||
mergeRecord.set(property, filepath); | ||
} | ||
debug('merge %j to %s from %s', Object.keys(ext), name, filepath); | ||
} | ||
}, | ||
}; |
@@ -39,3 +39,3 @@ 'use strict'; | ||
override: true, | ||
lowercaseFirst: true, | ||
caseStyle: 'lower', | ||
}, opt); | ||
@@ -42,0 +42,0 @@ const middlewarePaths = this.getLoadUnits().map(unit => join(unit.path, 'app/middleware')); |
@@ -21,3 +21,3 @@ 'use strict'; | ||
call: true, | ||
lowercaseFirst: true, | ||
caseStyle: 'lower', | ||
fieldClass: 'serviceClasses', | ||
@@ -24,0 +24,0 @@ }, opt); |
'use strict'; | ||
/** | ||
* BaseContextClass is a base class that can be extended, | ||
* it's instantiated in context level, | ||
* {@link Helper}, {@link Service} is extending it. | ||
*/ | ||
class BaseContextClass { | ||
/** | ||
* @constructor | ||
* @param {Context} ctx - context instance | ||
* @since 1.0.0 | ||
*/ | ||
constructor(ctx) { | ||
/** | ||
* @member {Context} BaseContextClass#ctx | ||
* @since 1.0.0 | ||
*/ | ||
this.ctx = ctx; | ||
/** | ||
* @member {Application} BaseContextClass#app | ||
* @since 1.0.0 | ||
*/ | ||
this.app = ctx.app; | ||
/** | ||
* @member {Config} BaseContextClass#config | ||
* @since 1.0.0 | ||
*/ | ||
this.config = ctx.app.config; | ||
/** | ||
* @member {Service} BaseContextClass#service | ||
* @since 1.0.0 | ||
*/ | ||
this.service = ctx.service; | ||
@@ -9,0 +36,0 @@ } |
'use strict'; | ||
const co = require('co'); | ||
const path = require('path'); | ||
const interopRequire = require('interop-require'); | ||
const homedir = require('node-homedir'); | ||
@@ -13,10 +11,12 @@ const is = require('is-type-of'); | ||
loadFile(filepath) { | ||
let exports; | ||
try { | ||
exports = interopRequire(filepath); | ||
const obj = require(filepath); | ||
if (!obj) return obj; | ||
// it's es module | ||
if (obj.__esModule) return 'default' in obj ? obj.default : obj; | ||
return obj; | ||
} catch (err) { | ||
err.message = 'load file: ' + filepath + ', error: ' + err.message; | ||
err.message = '[egg-core] load file: ' + filepath + ', error: ' + err.message; | ||
throw err; | ||
} | ||
return exports; | ||
}, | ||
@@ -40,12 +40,2 @@ | ||
// rename fullpath | ||
// /path/to/app/controller/admin/config.js => controller.admin.config | ||
getPathName(fullpath, app) { | ||
const baseDir = app.loader.appInfo.baseDir; | ||
return fullpath | ||
.replace(path.join(baseDir, 'app/'), '') | ||
.replace(/\/|\\/g, '.') | ||
.replace(/\.js$/, ''); | ||
}, | ||
* callFn(fn, args) { | ||
@@ -52,0 +42,0 @@ args = args || []; |
@@ -7,2 +7,3 @@ 'use strict'; | ||
const inflection = require('inflection'); | ||
const assert = require('assert'); | ||
const methods = require('./index').methods; | ||
@@ -51,2 +52,5 @@ const utils = require('./index'); | ||
/** | ||
* Extend {@link https://github.com/alexmingoia/koa-router} | ||
*/ | ||
class Router extends KoaRouter { | ||
@@ -134,2 +138,3 @@ | ||
* @return {Router} return route object. | ||
* @since 1.0.0 | ||
*/ | ||
@@ -187,51 +192,52 @@ resources(...args) { | ||
* @return {String} url by path name and query params. | ||
* @since 1.0.0 | ||
*/ | ||
url(name, params) { | ||
const route = this.route(name); | ||
if (!route) return ''; | ||
if (route) { | ||
const args = params; | ||
let url = route.path || route.regexp.source; | ||
const args = params; | ||
let url = route.path; | ||
const queries = []; | ||
if (typeof args === 'object' && args !== null) { | ||
const replacedParams = []; | ||
url = url.replace(/:([a-zA-Z_]\w*)/g, function($0, key) { | ||
if (utility.has(args, key)) { | ||
const values = args[key]; | ||
replacedParams.push(key); | ||
return utility.encodeURIComponent(Array.isArray(values) ? values[0] : values); | ||
} | ||
return $0; | ||
}); | ||
for (const key in args) { | ||
if (replacedParams.indexOf(key) !== -1) { | ||
continue; | ||
} | ||
assert(!is.regExp(url), `Can't get the url for regExp ${url} for by name '${name}'`); | ||
const queries = []; | ||
if (typeof args === 'object' && args !== null) { | ||
const replacedParams = []; | ||
url = url.replace(/:([a-zA-Z_]\w*)/g, function($0, key) { | ||
if (utility.has(args, key)) { | ||
const values = args[key]; | ||
const encodedKey = utility.encodeURIComponent(key); | ||
if (Array.isArray(values)) { | ||
for (const val of values) { | ||
queries.push(`${encodedKey}=${utility.encodeURIComponent(val)}`); | ||
} | ||
} else { | ||
queries.push(`${encodedKey}=${utility.encodeURIComponent(values)}`); | ||
} | ||
replacedParams.push(key); | ||
return utility.encodeURIComponent(Array.isArray(values) ? values[0] : values); | ||
} | ||
} | ||
return $0; | ||
}); | ||
if (queries.length > 0) { | ||
const queryStr = queries.join('&'); | ||
if (url.indexOf('?') === -1) { | ||
url = `${url}?${queryStr}`; | ||
for (const key in args) { | ||
if (replacedParams.indexOf(key) !== -1) { | ||
continue; | ||
} | ||
const values = args[key]; | ||
const encodedKey = utility.encodeURIComponent(key); | ||
if (Array.isArray(values)) { | ||
for (const val of values) { | ||
queries.push(`${encodedKey}=${utility.encodeURIComponent(val)}`); | ||
} | ||
} else { | ||
url = `${url}&${queryStr}`; | ||
queries.push(`${encodedKey}=${utility.encodeURIComponent(values)}`); | ||
} | ||
} | ||
} | ||
return url; | ||
if (queries.length > 0) { | ||
const queryStr = queries.join('&'); | ||
if (url.indexOf('?') === -1) { | ||
url = `${url}?${queryStr}`; | ||
} else { | ||
url = `${url}&${queryStr}`; | ||
} | ||
} | ||
return ''; | ||
return url; | ||
} | ||
@@ -257,3 +263,3 @@ | ||
let middlewares; | ||
if (args.length >= 3 && is.string(args[1])) { | ||
if (args.length >= 3 && (is.string(args[1]) || is.regExp(args[1]))) { | ||
// app.get(name, url, [...middleware], controller) | ||
@@ -260,0 +266,0 @@ prefix = args.slice(0, 2); |
{ | ||
"name": "egg-core", | ||
"version": "2.1.1", | ||
"version": "2.1.2", | ||
"description": "A core Pluggable framework based on koa", | ||
@@ -36,5 +36,5 @@ "main": "index.js", | ||
"autod": "^2.7.1", | ||
"egg-bin": "^2.0.2", | ||
"egg-bin": "^2.2.1", | ||
"egg-ci": "^1.1.0", | ||
"eslint": "^3.15.0", | ||
"eslint": "^3.16.1", | ||
"eslint-config-egg": "^3.2.0", | ||
@@ -44,3 +44,3 @@ "mm": "^2.1.0", | ||
"pedding": "^1.1.0", | ||
"rimraf": "^2.5.4", | ||
"rimraf": "^2.6.0", | ||
"spy": "^1.0.0", | ||
@@ -51,3 +51,3 @@ "supertest": "^3.0.0" | ||
"co": "^4.6.0", | ||
"debug": "^2.6.0", | ||
"debug": "^2.6.1", | ||
"depd": "^1.1.0", | ||
@@ -59,9 +59,8 @@ "egg-logger": "^1.5.0", | ||
"inflection": "^1.12.0", | ||
"interop-require": "^1.0.0", | ||
"is-type-of": "^1.0.0", | ||
"koa": "^1.2.4", | ||
"koa": "^1.2.5", | ||
"koa-router": "^5.4.0", | ||
"node-homedir": "^1.0.0", | ||
"ready-callback": "^2.0.0", | ||
"utility": "^1.9.0" | ||
"ready-callback": "^2.0.1", | ||
"utility": "^1.11.0" | ||
}, | ||
@@ -68,0 +67,0 @@ "files": [ |
@@ -227,7 +227,7 @@ # egg-core | ||
-------------- | -------------- | ------------------------ | ||
directory | `String/Array` | directories to load | ||
target | `Object` | attach object from loaded files | ||
directory | `String/Array` | directories to be loaded | ||
target | `Object` | attach the target object from loaded files | ||
ignore | `String` | ignore the files when load | ||
initializer | `Function` | custom file exports, receive two parameters, first is the inject object, second is an `options` object that contain `path` | ||
lowercaseFirst | `Boolean` | determine whether the fist letter is lowercase | ||
caseStyle | `String/Function` | set property's case when converting a filepath to property list. | ||
override | `Boolean` | determine whether override the property when get the same name | ||
@@ -234,0 +234,0 @@ call | `Boolean` | determine whether invoke when exports is function |
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
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
78795
14
2097
- Removedinterop-require@^1.0.0
- Removedinterop-require@1.0.0(transitive)
Updateddebug@^2.6.1
Updatedkoa@^1.2.5
Updatedready-callback@^2.0.1
Updatedutility@^1.11.0