Comparing version 1.1.0-beta.16 to 1.1.0
@@ -1,43 +0,50 @@ | ||
"use strict"; | ||
/** | ||
* 扩展 Koa Application 对象 | ||
*/ | ||
const assert = require("assert"); | ||
const appExtends = { | ||
getConfig(key) { | ||
if (!key) { | ||
return this.config; | ||
} | ||
else { | ||
let keys = key.split('.'); | ||
let result = this.config; | ||
let item; | ||
while ((item = keys.shift())) { | ||
result = result[item]; | ||
} | ||
return result; | ||
} | ||
}, | ||
getServiceClass(packageName, serviceName) { | ||
assert(packageName, 'Package name cannot be empty!'); | ||
assert(serviceName, 'Service name cannot be empty!'); | ||
if (this.services && this.services[packageName] && this.services[packageName][serviceName]) { | ||
return this.services[packageName][serviceName]; | ||
} | ||
else { | ||
throw new Error(`Service ${packageName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
getLib(packageName, libName) { | ||
assert(packageName, 'Package name cannot be empty!'); | ||
assert(libName, 'Lib name cannot be empty!'); | ||
if (this.libs && this.libs[packageName] && this.libs[packageName][libName]) { | ||
return this.libs[packageName][libName]; | ||
} | ||
else { | ||
throw new Error(`Lib ${packageName} ${libName} is not found.`); | ||
} | ||
}, | ||
}; | ||
module.exports = appExtends; | ||
//# sourceMappingURL=application.js.map | ||
const assert = require('assert'); | ||
module.exports = { | ||
/** | ||
* 获取配置信息,参数 key 可以是点分隔符隔开的字符串,例如 foo.bar | ||
* @param {String} key 配置 key | ||
*/ | ||
getConfig(key) { | ||
if (!key) { | ||
return this.config; | ||
} else { | ||
let keys = key.split('.'); | ||
let result = this.config; | ||
let item; | ||
while (item = keys.shift()) { | ||
result = result[item]; | ||
} | ||
return result; | ||
} | ||
}, | ||
/** | ||
* 获取 Service 类 | ||
* @param {String} packageName 包名 | ||
* @param {String} serviceName 服务名 | ||
*/ | ||
getServiceClass(packageName, serviceName) { | ||
assert(packageName, 'Package name cannot be empty!'); | ||
assert(serviceName, 'Service name cannot be empty!'); | ||
if (this.services && this.services[packageName] && this.services[packageName][serviceName]) { | ||
return this.services[packageName][serviceName]; | ||
} else { | ||
throw new Error(`Service ${packageName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
getLib(packageName, libName) { | ||
assert(packageName, 'Package name cannot be empty!'); | ||
assert(libName, 'Lib name cannot be empty!'); | ||
if (this.libs && this.libs[packageName] && this.libs[packageName][libName]) { | ||
return this.libs[packageName][libName]; | ||
} else { | ||
throw new Error(`Lib ${packageName} ${libName} is not found.`); | ||
} | ||
} | ||
}; |
@@ -1,70 +0,91 @@ | ||
"use strict"; | ||
/** | ||
* 扩展 Koa Context 对象 | ||
*/ | ||
const assert = require("assert"); | ||
const ctxExtends = { | ||
getConfig(...args) { | ||
return this.app.getConfig(...args); | ||
}, | ||
getServiceClass(...args) { | ||
return this.app.getServiceClass(...args); | ||
}, | ||
getService(packageName, serviceName) { | ||
assert(packageName, 'Package name cannot be empty!'); | ||
assert(serviceName, 'Service name cannot be empty!'); | ||
if (this.app.services && this.app.services[packageName] && this.app.services[packageName][serviceName]) { | ||
const ServiceClass = this.app.services[packageName][serviceName]; | ||
return new ServiceClass(this); | ||
} | ||
else { | ||
throw new Error(`Service ${packageName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
async callService(service, method, ...args) { | ||
const keys = service.split('/'); | ||
let packageName = undefined; | ||
let serviceName = undefined; | ||
if (keys.length === 2) { | ||
packageName = keys[0]; | ||
serviceName = keys[1]; | ||
} | ||
else if (keys.length === 1) { | ||
packageName = this.app.ROOT_NAME; | ||
serviceName = keys[0]; | ||
} | ||
if (this.app.services && this.app.services[packageName] && this.app.services[packageName][serviceName]) { | ||
const ServiceClass = this.app.services[packageName][serviceName]; | ||
const service = new ServiceClass(this); | ||
if (service[method]) { | ||
return await service[method](...args); | ||
} | ||
else { | ||
throw new Error(`method name ${method} is not found.`); | ||
} | ||
} | ||
else { | ||
throw new Error(`Service ${packageName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
invokeServiceMethod(pkgName, serviceName, methodName, ...args) { | ||
if (this.app.services && this.app.services[pkgName] && this.app.services[pkgName][serviceName]) { | ||
const ServiceClass = this.app.services[pkgName][serviceName]; | ||
const service = new ServiceClass(this); | ||
if (service[methodName]) { | ||
return service[methodName](...args); | ||
} | ||
else { | ||
throw new Error(`method name ${methodName} is not found.`); | ||
} | ||
} | ||
else { | ||
throw new Error(`Service ${pkgName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
getLib(...args) { | ||
return this.app.getLib(...args); | ||
}, | ||
}; | ||
module.exports = ctxExtends; | ||
//# sourceMappingURL=context.js.map | ||
const assert = require('assert'); | ||
module.exports = { | ||
getConfig(...args) { | ||
return this.app.getConfig(...args); | ||
}, | ||
getServiceClass(...args) { | ||
return this.app.getServiceClass(...args); | ||
}, | ||
/** | ||
* 获取一个 Service 类实例 | ||
* @param {String} packageName 包名 | ||
* @param {String} serviceName 服务名 | ||
*/ | ||
getService(packageName, serviceName) { | ||
assert(packageName, 'Package name cannot be empty!'); | ||
assert(serviceName, 'Service name cannot be empty!'); | ||
if (this.app.services && this.app.services[packageName] && this.app.services[packageName][serviceName]) { | ||
const ServiceClass = this.app.services[packageName][serviceName]; | ||
return new ServiceClass(this); | ||
} else { | ||
throw new Error(`Service ${packageName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
/** | ||
* 调用服务 | ||
* @param {String} service 服务名 | ||
* @param {String} method 方法名 | ||
* @param {Object} args 参数 | ||
*/ | ||
async callService(service, method, ...args) { | ||
const keys = service.split('/'); | ||
let packageName, | ||
serviceName; | ||
if (keys.length === 2) { | ||
packageName = keys[0]; | ||
serviceName = keys[1]; | ||
} else if (keys.length === 1) { | ||
packageName = this.app.ROOT_NAME; | ||
serviceName = keys[0]; | ||
} | ||
if (this.app.services && | ||
this.app.services[packageName] && | ||
this.app.services[packageName][serviceName]) { | ||
const ServiceClass = this.app.services[packageName][serviceName]; | ||
const service = new ServiceClass(this); | ||
if (service[method]) { | ||
return await service[method](...args); | ||
} else { | ||
throw new Error(`method name ${method} is not found.`); | ||
} | ||
} else { | ||
throw new Error(`Service ${packageName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
/** | ||
* 调用服务(定义支持) | ||
* @param {String} pkgName 包名 | ||
* @param {String} serviceName 服务名 | ||
* @param {String} methodName 方法名 | ||
* @param {Object} args 参数 | ||
*/ | ||
async invokeServiceMethod(pkgName, serviceName, methodName, ...args) { | ||
if (this.app.services && | ||
this.app.services[pkgName] && | ||
this.app.services[pkgName][serviceName]) { | ||
const ServiceClass = this.app.services[pkgName][serviceName]; | ||
const service = new ServiceClass(this); | ||
if (service[methodName]) { | ||
return await service[methodName](...args); | ||
} else { | ||
throw new Error(`method name ${methodName} is not found.`); | ||
} | ||
} else { | ||
throw new Error(`Service ${pkgName} ${serviceName} is not found.`); | ||
} | ||
}, | ||
getLib(...args) { | ||
return this.app.getLib(...args); | ||
} | ||
}; |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -7,69 +6,68 @@ * 配置加载器加载顺序 | ||
const NODE_ENV = process.env.NODE_ENV; | ||
const defaultLoaderConfig = { | ||
AstroboyPkgLoader: { | ||
priority: 10, | ||
module.exports = { | ||
AstroboyPkgLoader: { | ||
priority: 10, | ||
}, | ||
AstroboyExtendLoader: { | ||
priority: 15, | ||
options: { | ||
applicationPattern: `/app/extends/application.${SUPPORT_EXT}`, | ||
contextPattern: [`/app/extends/context/*.${SUPPORT_EXT}`, `/app/extends/context.${SUPPORT_EXT}`], | ||
requestPattern: `/app/extends/request.${SUPPORT_EXT}`, | ||
responsePattern: `/app/extends/response.${SUPPORT_EXT}`, | ||
controllerPattern: `/app/extends/controller.${SUPPORT_EXT}`, | ||
}, | ||
AstroboyExtendLoader: { | ||
priority: 15, | ||
options: { | ||
applicationPattern: `/app/extends/application.${SUPPORT_EXT}`, | ||
contextPattern: [`/app/extends/context/*.${SUPPORT_EXT}`, `/app/extends/context.${SUPPORT_EXT}`], | ||
requestPattern: `/app/extends/request.${SUPPORT_EXT}`, | ||
responsePattern: `/app/extends/response.${SUPPORT_EXT}`, | ||
controllerPattern: `/app/extends/controller.${SUPPORT_EXT}`, | ||
}, | ||
}, | ||
AstroboyConfigLoader: { | ||
priority: 20, | ||
options: { | ||
// 注意:为了控制配置合并顺序,不要这么写 `/config/config.(default|${NODE_ENV}).js` | ||
pattern: ['/config/config.default.js', `/config/config.${NODE_ENV}.js`], | ||
}, | ||
AstroboyConfigLoader: { | ||
priority: 20, | ||
options: { | ||
// 注意:为了控制配置合并顺序,不要这么写 `/config/config.(default|${NODE_ENV}).js` | ||
pattern: [`/config/config.default.${SUPPORT_EXT}`, `/config/config.${NODE_ENV}.${SUPPORT_EXT}`], | ||
}, | ||
}, | ||
AstroboyMiddlewareLoader: { | ||
priority: 25, | ||
options: { | ||
pattern: `/app/middlewares/*.${SUPPORT_EXT}`, | ||
// 注意:为了控制配置合并顺序,不要这么写 `/config/config.(default|${NODE_ENV}).js` | ||
configPattern: ['/config/middleware.default.js', `/config/middleware.${NODE_ENV}.js`], | ||
}, | ||
AstroboyMiddlewareLoader: { | ||
priority: 25, | ||
options: { | ||
pattern: `/app/middlewares/*.${SUPPORT_EXT}`, | ||
// 注意:为了控制配置合并顺序,不要这么写 `/config/config.(default|${NODE_ENV}).js` | ||
configPattern: [`/config/middleware.default.${SUPPORT_EXT}`, `/config/middleware.${NODE_ENV}.${SUPPORT_EXT}`], | ||
}, | ||
}, | ||
AstroboyLibLoader: { | ||
priority: 30, | ||
options: { | ||
pattern: `/app/lib/*.${SUPPORT_EXT}`, | ||
}, | ||
AstroboyLibLoader: { | ||
priority: 30, | ||
options: { | ||
pattern: `/app/lib/*.${SUPPORT_EXT}`, | ||
}, | ||
}, | ||
AstroboyBootLoader: { | ||
priority: 35, | ||
options: { | ||
pattern: `/boot.${SUPPORT_EXT}`, | ||
}, | ||
AstroboyBootLoader: { | ||
priority: 35, | ||
options: { | ||
pattern: `/boot.${SUPPORT_EXT}`, | ||
}, | ||
}, | ||
AstroboyControllerLoader: { | ||
priority: 40, | ||
options: { | ||
pattern: `/app/controllers/**/*.${SUPPORT_EXT}`, | ||
}, | ||
AstroboyControllerLoader: { | ||
priority: 40, | ||
options: { | ||
pattern: `/app/controllers/**/*.${SUPPORT_EXT}`, | ||
}, | ||
}, | ||
AstroboyServiceLoader: { | ||
priority: 45, | ||
options: { | ||
pattern: `/app/services/**/*.${SUPPORT_EXT}`, | ||
}, | ||
AstroboyServiceLoader: { | ||
priority: 45, | ||
options: { | ||
pattern: `/app/services/**/*.${SUPPORT_EXT}`, | ||
}, | ||
}, | ||
AstroboyRouterLoader: { | ||
priority: 50, | ||
options: { | ||
pattern: `/app/routers/**/*.${SUPPORT_EXT}`, | ||
}, | ||
AstroboyRouterLoader: { | ||
priority: 50, | ||
options: { | ||
pattern: `/app/routers/**/*.${SUPPORT_EXT}`, | ||
}, | ||
}, | ||
AstroboyVersionFileLoader: { | ||
priority: 55, | ||
options: { | ||
pattern: '/config/version*.json', | ||
}, | ||
AstroboyVersionFileLoader: { | ||
priority: 55, | ||
options: { | ||
pattern: '/config/version*.json', | ||
}, | ||
}, | ||
}, | ||
}; | ||
module.exports = defaultLoaderConfig; | ||
//# sourceMappingURL=loader.default.js.map |
@@ -1,29 +0,33 @@ | ||
"use strict"; | ||
const path = require("path"); | ||
/** | ||
* 默认插件配置文件 | ||
*/ | ||
const defaultPluginConfig = { | ||
'astroboy-body': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-body'), | ||
}, | ||
'astroboy-router': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-router'), | ||
}, | ||
'astroboy-security': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-security'), | ||
}, | ||
'astroboy-static': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-static'), | ||
}, | ||
'astroboy-view': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-view'), | ||
}, | ||
}; | ||
module.exports = defaultPluginConfig; | ||
//# sourceMappingURL=plugin.default.js.map | ||
const path = require('path'); | ||
module.exports = { | ||
'astroboy-body': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-body') | ||
}, | ||
'astroboy-router': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-router') | ||
}, | ||
'astroboy-security': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-security') | ||
}, | ||
'astroboy-static': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-static') | ||
}, | ||
'astroboy-view': { | ||
enable: true, | ||
path: path.resolve(__dirname, '../plugins/astroboy-view') | ||
}, | ||
}; |
@@ -1,72 +0,58 @@ | ||
"use strict"; | ||
const chalk_1 = require("chalk"); | ||
const path = require("path"); | ||
const Koa = require("koa"); | ||
const events_1 = require("events"); | ||
const CoreLoader_1 = require("./CoreLoader"); | ||
const BaseClass_1 = require("./base/BaseClass"); | ||
/** | ||
* ## Astroboy Framework | ||
* | ||
* @author Big Mogician | ||
* @class Astroboy | ||
* @extends {EventEmitter} | ||
* @template DEFINE Framework Definition, defalut is `IAstroboyFrameworkDefine`. | ||
*/ | ||
class Astroboy extends events_1.EventEmitter { | ||
constructor(options = {}) { | ||
super(); | ||
options.NODE_ENV = | ||
process.env.APPLICATION_STANDARD_ENV || process.env.NODE_ENV || options.NODE_ENV || 'development'; | ||
options.NODE_PORT = process.env.NODE_PORT || options.NODE_PORT || '8201'; | ||
options.ROOT_PATH = options.ROOT_PATH || process.cwd(); | ||
this.options = options; | ||
this.init(); | ||
this.start(); | ||
} | ||
get [Symbol.for('BASE_DIR')]() { | ||
return path.join(__dirname, '..'); | ||
} | ||
init() { | ||
this.app = new Koa(); | ||
this.app.env = this.options.NODE_ENV; | ||
this.app.NODE_ENV = this.options.NODE_ENV; | ||
this.app.ROOT_PATH = this.options.ROOT_PATH; | ||
this.app.ROOT_NAME = path.basename(this.options.ROOT_PATH); | ||
this.loader = new CoreLoader_1.CoreLoader({ | ||
astroboy: this, | ||
app: this.app, | ||
const EventEmitter = require('events'); | ||
const path = require('path'); | ||
const chalk = require('chalk'); | ||
const Koa = require('koa'); | ||
const CoreLoader = require('./CoreLoader'); | ||
class Astroboy extends EventEmitter { | ||
get [Symbol.for('BASE_DIR')]() { | ||
return path.join(__dirname, '..'); | ||
} | ||
constructor(options = {}) { | ||
super(); | ||
options.NODE_ENV = | ||
process.env.APPLICATION_STANDARD_ENV || process.env.NODE_ENV || options.NODE_ENV || 'development'; | ||
options.NODE_PORT = process.env.NODE_PORT || options.NODE_PORT || '8201'; | ||
options.ROOT_PATH = options.ROOT_PATH || process.cwd(); | ||
this.options = options; | ||
this.init(); | ||
this.start(); | ||
} | ||
init() { | ||
this.app = new Koa(); | ||
this.app.env = this.options.NODE_ENV; | ||
this.app.NODE_ENV = this.options.NODE_ENV; | ||
this.app.ROOT_PATH = this.options.ROOT_PATH; | ||
this.app.ROOT_NAME = path.basename(this.options.ROOT_PATH); | ||
this.loader = new CoreLoader({ | ||
astroboy: this, | ||
app: this.app, | ||
}); | ||
} | ||
start() { | ||
this.app.listen(this.options.NODE_PORT, () => { | ||
console.log(chalk.green('应用启动成功')); | ||
console.log(chalk.green(`访问地址:${chalk.blue('http://127.0.0.1:' + this.options.NODE_PORT)}`)); | ||
this.emit('start', this.app); | ||
}); | ||
this.app.on('error', (err, ctx) => { | ||
this.emit('error', err, ctx); | ||
}); | ||
// 添加默认的 error 事件监听器 | ||
setTimeout(() => { | ||
if (this.listenerCount('error') === 0) { | ||
this.on('error', (err, ctx) => { | ||
console.log('[default error callback]'); | ||
console.log(err); | ||
}); | ||
} | ||
start() { | ||
this.app.listen(this.options.NODE_PORT, () => { | ||
console.log(chalk_1.default.green('应用启动成功')); | ||
console.log(chalk_1.default.green(`访问地址:${chalk_1.default.blue('http://127.0.0.1:' + this.options.NODE_PORT)}`)); | ||
this.emit('start', this.app); | ||
}); | ||
this.app.on('error', (err, ctx) => { | ||
this.emit('error', err, ctx); | ||
}); | ||
// 添加默认的 error 事件监听器 | ||
setTimeout(() => { | ||
if (this.listenerCount('error') === 0) { | ||
this.on('error', (err, ctx) => { | ||
console.log('[default error callback]'); | ||
console.log(err); | ||
}); | ||
} | ||
}, 3000); | ||
} | ||
} | ||
}, 3000); | ||
} | ||
} | ||
(function (Astroboy) { | ||
/** ### Astroboy Base Class */ | ||
Astroboy.BaseClass = BaseClass_1.BaseClass; | ||
/** ### Astroboy Controller Base */ | ||
Astroboy.Controller = BaseClass_1.BaseClass; | ||
/** ### Astroboy Service Base */ | ||
Astroboy.Service = BaseClass_1.BaseClass; | ||
/** ### Astroboy <Helper&Utils> Base */ | ||
Astroboy.Helper = BaseClass_1.BaseClass; | ||
})(Astroboy || (Astroboy = {})); | ||
module.exports = Astroboy; | ||
//# sourceMappingURL=Astroboy.js.map |
@@ -1,41 +0,39 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* ## Astroboy Base Class | ||
* - `ctx` Context 请求上下文对象 | ||
* - `app` Koa Application 实例对象 | ||
* - `config` 应用配置对象 | ||
* | ||
* @author Big Mogician | ||
* @export | ||
* @class BaseClass | ||
* @implements {IAstroboyCtxExtends<DEFINE>} | ||
* @template DEFINE Framework Definition, default is `IAstroboyFrameworkDefine` | ||
* ctx Context 请求上下文对象 | ||
* app Koa Application 实例对象 | ||
* config 应用配置对象 | ||
*/ | ||
class BaseClass { | ||
constructor(ctx) { | ||
this.ctx = ctx; | ||
this.app = (ctx && ctx.app); | ||
this.config = (ctx && ctx.app && ctx.app.config); | ||
} | ||
getConfig(...args) { | ||
return this.ctx.getConfig(...args); | ||
} | ||
getLib(...args) { | ||
return this.ctx.getLib(...args); | ||
} | ||
getServiceClass(...args) { | ||
return this.ctx.getServiceClass(...args); | ||
} | ||
getService(...args) { | ||
return this.ctx.getService(...args); | ||
} | ||
callService(...args) { | ||
return this.ctx.callService(...args); | ||
} | ||
invokeServiceMethod(...args) { | ||
return this.ctx.invokeServiceMethod(...args); | ||
} | ||
constructor(ctx) { | ||
this.ctx = ctx; | ||
this.app = ctx && ctx.app; | ||
this.config = ctx && ctx.app && ctx.app.config; | ||
} | ||
getConfig(...args) { | ||
return this.ctx.getConfig(...args); | ||
} | ||
getServiceClass(...args) { | ||
return this.ctx.getServiceClass(...args); | ||
} | ||
getService(...args) { | ||
return this.ctx.getService(...args); | ||
} | ||
callService(...args) { | ||
return this.ctx.callService(...args); | ||
} | ||
invokeServiceMethod(...args) { | ||
return this.ctx.invokeServiceMethod(...args); | ||
} | ||
getLib(...args) { | ||
return this.ctx.getLib(...args); | ||
} | ||
} | ||
exports.BaseClass = BaseClass; | ||
//# sourceMappingURL=BaseClass.js.map | ||
module.exports = BaseClass; |
@@ -1,293 +0,211 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// @ts-ignore no types matched | ||
const pathMatching = require("path-matching"); | ||
const path = require("path"); | ||
const lodash = require("lodash"); | ||
const util_1 = require("./lib/util"); | ||
const Loader_1 = require("./Loader"); | ||
/** | ||
* ## Core Loader | ||
* - decide how to build application. | ||
* | ||
* @author Big Mogician | ||
* @export | ||
* @class CoreLoader | ||
* @extends {Loader<F, A>} | ||
* @template F | ||
* @template A | ||
*/ | ||
class CoreLoader extends Loader_1.Loader { | ||
constructor(options = {}) { | ||
super(options); | ||
this.options = options || {}; | ||
this.astroboy = this.options.astroboy; | ||
this.app = this.options.app || this.app; | ||
this.NODE_ENV = this.app.NODE_ENV || 'development'; | ||
this.patterns = Object.assign({}, this.defaultPatterns); | ||
this.init(); | ||
const path = require('path'); | ||
const lodash = require('lodash'); | ||
const pathMatching = require('path-matching'); | ||
const Util = require('./lib/util'); | ||
const Loader = require('./Loader'); | ||
class CoreLoader extends Loader { | ||
get defaultPatterns() { | ||
return { | ||
loaderPattern: `/loader/*.(js|ts)`, | ||
pluginPattern: `/config/plugin.(default|${this.NODE_ENV}).js`, | ||
loaderConfigPattern: `/config/loader.(default|${this.NODE_ENV}).js`, | ||
}; | ||
} | ||
constructor(options = {}) { | ||
super(options); | ||
this.options = options; | ||
this.astroboy = this.options.astroboy; | ||
this.app = this.options.app; | ||
this.NODE_ENV = this.app.NODE_ENV; | ||
this.patterns = Object.assign({}, this.defaultPatterns); | ||
this.init(); | ||
} | ||
init() { | ||
this.loadCoreDirs(this.app.ROOT_PATH); | ||
this.loadPluginConfig(); | ||
this.loadFullDirs(); | ||
this.loadLoaderQueue(); | ||
this.loadLoaders(); | ||
this.runLoaders(); | ||
this.useMiddlewares(); | ||
} | ||
// 加载核心目录,包括 app、framework,但不包括 plugin | ||
loadCoreDirs(baseDir) { | ||
let coreDirs = [ | ||
{ | ||
baseDir: baseDir, | ||
type: 'app', | ||
name: path.basename(baseDir), | ||
}, | ||
]; | ||
let proto = this.astroboy; | ||
while (proto) { | ||
proto = Object.getPrototypeOf(proto); | ||
if (proto) { | ||
const newBaseDir = proto[Symbol.for('BASE_DIR')]; | ||
if (newBaseDir) { | ||
coreDirs.push({ | ||
baseDir: newBaseDir, | ||
type: 'framework', | ||
name: path.basename(newBaseDir), | ||
}); | ||
} | ||
} | ||
} | ||
get defaultPatterns() { | ||
return { | ||
loaderPattern: `/loader/*.(js|ts)`, | ||
pluginPattern: `/config/plugin.(default|${this.NODE_ENV}).(js|ts)`, | ||
loaderConfigPattern: `/config/loader.(default|${this.NODE_ENV}).(js|ts)`, | ||
}; | ||
} | ||
/** | ||
* ### `init` hook | ||
* | ||
* @virtual | ||
* @author Big Mogician | ||
* @protected | ||
* @memberof CoreLoader | ||
*/ | ||
init() { | ||
this.loadCoreDirs(this.app.ROOT_PATH); | ||
this.loadPluginConfig(); | ||
this.loadFullDirs(); | ||
this.loadLoaderQueue(); | ||
this.loadLoaders(); | ||
this.runLoaders(); | ||
this.useMiddlewares(); | ||
} | ||
/** | ||
* ### `load` hook | ||
* | ||
* @virtual | ||
* @author Big Mogician | ||
* @memberof CoreLoader | ||
*/ | ||
load() { } | ||
/** | ||
* ### 加载核心目录,包括 app、framework,但不包括 plugin | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {string} baseDir | ||
* @memberof CoreLoader | ||
*/ | ||
loadCoreDirs(baseDir) { | ||
const coreDirs = [ | ||
{ | ||
baseDir: baseDir, | ||
type: 'app', | ||
name: path.basename(baseDir), | ||
}, | ||
]; | ||
let proto = this.astroboy; | ||
while (proto) { | ||
proto = Object.getPrototypeOf(proto); | ||
if (proto) { | ||
const newBaseDir = proto[Symbol.for('BASE_DIR')]; | ||
if (newBaseDir) { | ||
coreDirs.push({ | ||
baseDir: newBaseDir, | ||
type: 'framework', | ||
name: path.basename(newBaseDir), | ||
}); | ||
} | ||
} | ||
this.coreDirs = coreDirs.reverse(); | ||
Util.outputJsonSync(`${this.app.ROOT_PATH}/run/coreDirs.json`, this.coreDirs); | ||
} | ||
// 获取插件配置 | ||
loadPluginConfig() { | ||
let pluginConfig = {}; | ||
this.coreDirs.forEach(item => { | ||
this.globDir(item.baseDir, this.patterns.pluginPattern, entries => { | ||
pluginConfig = entries.reduce((a, b) => { | ||
let content = require(b); | ||
return lodash.merge(a, content); | ||
}, pluginConfig); | ||
}); | ||
}); | ||
this.pluginConfig = pluginConfig; | ||
Util.outputJsonSync(`${this.app.ROOT_PATH}/run/pluginConfig.json`, pluginConfig); | ||
} | ||
// 获取遍历目录 | ||
loadFullDirs() { | ||
let dirs = []; | ||
this.coreDirs.forEach(item => { | ||
dirs = dirs.concat(this.getPluginDirs(item.baseDir).reverse()); | ||
dirs.push(item); | ||
}); | ||
this.dirs = dirs; | ||
Util.outputJsonSync(`${this.app.ROOT_PATH}/run/dirs.json`, dirs); | ||
} | ||
// 获取需要遍历的插件目录 | ||
getPluginDirs(baseDir) { | ||
const config = this.getPluginConfig(baseDir); | ||
let ret = []; | ||
if (lodash.isPlainObject(config)) { | ||
for (let name in config) { | ||
if (this.pluginConfig[name].enable) { | ||
const baseDir = this.getPluginPath(config[name]); | ||
ret.push({ | ||
baseDir: baseDir, | ||
type: 'plugin', | ||
name: path.basename(baseDir), | ||
}); | ||
} | ||
this.coreDirs = coreDirs.reverse(); | ||
util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/coreDirs.json`, this.coreDirs); | ||
} | ||
} | ||
/** | ||
* ### 获取插件配置 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @memberof CoreLoader | ||
*/ | ||
loadPluginConfig() { | ||
let pluginConfig = {}; | ||
this.coreDirs.forEach(item => { | ||
this.globDir(item.baseDir, this.patterns.pluginPattern, entries => { | ||
pluginConfig = entries.reduce((a, b) => { | ||
const content = require(b); | ||
return lodash.merge(a, content); | ||
}, pluginConfig); | ||
}); | ||
return ret; | ||
} | ||
getPluginConfig(baseDir) { | ||
let config = {}; | ||
this.globDir(baseDir, this.patterns.pluginPattern, entries => { | ||
config = entries.reduce((a, b) => { | ||
return lodash.merge(a, require(b)); | ||
}, {}); | ||
}); | ||
return config; | ||
} | ||
// 获取加载器执行队列 | ||
loadLoaderQueue() { | ||
let loaderConfig = {}; | ||
this.globDirs(this.patterns.loaderConfigPattern, entries => { | ||
loaderConfig = entries.reduce((previousValue, currentValue) => { | ||
return lodash.merge(previousValue, require(currentValue)); | ||
}, loaderConfig); | ||
}); | ||
let queue = []; | ||
Object.keys(loaderConfig).forEach(item => { | ||
queue.push( | ||
Object.assign( | ||
{ | ||
priority: 300, | ||
name: item, | ||
}, | ||
loaderConfig[item] | ||
) | ||
); | ||
}); | ||
queue = queue.sort((a, b) => { | ||
return a.priority - b.priority; | ||
}); | ||
this.loaderQueue = queue; | ||
} | ||
// 获取加载器 | ||
loadLoaders() { | ||
let loaders = {}; | ||
this.globDirs(this.patterns.loaderPattern, entries => { | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(path.basename(entry)); | ||
loaders[key] = require(entry); | ||
}); | ||
}); | ||
this.loaders = loaders; | ||
} | ||
// 执行加载器 | ||
runLoaders() { | ||
const app = this.app; | ||
const loaders = this.loaders; | ||
this.loaderQueue.forEach(item => { | ||
if (loaders[item.name]) { | ||
const loader = new loaders[item.name]({ | ||
dirs: this.dirs, | ||
config: item.options, | ||
app, | ||
}); | ||
this.pluginConfig = pluginConfig; | ||
util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/pluginConfig.json`, pluginConfig); | ||
} | ||
/** | ||
* ### 获取遍历目录 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @memberof CoreLoader | ||
*/ | ||
loadFullDirs() { | ||
let dirs = []; | ||
this.coreDirs.forEach(item => { | ||
dirs = dirs.concat(this.getPluginDirs(item.baseDir).reverse()); | ||
dirs.push(item); | ||
}); | ||
this.dirs = dirs; | ||
util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/dirs.json`, dirs); | ||
} | ||
/** | ||
* ### 获取需要遍历的插件目录 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {string} baseDir | ||
* @returns | ||
* @memberof CoreLoader | ||
*/ | ||
getPluginDirs(baseDir) { | ||
const config = this.getPluginConfig(baseDir); | ||
const ret = []; | ||
if (lodash.isPlainObject(config)) { | ||
for (let name in config) { | ||
if (this.pluginConfig[name].enable) { | ||
const baseDir = this.getPluginPath(config[name]); | ||
ret.push({ | ||
baseDir: baseDir, | ||
type: 'plugin', | ||
name: path.basename(baseDir), | ||
}); | ||
} | ||
} | ||
if (!(loader instanceof Loader)) { | ||
throw new Error(`Loader ${item.name} must extend Loader.`); | ||
} | ||
return ret; | ||
} | ||
/** | ||
* ### 获取需要遍历的插件配置 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {string} baseDir | ||
* @returns | ||
* @memberof CoreLoader | ||
*/ | ||
getPluginConfig(baseDir) { | ||
let config = {}; | ||
this.globDir(baseDir, this.patterns.pluginPattern, entries => { | ||
config = entries.reduce((a, b) => { | ||
return lodash.merge(a, require(b)); | ||
}, {}); | ||
}); | ||
return config; | ||
} | ||
/** | ||
* ### 获取加载器执行队列 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @memberof CoreLoader | ||
*/ | ||
loadLoaderQueue() { | ||
let loaderConfig = {}; | ||
this.globDirs(this.patterns.loaderConfigPattern, entries => { | ||
loaderConfig = entries.reduce((previousValue, currentValue) => { | ||
return lodash.merge(previousValue, require(currentValue)); | ||
}, loaderConfig); | ||
}); | ||
let queue = []; | ||
Object.keys(loaderConfig).forEach(item => { | ||
queue.push(Object.assign({ | ||
priority: 300, | ||
name: item, | ||
}, loaderConfig[item])); | ||
}); | ||
queue = queue.sort((a, b) => { | ||
return a.priority - b.priority; | ||
}); | ||
this.loaderQueue = queue; | ||
} | ||
/** | ||
* ### 获取加载器 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @memberof CoreLoader | ||
*/ | ||
loadLoaders() { | ||
let loaders = {}; | ||
this.globDirs(this.patterns.loaderPattern, entries => { | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(path.basename(entry)); | ||
loaders[key] = require(entry); | ||
}); | ||
}); | ||
this.loaders = loaders; | ||
} | ||
/** | ||
* ### 执行加载器 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @memberof CoreLoader | ||
*/ | ||
runLoaders() { | ||
const app = this.app; | ||
const loaders = this.loaders; | ||
this.loaderQueue.forEach(item => { | ||
if (loaders[item.name]) { | ||
const loader = new loaders[item.name]({ | ||
dirs: this.dirs, | ||
config: item.options, | ||
app, | ||
}); | ||
if (!(loader instanceof Loader_1.Loader)) { | ||
throw new Error(`Loader ${item.name} must extend Loader.`); | ||
} | ||
loader.load(); | ||
} | ||
else { | ||
throw new Error(`Loader ${item.name} is not found.`); | ||
} | ||
}); | ||
} | ||
/** | ||
* ### Use Middlewares | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @memberof CoreLoader | ||
*/ | ||
useMiddlewares() { | ||
const app = this.app; | ||
const middlewares = app.middlewares; | ||
app.middlewareQueue.forEach(item => { | ||
if (middlewares[item.name]) { | ||
let fn = middlewares[item.name](item.options, app); | ||
fn = this.wrapMiddleware(fn, item); | ||
if (fn) { | ||
app.use(fn); | ||
} | ||
} | ||
else { | ||
throw new Error(`middleware ${item.name} is not found.`); | ||
} | ||
}); | ||
} | ||
/** | ||
* ### Wrap Middlewares | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {NormalizedMiddleware} middleware | ||
* @param {IPriority} options | ||
* @returns | ||
* @memberof CoreLoader | ||
*/ | ||
wrapMiddleware(middleware, options) { | ||
const match = pathMatching(options); | ||
let fn = async function (ctx, next) { | ||
if (match(ctx)) { | ||
await middleware(ctx, next); | ||
} | ||
else { | ||
await next(); | ||
} | ||
}; | ||
fn._name = `wrap-${middleware.name || middleware._name}`; | ||
return fn; | ||
} | ||
loader.load(); | ||
} else { | ||
throw new Error(`Loader ${item.name} is not found.`); | ||
} | ||
}); | ||
} | ||
useMiddlewares() { | ||
const app = this.app; | ||
const middlewares = app.middlewares; | ||
app.middlewareQueue.forEach(item => { | ||
if (middlewares[item.name]) { | ||
let fn = middlewares[item.name](item.options, app); | ||
fn = this.wrapMiddleware(fn, item); | ||
if (fn) { | ||
app.use(fn); | ||
} | ||
} else { | ||
throw new Error(`middleware ${item.name} is not found.`); | ||
} | ||
}); | ||
} | ||
wrapMiddleware(middleware, options) { | ||
const match = pathMatching(options); | ||
let fn = async function(ctx, next) { | ||
if (match(ctx)) { | ||
await middleware(ctx, next); | ||
} else { | ||
await next(); | ||
} | ||
}; | ||
fn._name = `wrap-${middleware.name || middleware._name}`; | ||
return fn; | ||
} | ||
} | ||
exports.CoreLoader = CoreLoader; | ||
//# sourceMappingURL=CoreLoader.js.map | ||
module.exports = CoreLoader; |
@@ -1,21 +0,14 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs = require("fs-extra"); | ||
/** | ||
* ### 输出内容到文件 | ||
* | ||
* @author Big Mogician | ||
* @export | ||
* @param {string} file | ||
* @param {*} data | ||
* @param {*} [options={}] | ||
*/ | ||
function outputJsonSync(file, data, options = {}) { | ||
options = Object.assign({ | ||
const fs = require('fs-extra'); | ||
module.exports = { | ||
outputJsonSync(file, data, options = {}) { | ||
options = Object.assign( | ||
{ | ||
spaces: 2, | ||
EOL: '\r\n', | ||
}, options); | ||
}, | ||
options | ||
); | ||
fs.outputJsonSync(file, data, options); | ||
} | ||
exports.outputJsonSync = outputJsonSync; | ||
//# sourceMappingURL=util.js.map | ||
}, | ||
}; |
@@ -1,105 +0,53 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const glob = require("fast-glob"); | ||
const path = require("path"); | ||
const TYPING_FILE_EXTS = '.d.ts'; | ||
'use strict'; | ||
const glob = require('fast-glob'); | ||
const path = require('path'); | ||
const APP_EXTENSIONS = ['js', 'ts']; | ||
/** | ||
* ### Check the file is typing file or not. | ||
* | ||
* @author Big Mogician | ||
* @param {EntryItem} entry | ||
* @returns | ||
*/ | ||
function fileIsNotTypingFile(entry) { | ||
return typeof entry === 'string' ? !entry.endsWith(TYPING_FILE_EXTS) : !entry.path.endsWith(TYPING_FILE_EXTS); | ||
} | ||
/** | ||
* ### Base Loader | ||
* | ||
* @author Big Mogician | ||
* @export | ||
* @abstract | ||
* @class Loader | ||
* @template F | ||
* @template A | ||
*/ | ||
class Loader { | ||
constructor(options = {}) { | ||
this.dirs = options.dirs || []; | ||
this.config = options.config || {}; | ||
this.app = options.app || {}; | ||
constructor(options = {}) { | ||
this.dirs = options.dirs; | ||
this.config = options.config; | ||
this.app = options.app; | ||
} | ||
load() {} | ||
resolveExtensions(path, resolveDevide = false) { | ||
let newPath = path; | ||
APP_EXTENSIONS.forEach(ext => (newPath = newPath.replace(`.${ext}`, ''))); | ||
return resolveDevide ? newPath.replace(/\//g, '.') : newPath; | ||
} | ||
globDirs(patterns, callback) { | ||
this.dirs.forEach(item => { | ||
this.globDir(item.baseDir, patterns, callback); | ||
}); | ||
} | ||
globDir(baseDir, patterns, callback) { | ||
let newPatterns; | ||
if (typeof patterns === 'string') { | ||
newPatterns = [`${baseDir}${patterns}`]; | ||
} else if (Array.isArray(patterns)) { | ||
newPatterns = patterns.map(pattern => { | ||
return `${baseDir}${pattern}`; | ||
}); | ||
} | ||
/** | ||
* ### Resolve Extensions | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {string} path | ||
* @param {boolean} [resolveDevide=false] | ||
* @returns | ||
* @memberof Loader | ||
*/ | ||
resolveExtensions(path, resolveDevide = false) { | ||
let newPath = path; | ||
APP_EXTENSIONS.forEach(ext => (newPath = newPath.replace(`.${ext}`, ''))); | ||
return resolveDevide ? newPath.replace(/\//g, '.') : newPath; | ||
const entries = glob.sync(newPatterns, { dot: true }); | ||
callback(entries.filter(i => !i.includes('.d.ts'))); | ||
} | ||
// 获取插件的根目录 | ||
// 要求插件的入口文件必须放在插件根目录 | ||
getPluginPath(plugin) { | ||
if (plugin.path) { | ||
return plugin.path; | ||
} | ||
/** | ||
* ### Get Dirs | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {(string | string[])} patterns | ||
* @param {(files: EntryItem[]) => void} callback | ||
* @memberof Loader | ||
*/ | ||
globDirs(patterns, callback) { | ||
this.dirs.forEach(item => { | ||
this.globDir(item.baseDir, patterns, callback); | ||
}); | ||
} | ||
/** | ||
* ### Resolve Dir | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {string} baseDir | ||
* @param {(string | string[])} patterns | ||
* @param {(files: EntryItem[]) => void} callback | ||
* @memberof Loader | ||
*/ | ||
globDir(baseDir, patterns, callback) { | ||
let newPatterns = []; | ||
if (typeof patterns === 'string') { | ||
newPatterns = [`${baseDir}${patterns}`]; | ||
} | ||
else if (Array.isArray(patterns)) { | ||
newPatterns = patterns.map(pattern => { | ||
return `${baseDir}${pattern}`; | ||
}); | ||
} | ||
const entries = glob.sync(newPatterns, { dot: true }); | ||
callback(entries.filter(fileIsNotTypingFile)); | ||
} | ||
/** | ||
* ### 获取插件的根目录 | ||
* - 要求插件的入口文件必须放在插件根目录 | ||
* | ||
* @author Big Mogician | ||
* @protected | ||
* @param {IPluginEntry} plugin | ||
* @returns | ||
* @memberof Loader | ||
*/ | ||
getPluginPath(plugin) { | ||
if (plugin.path) { | ||
return plugin.path; | ||
} | ||
const name = plugin.package || plugin.name; | ||
const entryFile = require.resolve(name); | ||
return path.dirname(entryFile); | ||
} | ||
const name = plugin.package || plugin.name; | ||
const entryFile = require.resolve(name); | ||
return path.dirname(entryFile); | ||
} | ||
} | ||
exports.Loader = Loader; | ||
//# sourceMappingURL=Loader.js.map | ||
module.exports = Loader; |
11
index.js
@@ -1,4 +0,9 @@ | ||
"use strict"; | ||
const Astroboy = require("./core/Astroboy"); | ||
const Astroboy = require('./core/Astroboy'); | ||
const BaseClass = require('./core/base/BaseClass'); | ||
module.exports = Astroboy; | ||
//# sourceMappingURL=index.js.map | ||
module.exports.BaseClass = BaseClass; | ||
module.exports.Controller = BaseClass; | ||
module.exports.Service = BaseClass; | ||
module.exports.Helper = BaseClass; |
@@ -1,17 +0,18 @@ | ||
"use strict"; | ||
const assert = require("assert"); | ||
const lodash = require("lodash"); | ||
const Loader_1 = require("../core/Loader"); | ||
class AstroboyBootLoader extends Loader_1.Loader { | ||
load() { | ||
this.globDirs(this.config.pattern || [], entries => { | ||
entries.forEach(entry => { | ||
const boot = require(entry); | ||
assert(lodash.isFunction(boot), `${entry} must return a function.`); | ||
boot(this.app); | ||
}); | ||
}); | ||
} | ||
'use strict'; | ||
const lodash = require('lodash'); | ||
const assert = require('assert'); | ||
const Loader = require('../core/Loader'); | ||
class AstroboyBootLoader extends Loader { | ||
load() { | ||
this.globDirs(this.config.pattern, entries => { | ||
entries.forEach(entry => { | ||
let boot = require(entry); | ||
assert(lodash.isFunction(boot), `${entry} must return a function.`); | ||
boot(this.app); | ||
}); | ||
}); | ||
} | ||
} | ||
module.exports = AstroboyBootLoader; | ||
//# sourceMappingURL=AstroboyBootLoader.js.map |
@@ -1,27 +0,27 @@ | ||
"use strict"; | ||
const lodash = require("lodash"); | ||
const Loader_1 = require("../core/Loader"); | ||
const util_1 = require("../core/lib/util"); | ||
class AstroboyConfigLoader extends Loader_1.Loader { | ||
load() { | ||
let config = {}; | ||
this.globDirs(this.config.pattern || [], entries => { | ||
config = entries.reduce((a, b) => { | ||
let content = require(b); | ||
// 配置文件支持两种写法: | ||
// 1、返回一个 function,执行改方法返回一个对象 | ||
// 2、普通 JS 对象 | ||
if (lodash.isFunction(content)) { | ||
return lodash.merge(a, content(this.app)); | ||
} | ||
else if (lodash.isPlainObject(content)) { | ||
return lodash.merge(a, content); | ||
} | ||
}, config); | ||
}); | ||
this.app.config = config; | ||
util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/config.json`, config); | ||
} | ||
'use strict'; | ||
const lodash = require('lodash'); | ||
const Loader = require('../core/Loader'); | ||
const Util = require('../core/lib/util'); | ||
class AstroboyConfigLoader extends Loader { | ||
load() { | ||
let config = {}; | ||
this.globDirs(this.config.pattern, entries => { | ||
config = entries.reduce((a, b) => { | ||
let content = require(b); | ||
// 配置文件支持两种写法: | ||
// 1、返回一个 function,执行改方法返回一个对象 | ||
// 2、普通 JS 对象 | ||
if (lodash.isFunction(content)) { | ||
return lodash.merge(a, content(this.app)); | ||
} else if (lodash.isPlainObject(content)) { | ||
return lodash.merge(a, content); | ||
} | ||
}, config); | ||
}); | ||
this.app.config = config; | ||
Util.outputJsonSync(`${this.app.ROOT_PATH}/run/config.json`, config); | ||
} | ||
} | ||
module.exports = AstroboyConfigLoader; | ||
//# sourceMappingURL=AstroboyConfigLoader.js.map |
@@ -1,21 +0,22 @@ | ||
"use strict"; | ||
const glob = require("fast-glob"); | ||
const Loader_1 = require("../core/Loader"); | ||
class AstroboyControllerLoader extends Loader_1.Loader { | ||
load() { | ||
const app = this.app; | ||
let controllers = {}; | ||
const entries = glob.sync([`${app.ROOT_PATH}${this.config.pattern}`], { | ||
dot: true, | ||
}); | ||
entries | ||
.filter(i => !i.includes('.d.ts')) | ||
.forEach(entry => { | ||
const key = this.resolveExtensions(entry.split('controllers/')[1], true); | ||
controllers[key] = require(entry); | ||
}); | ||
app.controllers = controllers; | ||
} | ||
'use strict'; | ||
const glob = require('fast-glob'); | ||
const Loader = require('../core/Loader'); | ||
class AstroboyControllerLoader extends Loader { | ||
load() { | ||
const app = this.app; | ||
let controllers = {}; | ||
const entries = glob.sync([`${app.ROOT_PATH}${this.config.pattern}`], { | ||
dot: true, | ||
}); | ||
entries | ||
.filter(i => !i.includes('.d.ts')) | ||
.forEach(entry => { | ||
const key = this.resolveExtensions(entry.split('controllers/')[1], true); | ||
controllers[key] = require(entry); | ||
}); | ||
app.controllers = controllers; | ||
} | ||
} | ||
module.exports = AstroboyControllerLoader; | ||
//# sourceMappingURL=AstroboyControllerLoader.js.map |
@@ -1,4 +0,2 @@ | ||
"use strict"; | ||
const Loader_1 = require("../core/Loader"); | ||
const BaseClass_1 = require("../core/base/BaseClass"); | ||
'use strict'; | ||
const requestProto = require('koa/lib/request'); | ||
@@ -9,37 +7,44 @@ const responseProto = require('koa/lib/response'); | ||
const completeAssign = require('complete-assign'); | ||
class AstroboyExtendLoader extends Loader_1.Loader { | ||
load() { | ||
// application extend | ||
this.globDirs(this.config.applicationPattern || [], entries => { | ||
entries.forEach(entry => { | ||
completeAssign(applicationProto, require(entry)); | ||
}); | ||
}); | ||
// context extend | ||
this.globDirs(this.config.contextPattern || [], entries => { | ||
entries.forEach(entry => { | ||
completeAssign(contextProto, require(entry)); | ||
}); | ||
}); | ||
// request extend | ||
this.globDirs(this.config.requestPattern || [], entries => { | ||
entries.forEach(entry => { | ||
completeAssign(requestProto, require(entry)); | ||
}); | ||
}); | ||
// response extend | ||
this.globDirs(this.config.responsePattern || [], entries => { | ||
entries.forEach(entry => { | ||
completeAssign(responseProto, require(entry)); | ||
}); | ||
}); | ||
// controller extend | ||
this.globDirs(this.config.controllerPattern || [], entries => { | ||
entries.forEach(entry => { | ||
completeAssign(BaseClass_1.BaseClass.prototype, require(entry)); | ||
}); | ||
}); | ||
} | ||
const Loader = require('../core/Loader'); | ||
const baseClassProto = require('../core/base/BaseClass').prototype; | ||
class AstroboyExtendLoader extends Loader { | ||
load() { | ||
// application extend | ||
this.globDirs(this.config.applicationPattern, entries => { | ||
entries.forEach(entry => { | ||
completeAssign(applicationProto, require(entry)); | ||
}); | ||
}); | ||
// context extend | ||
this.globDirs(this.config.contextPattern, entries => { | ||
entries.forEach(entry => { | ||
completeAssign(contextProto, require(entry)); | ||
}); | ||
}); | ||
// request extend | ||
this.globDirs(this.config.requestPattern, entries => { | ||
entries.forEach(entry => { | ||
completeAssign(requestProto, require(entry)); | ||
}); | ||
}); | ||
// response extend | ||
this.globDirs(this.config.responsePattern, entries => { | ||
entries.forEach(entry => { | ||
completeAssign(responseProto, require(entry)); | ||
}); | ||
}); | ||
// controller extend | ||
this.globDirs(this.config.controllerPattern, entries => { | ||
entries.forEach(entry => { | ||
completeAssign(baseClassProto, require(entry)); | ||
}); | ||
}); | ||
} | ||
} | ||
module.exports = AstroboyExtendLoader; | ||
//# sourceMappingURL=AstroboyExtendLoader.js.map |
@@ -1,28 +0,29 @@ | ||
"use strict"; | ||
const fs = require("fs"); | ||
const Loader_1 = require("../core/Loader"); | ||
class AstroboyLibLoader extends Loader_1.Loader { | ||
load() { | ||
let libs = {}; | ||
this.dirs.forEach(item => { | ||
const indexFile = `${item.baseDir}/app/lib/index.js`; | ||
if (fs.existsSync(indexFile)) { | ||
libs[item.name] = require(indexFile); | ||
} | ||
else { | ||
this.globDir(item.baseDir, this.config.pattern || [], entries => { | ||
if (entries.length > 0) { | ||
libs[item.name] = {}; | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(entry.split('lib/')[1], true); | ||
libs[item.name][key] = require(entry); | ||
}); | ||
} | ||
}); | ||
} | ||
'use strict'; | ||
const fs = require('fs'); | ||
const Loader = require('../core/Loader'); | ||
class AstroboyLibLoader extends Loader { | ||
load() { | ||
let libs = {}; | ||
this.dirs.forEach(item => { | ||
const indexFile = `${item.baseDir}/app/lib/index.js`; | ||
if (fs.existsSync(indexFile)) { | ||
libs[item.name] = require(indexFile); | ||
} else { | ||
this.globDir(item.baseDir, this.config.pattern, entries => { | ||
if (entries.length > 0) { | ||
libs[item.name] = {}; | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(entry.split('lib/')[1], true); | ||
libs[item.name][key] = require(entry); | ||
}); | ||
} | ||
}); | ||
this.app.libs = libs; | ||
} | ||
} | ||
}); | ||
this.app.libs = libs; | ||
} | ||
} | ||
module.exports = AstroboyLibLoader; | ||
//# sourceMappingURL=AstroboyLibLoader.js.map |
@@ -1,45 +0,53 @@ | ||
"use strict"; | ||
const path = require("path"); | ||
const lodash = require("lodash"); | ||
const Loader_1 = require("../core/Loader"); | ||
const util_1 = require("../core/lib/util"); | ||
class AstroboyMiddlewareLoader extends Loader_1.Loader { | ||
load() { | ||
// 加载中间件配置 | ||
let middlewareConfig = {}; | ||
this.globDirs(this.config.configPattern || [], entries => { | ||
entries.forEach(entry => { | ||
middlewareConfig = lodash.merge(middlewareConfig, require(entry)); | ||
}); | ||
}); | ||
this.app.middlewareConfig = middlewareConfig; | ||
// 加载中间件 | ||
let middlewares = {}; | ||
this.globDirs(this.config.pattern || [], entries => { | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(path.basename(entry)); | ||
middlewares[key] = require(entry); | ||
}); | ||
}); | ||
this.app.middlewares = middlewares; | ||
// 生成中间件加载顺序 | ||
let middlewareQueue = []; | ||
Object.keys(middlewareConfig).forEach(item => { | ||
middlewareQueue.push(Object.assign({ | ||
priority: 300, | ||
name: item, | ||
}, middlewareConfig[item])); | ||
}); | ||
middlewareQueue = middlewareQueue | ||
.filter(item => { | ||
return item.enable === true; | ||
}) | ||
.sort((a, b) => { | ||
return a.priority - b.priority; | ||
}); | ||
this.app.middlewareQueue = middlewareQueue; | ||
util_1.outputJsonSync(`${this.app.ROOT_PATH}/run/middlewares.json`, middlewareQueue); | ||
} | ||
'use strict'; | ||
const path = require('path'); | ||
const lodash = require('lodash'); | ||
const Loader = require('../core/Loader'); | ||
const Util = require('../core/lib/util'); | ||
class AstroboyMiddlewareLoader extends Loader { | ||
load() { | ||
// 加载中间件配置 | ||
let middlewareConfig = {}; | ||
this.globDirs(this.config.configPattern, entries => { | ||
entries.forEach(entry => { | ||
middlewareConfig = lodash.merge(middlewareConfig, require(entry)); | ||
}); | ||
}); | ||
this.app.middlewareConfig = middlewareConfig; | ||
// 加载中间件 | ||
let middlewares = {}; | ||
this.globDirs(this.config.pattern, entries => { | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(path.basename(entry)); | ||
middlewares[key] = require(entry); | ||
}); | ||
}); | ||
this.app.middlewares = middlewares; | ||
// 生成中间件加载顺序 | ||
let middlewareQueue = []; | ||
Object.keys(middlewareConfig).forEach(item => { | ||
middlewareQueue.push( | ||
Object.assign( | ||
{ | ||
priority: 300, | ||
name: item, | ||
}, | ||
middlewareConfig[item] | ||
) | ||
); | ||
}); | ||
middlewareQueue = middlewareQueue | ||
.filter(item => { | ||
return item.enable === true; | ||
}) | ||
.sort((a, b) => { | ||
return a.priority - b.priority; | ||
}); | ||
this.app.middlewareQueue = middlewareQueue; | ||
Util.outputJsonSync(`${this.app.ROOT_PATH}/run/middlewares.json`, middlewareQueue); | ||
} | ||
} | ||
module.exports = AstroboyMiddlewareLoader; | ||
//# sourceMappingURL=AstroboyMiddlewareLoader.js.map |
@@ -1,14 +0,16 @@ | ||
"use strict"; | ||
const path = require("path"); | ||
const fs = require("fs"); | ||
const Loader_1 = require("../core/Loader"); | ||
class AstroboyPkgLoader extends Loader_1.Loader { | ||
load() { | ||
const pkgPath = path.resolve(__dirname, '../package.json'); | ||
if (fs.existsSync(pkgPath)) { | ||
this.app.pkg = require(pkgPath); | ||
} | ||
'use strict'; | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const Loader = require('../core/Loader'); | ||
class AstroboyPkgLoader extends Loader { | ||
load() { | ||
const pkgPath = path.resolve(__dirname, '../package.json'); | ||
if (fs.existsSync(pkgPath)) { | ||
this.app.pkg = require(pkgPath); | ||
} | ||
} | ||
} | ||
module.exports = AstroboyPkgLoader; | ||
//# sourceMappingURL=AstroboyPkgLoader.js.map |
@@ -1,42 +0,42 @@ | ||
"use strict"; | ||
const fs = require("fs-extra"); | ||
const glob = require("fast-glob"); | ||
// @ts-ignore typings missing | ||
const methods = require("methods"); | ||
const Loader_1 = require("../core/Loader"); | ||
class AstroboyRouterLoader extends Loader_1.Loader { | ||
load() { | ||
let routers = []; | ||
const indexFile = `${this.app.ROOT_PATH}/app/routers/index.js`; | ||
if (fs.existsSync(indexFile)) { | ||
routers = require(indexFile); | ||
} | ||
else { | ||
const entries = glob.sync([`${this.app.ROOT_PATH}${this.config.pattern}`], { | ||
dot: true, | ||
}); | ||
entries.forEach(entry => { | ||
routers = routers.concat(require(entry)); | ||
}); | ||
} | ||
const controllers = this.app.controllers; | ||
let newRouters = []; | ||
routers.forEach(router => { | ||
// 如果第一个参数不是 routerName,则添加空参数名 | ||
if (methods.indexOf(router[0].toLowerCase()) > -1) { | ||
router.unshift(''); | ||
} | ||
newRouters.push({ | ||
name: router[0], | ||
verb: router[1].toLowerCase(), | ||
path: Array.isArray(router[2]) ? router[2] : [router[2]], | ||
controller: controllers[router[3]], | ||
methods: Array.isArray(router[4]) ? router[4] : [router[4]], | ||
controllerName: router[3], | ||
}); | ||
}); | ||
this.app.routers = newRouters; | ||
'use strict'; | ||
const fs = require('fs-extra'); | ||
const glob = require('fast-glob'); | ||
const methods = require('methods'); | ||
const Loader = require('../core/Loader'); | ||
class AstroboyRouterLoader extends Loader { | ||
load() { | ||
let routers = []; | ||
const indexFile = `${this.app.ROOT_PATH}/app/routers/index.js`; | ||
if (fs.existsSync(indexFile)) { | ||
routers = require(indexFile); | ||
} else { | ||
const entries = glob.sync([`${this.app.ROOT_PATH}${this.config.pattern}`], { | ||
dot: true, | ||
}); | ||
entries.forEach(entry => { | ||
routers = routers.concat(require(entry)); | ||
}); | ||
} | ||
const controllers = this.app.controllers; | ||
let newRouters = []; | ||
routers.forEach(router => { | ||
// 如果第一个参数不是 routerName,则添加空参数名 | ||
if (methods.indexOf(router[0].toLowerCase()) > -1) { | ||
router.unshift(''); | ||
} | ||
newRouters.push({ | ||
name: router[0], | ||
verb: router[1].toLowerCase(), | ||
path: Array.isArray(router[2]) ? router[2] : [router[2]], | ||
controller: controllers[router[3]], | ||
methods: Array.isArray(router[4]) ? router[4] : [router[4]], | ||
controllerName: router[3], | ||
}); | ||
}); | ||
this.app.routers = newRouters; | ||
} | ||
} | ||
module.exports = AstroboyRouterLoader; | ||
//# sourceMappingURL=AstroboyRouterLoader.js.map |
@@ -1,28 +0,28 @@ | ||
"use strict"; | ||
const fs = require("fs-extra"); | ||
const Loader_1 = require("../core/Loader"); | ||
class AstroboyServiceLoader extends Loader_1.Loader { | ||
load() { | ||
let services = {}; | ||
this.dirs.forEach(item => { | ||
const indexFile = `${item.baseDir}/app/services/index.js`; | ||
if (fs.existsSync(indexFile)) { | ||
services[item.name] = require(indexFile); | ||
} | ||
else { | ||
this.globDir(item.baseDir, this.config.pattern || [], entries => { | ||
if (entries.length > 0) { | ||
services[item.name] = {}; | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(entry.split('services/')[1], true); | ||
services[item.name][key] = require(entry); | ||
}); | ||
} | ||
}); | ||
} | ||
'use strict'; | ||
const fs = require('fs-extra'); | ||
const Loader = require('../core/Loader'); | ||
class AstroboyServiceLoader extends Loader { | ||
load() { | ||
let services = {}; | ||
this.dirs.forEach(item => { | ||
const indexFile = `${item.baseDir}/app/services/index.js`; | ||
if (fs.existsSync(indexFile)) { | ||
services[item.name] = require(indexFile); | ||
} else { | ||
this.globDir(item.baseDir, this.config.pattern, entries => { | ||
if (entries.length > 0) { | ||
services[item.name] = {}; | ||
entries.forEach(entry => { | ||
const key = this.resolveExtensions(entry.split('services/')[1], true); | ||
services[item.name][key] = require(entry); | ||
}); | ||
} | ||
}); | ||
this.app.services = services; | ||
} | ||
} | ||
}); | ||
this.app.services = services; | ||
} | ||
} | ||
module.exports = AstroboyServiceLoader; | ||
//# sourceMappingURL=AstroboyServiceLoader.js.map |
@@ -1,21 +0,24 @@ | ||
"use strict"; | ||
const glob = require("fast-glob"); | ||
const path = require("path"); | ||
const Loader_1 = require("../core/Loader"); | ||
class AstroboyVersionFileLoader extends Loader_1.Loader { | ||
load() { | ||
let versionMap = {}; | ||
this.dirs.forEach(item => { | ||
const entries = glob.sync([`${item.baseDir}${this.config.pattern}`], { | ||
dot: true, | ||
}); | ||
entries.forEach(entry => { | ||
const key = path.basename(entry, '.json'); | ||
versionMap[key] = require(entry); | ||
}); | ||
}); | ||
this.app.versionMap = versionMap; | ||
} | ||
'use strict'; | ||
const glob = require('fast-glob'); | ||
const path = require('path'); | ||
const Loader = require('../core/Loader'); | ||
class AstroboyVersionFileLoader extends Loader { | ||
load() { | ||
let versionMap = {}; | ||
this.dirs.forEach(item => { | ||
const entries = glob.sync([`${item.baseDir}${this.config.pattern}`], { | ||
dot: true, | ||
}); | ||
entries.forEach(entry => { | ||
const key = path.basename(entry, '.json'); | ||
versionMap[key] = require(entry); | ||
}); | ||
}); | ||
this.app.versionMap = versionMap; | ||
} | ||
} | ||
module.exports = AstroboyVersionFileLoader; | ||
//# sourceMappingURL=AstroboyVersionFileLoader.js.map |
{ | ||
"name": "astroboy", | ||
"version": "1.1.0-beta.16", | ||
"version": "1.1.0", | ||
"description": "Astroboy(阿童木)is a Nodejs SFB(Separation of Front and Back ends) framework, built on koa2.", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"scripts": { | ||
@@ -21,5 +20,2 @@ "release": "sh release.sh", | ||
"dependencies": { | ||
"@types/fs-extra": "^5.1.0", | ||
"@types/koa": "^2.0.46", | ||
"@types/lodash": "^4.14.123", | ||
"chalk": "2.4.0", | ||
@@ -39,8 +35,8 @@ "complete-assign": "0.0.2", | ||
"path-to-regexp": "2.2.1", | ||
"tslib": "1.9.3", | ||
"xss": "0.3.7" | ||
}, | ||
"devDependencies": { | ||
"vuepress": "^1.0.0-alpha.42" | ||
"@types/koa": "^2.0.46", | ||
"vuepress": "^1.0.3" | ||
} | ||
} |
@@ -1,14 +0,11 @@ | ||
"use strict"; | ||
/** | ||
* 请求体解析中间件 | ||
*/ | ||
const koaBody = require("koa-body"); | ||
// @ts-ignore typings missed | ||
const bodyParser = require("koa-bodyparser"); | ||
const factory = (options, app) => { | ||
const fn = options.parser === 'koa-bodyparser' ? bodyParser(options) : koaBody(options); | ||
fn._name = 'body'; | ||
return fn; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-body.js.map | ||
const koaBody = require('koa-body'); | ||
const bodyParser = require('koa-bodyparser'); | ||
module.exports = (options, app) => { | ||
let fn = options.parser === 'koa-bodyparser' ? bodyParser(options) : koaBody(options); | ||
fn._name = 'body'; | ||
return fn; | ||
}; |
@@ -1,20 +0,18 @@ | ||
"use strict"; | ||
const path = require("path"); | ||
const config = { | ||
'astroboy-body': { | ||
priority: 15, | ||
enable: true, | ||
options: { | ||
formidable: { | ||
uploadDir: path.resolve('/tmp'), | ||
}, | ||
multipart: true, | ||
jsonLimit: '3mb', | ||
formLimit: '3mb', | ||
textLimit: '3mb', | ||
strict: false, | ||
}, | ||
}, | ||
}; | ||
module.exports = config; | ||
//# sourceMappingURL=middleware.default.js.map | ||
const path = require('path'); | ||
module.exports = { | ||
'astroboy-body': { | ||
priority: 15, | ||
enable: true, | ||
options: { | ||
formidable: { | ||
uploadDir: path.resolve('/tmp') | ||
}, | ||
multipart: true, | ||
jsonLimit: '3mb', | ||
formLimit: '3mb', | ||
textLimit: '3mb', | ||
strict: false | ||
} | ||
} | ||
}; |
@@ -1,58 +0,57 @@ | ||
"use strict"; | ||
/** | ||
* 框架路由中间件 | ||
*/ | ||
const lodash = require("lodash"); | ||
// @ts-ignore typings missed | ||
const KoaRouter = require("koa-router"); | ||
const compose = require("koa-compose"); | ||
const factory = function (options = {}, app) { | ||
const koaRouter = new KoaRouter(); | ||
app.routers.forEach((router) => { | ||
const ControllerClass = router.controller; | ||
if (ControllerClass) { | ||
if (lodash.isFunction(ControllerClass)) { | ||
for (let i = 0; i < router.methods.length; i++) { | ||
if (!ControllerClass.prototype[router.methods[i]]) { | ||
throw new Error(`注册路由失败,verb:${router.verb} path:${router.path}, method:${router.methods[i]} is not found.`); | ||
} | ||
const lodash = require('lodash'); | ||
const KoaRouter = require('koa-router'); | ||
const compose = require('koa-compose'); | ||
module.exports = function (options = {}, app) { | ||
const koaRouter = new KoaRouter(); | ||
app.routers.forEach(router => { | ||
const ControllerClass = router.controller; | ||
if (ControllerClass) { | ||
if (lodash.isFunction(ControllerClass)) { | ||
for (let i = 0; i < router.methods.length; i++) { | ||
if (!ControllerClass.prototype[router.methods[i]]) { | ||
throw new Error(`注册路由失败,verb:${router.verb} path:${router.path}, method:${router.methods[i]} is not found.`); | ||
} | ||
} | ||
router.path.forEach(item => { | ||
koaRouter[router.verb](router.name, item, async function (ctx, next) { | ||
const controller = new ControllerClass(ctx); | ||
// init 是 Controller 类初始化后调用的一个方法 | ||
if (ControllerClass.prototype.init) { | ||
await controller['init'](); | ||
} | ||
if (ctx.status !== 301 && ctx.status !== 302) { | ||
for (let i = 0; i < router.methods.length; i++) { | ||
let method = router.methods[i]; | ||
const beforeMethod = 'before' + method.slice(0, 1).toUpperCase() + method.slice(1); | ||
if (ControllerClass.prototype[beforeMethod]) { | ||
await controller[beforeMethod](); | ||
} | ||
router.path.forEach((item) => { | ||
koaRouter[router.verb](router.name, item, async function (ctx, next) { | ||
const controller = new ControllerClass(ctx); | ||
// init 是 Controller 类初始化后调用的一个方法 | ||
if (ControllerClass.prototype.init) { | ||
await controller['init'](); | ||
} | ||
if (ctx.status !== 301 && ctx.status !== 302) { | ||
for (let i = 0; i < router.methods.length; i++) { | ||
let method = router.methods[i]; | ||
const beforeMethod = 'before' + method.slice(0, 1).toUpperCase() + method.slice(1); | ||
if (ControllerClass.prototype[beforeMethod]) { | ||
await controller[beforeMethod](); | ||
} | ||
if (ctx.status !== 301 && ctx.status !== 302 && !ctx.body) { | ||
await controller[method](ctx, next); | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
if (ctx.status !== 301 && ctx.status !== 302 && !ctx.body) { | ||
await controller[method](ctx, next); | ||
} else { | ||
break; | ||
} | ||
} | ||
} | ||
else { | ||
throw new Error(`注册路由失败,verb:${router.verb} path:${router.path}, controllerName:${router.controllerName} is not a function.`); | ||
} | ||
} | ||
else { | ||
throw new Error(`注册路由失败,verb:${router.verb} path:${router.path}, controllerName:${router.controllerName} is undefined.`); | ||
} | ||
}); | ||
let fn = compose([koaRouter.routes(), koaRouter.allowedMethods()]); | ||
fn._name = 'astroboy-router'; | ||
return fn; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-router.js.map | ||
}); | ||
}); | ||
} else { | ||
throw new Error(`注册路由失败,verb:${router.verb} path:${router.path}, controllerName:${router.controllerName} is not a function.`); | ||
} | ||
} else { | ||
throw new Error(`注册路由失败,verb:${router.verb} path:${router.path}, controllerName:${router.controllerName} is undefined.`); | ||
} | ||
}); | ||
let fn = compose([ | ||
koaRouter.routes(), | ||
koaRouter.allowedMethods() | ||
]); | ||
fn._name = 'astroboy-router'; | ||
return fn; | ||
}; |
@@ -1,8 +0,7 @@ | ||
"use strict"; | ||
const config = { | ||
'astroboy-router': { | ||
enable: true, | ||
}, | ||
}; | ||
module.exports = config; | ||
//# sourceMappingURL=middleware.default.js.map | ||
module.exports = { | ||
'astroboy-router': { | ||
enable: true | ||
} | ||
}; |
@@ -1,6 +0,6 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const assert = require("assert"); | ||
var assert = require('assert'); | ||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
const length = Buffer.byteLength(chars); | ||
const length = Buffer.byteLength(chars) | ||
/** | ||
@@ -11,10 +11,11 @@ * 生成一个长度为 len 的字符串 | ||
function randomString(len = 10) { | ||
assert(typeof len === 'number' && len >= 0, 'the length of the random string must be a number!'); | ||
var str = ''; | ||
for (var i = 0; i < len; i++) { | ||
str += chars[Math.floor(length * Math.random())]; | ||
} | ||
return str; | ||
assert(typeof len === 'number' && len >= 0, 'the length of the random string must be a number!') | ||
var str = '' | ||
for (var i = 0; i < len; i++) { | ||
str += chars[Math.floor(length * Math.random())]; | ||
} | ||
return str | ||
} | ||
exports.randomString = randomString; | ||
//# sourceMappingURL=randomString.js.map | ||
module.exports = randomString; |
@@ -1,45 +0,56 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const crypto = require("crypto"); | ||
const randomString_1 = require("./randomString"); | ||
const crypto = require('crypto'); | ||
const randomString = require('./randomString'); | ||
class Token { | ||
get defaultOptions() { | ||
return { | ||
saltLength: 10, | ||
secretLength: 18, | ||
}; | ||
get defaultOptions() { | ||
return { | ||
saltLength: 10, | ||
secretLength: 18 | ||
}; | ||
} | ||
constructor(options = {}) { | ||
this.options = Object.assign({}, this.defaultOptions, options); | ||
this.saltLength = this.options.saltLength; | ||
this.secretLength = this.options.secretLength; | ||
} | ||
secretSync() { | ||
return randomString(this.secretLength); | ||
} | ||
create(secret) { | ||
const salt = randomString(this.saltLength); | ||
return this.tokenize(secret, salt); | ||
} | ||
tokenize(secret, salt) { | ||
const hash = crypto | ||
.createHash('sha1') | ||
.update(secret, 'utf-8') | ||
.digest('base64'); | ||
return salt + '-' + hash; | ||
} | ||
verify(secret, token) { | ||
if (!secret || !token || | ||
typeof secret !== 'string' || | ||
typeof token !== 'string') { | ||
return false; | ||
} | ||
constructor(options = {}) { | ||
this.options = Object.assign({}, this.defaultOptions, options); | ||
this.saltLength = this.options.saltLength; | ||
this.secretLength = this.options.secretLength; | ||
const index = token.indexOf('-'); | ||
if (index === -1) { | ||
return false; | ||
} | ||
secretSync() { | ||
return randomString_1.randomString(this.secretLength); | ||
} | ||
create(secret) { | ||
const salt = randomString_1.randomString(this.saltLength); | ||
return this.tokenize(secret, salt); | ||
} | ||
tokenize(secret, salt) { | ||
const hash = crypto | ||
.createHash('sha1') | ||
.update(secret, 'utf8') | ||
.digest('base64'); | ||
return salt + '-' + hash; | ||
} | ||
verify(secret, token) { | ||
if (!secret || !token || typeof secret !== 'string' || typeof token !== 'string') { | ||
return false; | ||
} | ||
const index = token.indexOf('-'); | ||
if (index === -1) { | ||
return false; | ||
} | ||
const salt = token.substr(0, index); | ||
const expected = this.tokenize(secret, salt); | ||
return expected === token; | ||
} | ||
const salt = token.substr(0, index); | ||
const expected = this.tokenize(secret, salt); | ||
return expected === token; | ||
} | ||
} | ||
exports.Token = Token; | ||
//# sourceMappingURL=token.js.map | ||
module.exports = Token; |
@@ -1,9 +0,7 @@ | ||
"use strict"; | ||
/** | ||
* Content-Security-Policy | ||
* https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy__by_cnvoid | ||
* | ||
* | ||
* Content-Security-Policy-Report-Only | ||
* https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only | ||
*/ | ||
//# sourceMappingURL=astroboy-security-csp.js.map | ||
*/ |
@@ -1,51 +0,56 @@ | ||
"use strict"; | ||
/** | ||
* CSRF | ||
*/ | ||
const token_1 = require("../lib/token"); | ||
const Token = require('../lib/token'); | ||
class CsrfError extends Error { | ||
constructor(code, msg) { | ||
super(`code: ${code}, msg: ${msg}`); | ||
this.errorContent = { | ||
code, | ||
msg, | ||
}; | ||
this.errorType = 'CsrfError'; | ||
constructor(code, msg) { | ||
super(`code: ${code}, msg: ${msg}`); | ||
this.errorContent = { | ||
code, | ||
msg | ||
}; | ||
this.errorType = 'CsrfError'; | ||
} | ||
} | ||
module.exports = function (options = {}, app) { | ||
let token = new Token({ | ||
saltLength: options.saltLength, | ||
secretLength: options.secretLength | ||
}); | ||
return async function csrf(ctx, next) { | ||
if (options.excluded.indexOf(ctx.method) === -1 && | ||
options.env.indexOf(process.env.NODE_ENV) > -1) { | ||
const csrfSecret = ctx.cookies.get(options.csrfSecretName); | ||
const csrfToken = ctx.header[options.csrfTokenName]; | ||
// token 或 secret 不存在 | ||
if (!csrfSecret || !csrfToken) { | ||
throw new CsrfError(1000, 'CSRF Token Not Found!'); | ||
} | ||
// token 校验失败 | ||
if (!token.verify(csrfSecret, csrfToken)) { | ||
throw new CsrfError(1001, 'CSRF token Invalid!'); | ||
} | ||
} | ||
} | ||
const factory = function (options = {}, app) { | ||
let token = new token_1.Token({ | ||
saltLength: options.saltLength, | ||
secretLength: options.secretLength, | ||
}); | ||
return async function csrf(ctx, next) { | ||
if ((options.excluded || []).indexOf(ctx.method) === -1 && | ||
(options.env || []).indexOf(process.env.NODE_ENV) > -1) { | ||
const csrfSecret = ctx.cookies.get(options.csrfSecretName); | ||
const csrfToken = ctx.header[options.csrfTokenName]; | ||
// token 或 secret 不存在 | ||
if (!csrfSecret || !csrfToken) { | ||
throw new CsrfError(1000, 'CSRF Token Not Found!'); | ||
} | ||
// token 校验失败 | ||
if (!token.verify(csrfSecret, csrfToken)) { | ||
throw new CsrfError(1001, 'CSRF token Invalid!'); | ||
} | ||
} | ||
await next(); | ||
// 如果返回 HTML 格式数据,则生成 | ||
if (ctx.response.is('text/html')) { | ||
const secret = token.secretSync(); | ||
const newToken = token.create(secret); | ||
ctx.cookies.set(options.csrfSecretName, secret, { | ||
maxAge: options.maxAge, | ||
}); | ||
ctx.cookies.set(options.csrfTokenName, newToken, { | ||
maxAge: options.maxAge, | ||
httpOnly: false, | ||
}); | ||
} | ||
}; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-security-csrf.js.map | ||
await next(); | ||
// 如果返回 HTML 格式数据,则生成 | ||
if (ctx.response.is('text/html')) { | ||
const secret = token.secretSync(); | ||
const newToken = token.create(secret); | ||
ctx.cookies.set(options.csrfSecretName, secret, { | ||
maxAge: options.maxAge | ||
}); | ||
ctx.cookies.set(options.csrfTokenName, newToken, { | ||
maxAge: options.maxAge, | ||
httpOnly: false | ||
}); | ||
} | ||
}; | ||
}; |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -6,9 +5,7 @@ * X-Content-Type-Options | ||
*/ | ||
const factory = function (options = 'nosniff', app) { | ||
return async function cto(ctx, next) { | ||
ctx.set('X-Content-Type-Options', options); | ||
await next(); | ||
}; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-security-cto.js.map | ||
module.exports = function(options = 'nosniff', app) { | ||
return async function cto(ctx, next) { | ||
ctx.set('X-Content-Type-Options', options); | ||
await next(); | ||
}; | ||
}; |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -9,9 +8,7 @@ * X-Frame-Options | ||
*/ | ||
const factory = function (options = 'SAMEORIGIN', app) { | ||
return async function frameOptions(ctx, next) { | ||
ctx.set('X-Frame-Options', options); | ||
await next(); | ||
}; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-security-frameOptions.js.map | ||
module.exports = function(options = 'SAMEORIGIN', app) { | ||
return async function frameOptions(ctx, next) { | ||
ctx.set('X-Frame-Options', options); | ||
await next(); | ||
}; | ||
}; |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -6,24 +5,25 @@ * Strict-Transport-Security | ||
*/ | ||
const assert = require("assert"); | ||
const factory = function (options, app) { | ||
if (typeof options === 'number') { | ||
options = { | ||
maxAge: options, | ||
}; | ||
const assert = require('assert'); | ||
module.exports = function(options, app) { | ||
if (typeof options === 'number') { | ||
options = { | ||
maxAge: options | ||
} | ||
options = options || {}; | ||
assert(typeof options.maxAge === 'number', 'options.maxAge should be a number'); | ||
let value = 'max-age=' + options.maxAge; | ||
if (options.includeSubDomains) { | ||
value += '; includeSubDomains'; | ||
} | ||
if (options.preload) { | ||
value += '; preload'; | ||
} | ||
return async function hsts(ctx, next) { | ||
ctx.set('Strict-Transport-Security', value); | ||
await next(); | ||
}; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-security-hsts.js.map | ||
} | ||
options = options || {}; | ||
assert(typeof options.maxAge === 'number', 'options.maxAge should be a number'); | ||
let value = 'max-age=' + options.maxAge; | ||
if (options.includeSubDomains) { | ||
value += '; includeSubDomains'; | ||
} | ||
if (options.preload) { | ||
value += '; preload'; | ||
} | ||
return async function hsts(ctx, next) { | ||
ctx.set('Strict-Transport-Security', value); | ||
await next(); | ||
} | ||
}; |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -7,18 +6,18 @@ * P3P - Platform for Privacy Preferences Project | ||
*/ | ||
const assert = require("assert"); | ||
const factory = function (options, app) { | ||
if (typeof options === 'string') { | ||
options = { | ||
value: options, | ||
}; | ||
} | ||
options = options || {}; | ||
options.value = options.value || 'p3p'; | ||
assert(typeof options.value === 'string', 'options.value should be a string'); | ||
return async function p3p(ctx, next) { | ||
ctx.set('P3P', options.value); | ||
await next(); | ||
const assert = require('assert'); | ||
module.exports = function(options, app) { | ||
if (typeof options === 'string') { | ||
options = { | ||
value: options | ||
}; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-security-p3p.js.map | ||
} | ||
options = options || {}; | ||
options.value = options.value || 'p3p'; | ||
assert(typeof options.value === 'string', 'options.value should be a string'); | ||
return async function p3p(ctx, next) { | ||
ctx.set('P3P', options.value); | ||
await next(); | ||
}; | ||
}; |
@@ -1,35 +0,38 @@ | ||
"use strict"; | ||
const lodash = require("lodash"); | ||
const xss = require("xss"); | ||
const factory = (options, app) => { | ||
const myxss = new xss.FilterXSS(options); | ||
const deepXss = function (value, deep = true) { | ||
let res; | ||
if (Array.isArray(value) && value.length > 0) { | ||
res = []; | ||
const lodash = require('lodash'); | ||
const xss = require('xss'); | ||
module.exports = (options, app) => { | ||
const myxss = new xss.FilterXSS(options); | ||
const deepXss = function(value, deep = true) { | ||
let res; | ||
if (Array.isArray(value) && value.length > 0) { | ||
res = []; | ||
} else if (lodash.isPlainObject(value) && Object.keys(value).length > 0) { | ||
res = {}; | ||
} else { | ||
if (typeof value === 'string') { | ||
return myxss.process(value.trim()); | ||
} | ||
return value; | ||
} | ||
return lodash.reduce( | ||
value, | ||
(result, val, key) => { | ||
if (deep) { | ||
val = deepXss(val); | ||
} | ||
else if (lodash.isPlainObject(value) && Object.keys(value).length > 0) { | ||
res = {}; | ||
} | ||
else { | ||
if (typeof value === 'string') { | ||
return myxss.process(value.trim()); | ||
} | ||
return value; | ||
} | ||
return lodash.reduce(value, (result, val, key) => { | ||
if (deep) { | ||
val = deepXss(val); | ||
} | ||
result[key] = val; | ||
return result; | ||
}, res); | ||
}; | ||
return async function xss(ctx, next) { | ||
ctx.query = deepXss(ctx.query); | ||
ctx.request.body = deepXss(ctx.request.body); | ||
await next(); | ||
}; | ||
result[key] = val; | ||
return result; | ||
}, | ||
res | ||
); | ||
}; | ||
return async function xss(ctx, next) { | ||
ctx.query = deepXss(ctx.query); | ||
ctx.request.body = deepXss(ctx.request.body); | ||
await next(); | ||
}; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-security-xss.js.map |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -9,9 +8,7 @@ * X-XSS-Protection: 0 禁止XSS过滤。 | ||
*/ | ||
const factory = function (options = '1; mode=block', app) { | ||
return async function xssProtection(ctx, next) { | ||
ctx.set('X-XSS-Protection', options); | ||
await next(); | ||
}; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-security-xssProtection.js.map | ||
module.exports = function(options = '1; mode=block', app) { | ||
return async function xssProtection(ctx, next) { | ||
ctx.set('X-XSS-Protection', options); | ||
await next(); | ||
}; | ||
}; |
@@ -1,45 +0,47 @@ | ||
"use strict"; | ||
const config = { | ||
'astroboy-security-csrf': { | ||
priority: 2, | ||
enable: false, | ||
options: { | ||
env: ['prod'], | ||
excluded: ['GET', 'HEAD', 'OPTIONS'], | ||
csrfSecretName: 'csrf_secret', | ||
csrfTokenName: 'csrf_token', | ||
saltLength: 10, | ||
secretLength: 18, | ||
maxAge: 3 * 3600 * 1000, | ||
}, | ||
module.exports = { | ||
'astroboy-security-csrf': { | ||
priority: 2, | ||
enable: false, | ||
options: { | ||
env: ['prod'], | ||
excluded: ['GET', 'HEAD', 'OPTIONS'], | ||
csrfSecretName: 'csrf_secret', | ||
csrfTokenName: 'csrf_token', | ||
saltLength: 10, | ||
secretLength: 18, | ||
maxAge: 3 * 3600 * 1000, | ||
}, | ||
'astroboy-security-cto': { | ||
priority: 10, | ||
enable: true, | ||
options: 'nosniff', | ||
}, | ||
'astroboy-security-cto': { | ||
priority: 10, | ||
enable: true, | ||
options: 'nosniff', | ||
}, | ||
'astroboy-security-frameOptions': { | ||
priority: 10, | ||
enable: true, | ||
options: 'SAMEORIGIN', | ||
}, | ||
'astroboy-security-hsts': { | ||
priority: 10, | ||
enable: true, | ||
options: { | ||
maxAge: 365 * 24 * 3600, | ||
}, | ||
'astroboy-security-frameOptions': { | ||
priority: 10, | ||
enable: true, | ||
options: 'SAMEORIGIN', | ||
}, | ||
'astroboy-security-hsts': { | ||
priority: 10, | ||
enable: true, | ||
options: { | ||
maxAge: 365 * 24 * 3600, | ||
}, | ||
}, | ||
'astroboy-security-xss': { | ||
enable: true, | ||
priority: 20, | ||
options: {}, | ||
}, | ||
'astroboy-security-xssProtection': { | ||
priority: 10, | ||
enable: true, | ||
options: '1; mode=block', | ||
}, | ||
}, | ||
'astroboy-security-xss': { | ||
enable: true, | ||
priority: 20, | ||
options: {}, | ||
}, | ||
'astroboy-security-xssProtection': { | ||
priority: 10, | ||
enable: true, | ||
options: '1; mode=block', | ||
}, | ||
}; | ||
module.exports = config; | ||
//# sourceMappingURL=middleware.default.js.map |
@@ -1,13 +0,10 @@ | ||
"use strict"; | ||
/** | ||
* https://github.com/koajs/static | ||
*/ | ||
// @ts-ignore typings missed | ||
const staticM = require("koa-static"); | ||
const factory = function (options, app) { | ||
let fn = staticM(options.root, options); | ||
fn._name = 'static'; | ||
return fn; | ||
}; | ||
module.exports = factory; | ||
//# sourceMappingURL=astroboy-static.js.map | ||
const staticM = require('koa-static'); | ||
module.exports = function (options, app) { | ||
let fn = staticM(options.root, options); | ||
fn._name = 'static'; | ||
return fn; | ||
}; |
@@ -1,13 +0,13 @@ | ||
"use strict"; | ||
const path = require("path"); | ||
const config = { | ||
'astroboy-static': { | ||
priority: 3, | ||
enable: true, | ||
options: { | ||
root: path.resolve('/tmp/static'), | ||
}, | ||
}, | ||
}; | ||
module.exports = config; | ||
//# sourceMappingURL=middleware.default.js.map | ||
const path = require('path'); | ||
module.exports = { | ||
'astroboy-static': { | ||
priority: 3, | ||
enable: true, | ||
options: { | ||
root: path.resolve('/tmp/static') | ||
} | ||
} | ||
} |
@@ -1,8 +0,7 @@ | ||
"use strict"; | ||
const config = { | ||
'astroboy-static': { | ||
enable: false, | ||
}, | ||
}; | ||
module.exports = config; | ||
//# sourceMappingURL=middleware.prod.js.map | ||
module.exports = { | ||
'astroboy-static': { | ||
enable: false | ||
} | ||
}; |
@@ -1,13 +0,13 @@ | ||
"use strict"; | ||
const ViewManager_1 = require("../lib/ViewManager"); | ||
const ViewManager = require('../lib/ViewManager'); | ||
const VIEW = Symbol('Application#view'); | ||
const app = { | ||
get view() { | ||
if (!this[VIEW]) { | ||
this[VIEW] = new ViewManager_1.ViewManager(this); | ||
} | ||
return this[VIEW]; | ||
}, | ||
}; | ||
module.exports = app; | ||
//# sourceMappingURL=application.js.map | ||
module.exports = { | ||
get view() { | ||
if (!this[VIEW]) { | ||
this[VIEW] = new ViewManager(this); | ||
} | ||
return this[VIEW]; | ||
} | ||
}; |
@@ -1,24 +0,39 @@ | ||
"use strict"; | ||
const ContextView_1 = require("../lib/ContextView"); | ||
const ContextView = require('../lib/ContextView'); | ||
const VIEW = Symbol('Context#view'); | ||
const ctx = { | ||
get view() { | ||
if (!this[VIEW]) { | ||
this[VIEW] = new ContextView_1.ContextView(this); | ||
} | ||
return this[VIEW]; | ||
}, | ||
render(...args) { | ||
return this.renderView(...args).then((body) => { | ||
this.body = body; | ||
}); | ||
}, | ||
renderView(...args) { | ||
return this.view.render(...args); | ||
}, | ||
renderString(...args) { | ||
return this.view.render(...args); | ||
}, | ||
}; | ||
module.exports = ctx; | ||
//# sourceMappingURL=context.js.map | ||
module.exports = { | ||
get view() { | ||
if (!this[VIEW]) { | ||
this[VIEW] = new ContextView(this); | ||
} | ||
return this[VIEW]; | ||
}, | ||
/** | ||
* Render a file, then set to body, the parameter is same as {@link @ContextView#render} | ||
* @return {Promise} result | ||
*/ | ||
render(...args) { | ||
return this.renderView(...args).then(body => { | ||
this.body = body; | ||
}); | ||
}, | ||
/** | ||
* Render a file, same as {@link @ContextView#render} | ||
* @return {Promise} result | ||
*/ | ||
renderView(...args) { | ||
return this.view.render(...args); | ||
}, | ||
/** | ||
* Render template string, same as {@link @ContextView#renderString} | ||
* @return {Promise} result | ||
*/ | ||
renderString(...args) { | ||
return this.view.renderString(...args); // NOTE: 不存在这个方法 | ||
}, | ||
} |
@@ -1,48 +0,57 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const path = require("path"); | ||
const assert = require("assert"); | ||
const path = require('path'); | ||
const assert = require('assert'); | ||
const RENDER = Symbol.for('contextView#render'); | ||
const RENDER_STRING = Symbol.for('contextView#renderString'); | ||
const GET_VIEW_ENGINE = Symbol.for('contextView#getViewEngine'); | ||
class ContextView { | ||
constructor(ctx) { | ||
this.ctx = ctx; | ||
this.app = this.ctx.app; | ||
this.viewManager = this.app.view; | ||
this.config = this.app.view.config; | ||
constructor(ctx) { | ||
this.ctx = ctx; | ||
this.app = this.ctx.app; | ||
this.viewManager = this.app.view; | ||
this.config = this.app.view.config; | ||
} | ||
render(...args) { | ||
return this[RENDER](...args); | ||
} | ||
async [RENDER](name, state = {}, options = {}) { | ||
const filename = await this.viewManager.resolve(name); | ||
// get the name of view engine, | ||
// if viewEngine is specified in options, don't match extension | ||
let viewEngineName = options.viewEngine; | ||
if (!viewEngineName) { | ||
const ext = path.extname(filename); | ||
viewEngineName = this.viewManager.extMap.get(ext); | ||
} | ||
render(...args) { | ||
return this[RENDER](...args); | ||
// use the default view engine that is configured if no matching above | ||
if (!viewEngineName) { | ||
viewEngineName = this.config.defaultViewEngine; | ||
} | ||
async [RENDER](name, state = {}, options = {}) { | ||
const filename = await this.viewManager.resolve(name); | ||
// get the name of view engine, | ||
// if viewEngine is specified in options, don't match extension | ||
let viewEngineName = options.viewEngine; | ||
if (!viewEngineName) { | ||
const ext = path.extname(filename); | ||
viewEngineName = this.viewManager.extMap.get(ext); | ||
} | ||
// use the default view engine that is configured if no matching above | ||
if (!viewEngineName) { | ||
viewEngineName = this.config.defaultViewEngine; | ||
} | ||
assert(viewEngineName, `Can't find viewEngine for ${filename}`); | ||
// get view engine and render | ||
const view = this[GET_VIEW_ENGINE](viewEngineName); | ||
return await view.render(filename, state, options); | ||
} | ||
[GET_VIEW_ENGINE](name) { | ||
const ViewEngine = this.viewManager.get(name); | ||
assert(ViewEngine, `Can't find ViewEngine "${name}"`); | ||
// use view engine to render | ||
const engine = new ViewEngine(this.ctx); | ||
// wrap render and renderString to support both async function and generator function | ||
// if (engine.render) engine.render = this.app.toAsyncFunction(engine.render); | ||
// if (engine.renderString) engine.renderString = this.app.toAsyncFunction(engine.renderString); | ||
return engine; | ||
} | ||
assert(viewEngineName, `Can't find viewEngine for ${filename}`); | ||
// get view engine and render | ||
const view = this[GET_VIEW_ENGINE](viewEngineName); | ||
return await view.render(filename, state, options); | ||
} | ||
[GET_VIEW_ENGINE](name) { | ||
const ViewEngine = this.viewManager.get(name); | ||
assert(ViewEngine, `Can't find ViewEngine "${name}"`); | ||
// use view engine to render | ||
const engine = new ViewEngine(this.ctx); | ||
// wrap render and renderString to support both async function and generator function | ||
// if (engine.render) engine.render = this.app.toAsyncFunction(engine.render); | ||
// if (engine.renderString) engine.renderString = this.app.toAsyncFunction(engine.renderString); | ||
return engine; | ||
} | ||
} | ||
exports.ContextView = ContextView; | ||
//# sourceMappingURL=ContextView.js.map | ||
module.exports = ContextView; |
@@ -1,69 +0,79 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const assert = require("assert"); | ||
const path = require("path"); | ||
const fs = require("fs-extra"); | ||
const assert = require('assert'); | ||
const path = require('path'); | ||
const fs = require('fs-extra'); | ||
class ViewManager extends Map { | ||
/** | ||
* @param {Application} app - application instance | ||
*/ | ||
constructor(app) { | ||
super(); | ||
this.config = app.config.view; | ||
if (typeof this.config.root === 'string') { | ||
this.config.root = [this.config.root]; | ||
} | ||
this.extMap = new Map(); | ||
this.fileMap = new Map(); | ||
for (const ext of Object.keys(this.config.mapping)) { | ||
this.extMap.set(ext, this.config.mapping[ext]); | ||
} | ||
/** | ||
* @param {Application} app - application instance | ||
*/ | ||
constructor(app) { | ||
super(); | ||
this.config = app.config.view; | ||
if (typeof this.config.root === 'string') { | ||
this.config.root = [this.config.root]; | ||
} | ||
/** | ||
* This method can register view engine. | ||
* | ||
* You can define a view engine class contains two method, `render` and `renderString` | ||
* | ||
* ```js | ||
* class View { | ||
* render() {} | ||
* renderString() {} | ||
* } | ||
* ``` | ||
* @param {String} name - the name of view engine | ||
* @param {Object} viewEngine - the class of view engine | ||
*/ | ||
use(name, viewEngine) { | ||
assert(name, 'name is required'); | ||
assert(!this.has(name), `${name} has been registered`); | ||
assert(viewEngine, 'viewEngine is required'); | ||
assert(viewEngine.prototype.render, 'viewEngine should implement `render` method'); | ||
assert(viewEngine.prototype.renderString, 'viewEngine should implement `renderString` method'); | ||
this.set(name, viewEngine); | ||
this.extMap = new Map(); | ||
this.fileMap = new Map(); | ||
for (const ext of Object.keys(this.config.mapping)) { | ||
this.extMap.set(ext, this.config.mapping[ext]); | ||
} | ||
async resolve(name) { | ||
const config = this.config; | ||
// check cache | ||
let filename = this.fileMap.get(name); | ||
if (config.cache && filename) { | ||
return filename; | ||
} | ||
// try find it with default extension | ||
filename = this.resolvePath([name, name + config.defaultExtension], config.root); | ||
// set cache | ||
this.fileMap.set(name, filename); | ||
return filename; | ||
} | ||
/** | ||
* This method can register view engine. | ||
* | ||
* You can define a view engine class contains two method, `render` and `renderString` | ||
* | ||
* ```js | ||
* class View { | ||
* render() {} | ||
* renderString() {} | ||
* } | ||
* ``` | ||
* @param {String} name - the name of view engine | ||
* @param {Object} viewEngine - the class of view engine | ||
*/ | ||
use(name, viewEngine) { | ||
assert(name, 'name is required'); | ||
assert(!this.has(name), `${name} has been registered`); | ||
assert(viewEngine, 'viewEngine is required'); | ||
assert(viewEngine.prototype.render, 'viewEngine should implement `render` method'); | ||
assert(viewEngine.prototype.renderString, 'viewEngine should implement `renderString` method'); | ||
this.set(name, viewEngine); | ||
} | ||
async resolve(name) { | ||
const config = this.config; | ||
// check cache | ||
let filename = this.fileMap.get(name); | ||
if (config.cache && filename) { | ||
return filename; | ||
} | ||
resolvePath(names, root) { | ||
for (const name of names) { | ||
for (const dir of root) { | ||
const filename = path.resolve(dir, name); | ||
if (fs.existsSync(filename)) { | ||
return filename; | ||
} | ||
} | ||
// try find it with default extension | ||
filename = this.resolvePath([name, name + config.defaultExtension], config.root); | ||
// set cache | ||
this.fileMap.set(name, filename); | ||
return filename; | ||
} | ||
resolvePath(names, root) { | ||
for (const name of names) { | ||
for (const dir of root) { | ||
const filename = path.resolve(dir, name); | ||
if (fs.existsSync(filename)) { | ||
return filename; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
exports.ViewManager = ViewManager; | ||
//# sourceMappingURL=ViewManager.js.map | ||
module.exports = ViewManager; |
@@ -1,15 +0,15 @@ | ||
"use strict"; | ||
const path = require("path"); | ||
const config = app => { | ||
return { | ||
view: { | ||
root: path.join(app.ROOT_PATH, 'app/views'), | ||
cache: true, | ||
defaultExtension: '.html', | ||
defaultViewEngine: '', | ||
mapping: {}, | ||
}, | ||
}; | ||
}; | ||
module.exports = config; | ||
//# sourceMappingURL=config.default.js.map | ||
const path = require('path'); | ||
module.exports = app => { | ||
return { | ||
view: { | ||
root: path.join(app.ROOT_PATH, 'app/views'), | ||
cache: true, | ||
defaultExtension: '.html', | ||
defaultViewEngine: '', | ||
mapping: {} | ||
} | ||
} | ||
} |
@@ -1,8 +0,7 @@ | ||
"use strict"; | ||
const config = { | ||
view: { | ||
cache: false, | ||
}, | ||
}; | ||
module.exports = config; | ||
//# sourceMappingURL=config.development.js.map | ||
module.exports = { | ||
view: { | ||
cache: false | ||
} | ||
} |
# Astroboy | ||
Astroboy(阿童木)is a Nodejs SFB(Separation of Front and Back ends) framework, built on koa2. | ||
[](https://badge.fury.io/js/astroboy) | ||
## Install | ||
```zsh | ||
yarn add astroboy | ||
``` | ||
## Run app with node | ||
### 1. Compile project | ||
```zsh | ||
tsc && cp config app/config | ||
``` | ||
### 2. Start app.js | ||
```zsh | ||
cd dist && node app/app.js | ||
``` | ||
## Run app with ts-node | ||
### 1. install ts-node and typescript | ||
```zsh | ||
yarn add typescript ts-node | ||
``` | ||
### 2. Start app | ||
```zsh | ||
npx ts-node app/app.ts | ||
``` | ||
## Run app in development mode | ||
- use [astroboy-cli](https://www.npmjs.com/package/astroboy-cli) for js or js/ts hybrid project | ||
- use [@exoskeleton/cli](https://www.npmjs.com/package/@exoskeleton/cli) for typescript-only project | ||
## More details | ||
> For more details, please refer to [https://astroboy-lab.github.io/astroboy](https://astroboy-lab.github.io/astroboy) |
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
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances 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
946567
15
1
2
84
1479
4
1
- Removed@types/fs-extra@^5.1.0
- Removed@types/koa@^2.0.46
- Removed@types/lodash@^4.14.123
- Removedtslib@1.9.3
- Removed@types/accepts@1.3.7(transitive)
- Removed@types/body-parser@1.19.5(transitive)
- Removed@types/connect@3.4.38(transitive)
- Removed@types/content-disposition@0.5.8(transitive)
- Removed@types/cookies@0.9.0(transitive)
- Removed@types/express@5.0.0(transitive)
- Removed@types/express-serve-static-core@5.0.6(transitive)
- Removed@types/fs-extra@5.1.0(transitive)
- Removed@types/http-assert@1.5.6(transitive)
- Removed@types/http-errors@2.0.4(transitive)
- Removed@types/keygrip@1.0.6(transitive)
- Removed@types/koa@2.15.0(transitive)
- Removed@types/koa-compose@3.2.8(transitive)
- Removed@types/lodash@4.17.15(transitive)
- Removed@types/mime@1.3.5(transitive)
- Removed@types/node@22.13.5(transitive)
- Removed@types/qs@6.9.18(transitive)
- Removed@types/range-parser@1.2.7(transitive)
- Removed@types/send@0.17.4(transitive)
- Removed@types/serve-static@1.15.7(transitive)
- Removedtslib@1.9.3(transitive)
- Removedundici-types@6.20.0(transitive)