diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 885a43a..0000000 --- a/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -test -.eslintrc.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 1395ec1..0000000 --- a/.eslintrc.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = { - env: { - node: true, - commonjs: true, - es6: true, - }, - extends: ['eslint:recommended', 'prettier'], - plugins: ['prettier'], - parser: "babel-eslint", - parserOptions: { - ecmaVersion: 2020, - }, - rules: { - indent: ['error', 4, { SwitchCase: 1 }], - 'linebreak-style': ['warn', 'unix'], - semi: ['error', 'never'], - 'no-tabs': 'off', - 'object-property-newline': 'off', - 'require-atomic-updates': 'off', - 'prettier/prettier': 'error', - 'no-useless-escape': "off", - }, - overrides: [ - { - "files": ["./*.js"] - } - ] -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index b9cc369..74b18dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules +dist .idea -.vscode \ No newline at end of file +.vscode diff --git a/.lintstagedrc b/.lintstagedrc deleted file mode 100644 index d2804b5..0000000 --- a/.lintstagedrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "*.js": "eslint --fix" -} \ No newline at end of file diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..7445623 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,311 @@ +# lowcode-controller + +[English](./readme.md) | [简体中文](./README.zh-CN.md) + +`lowcode-controller` 是一个通过声明式配置生成 Sequelize CRUD 控制器逻辑的工具。它支持分页查询、列表查询、单条查询、新增、更新、逻辑删除、物理删除、参数校验、生命周期钩子和自定义响应字段。 + +项目源码使用严格模式 TypeScript 编写,npm 包同时提供 CommonJS JavaScript、source map 和类型声明。现有 JavaScript 项目仍然可以继续使用 `require()`。 + +## 安装 + +```bash +npm install lowcode-controller +``` + +## 基本使用 + +```ts +import path from 'node:path' +import { + LowCodeController, + type LowCodeControllerConfig, +} from 'lowcode-controller' + +import CatModel from '../model/cat_model' + +LowCodeController.setGlobalDBPath(path.join(__dirname, '../db/mysql')) +LowCodeController.setUserNameField('username') + +const config: LowCodeControllerConfig = { + pageQuery: { + query: { + cat_name: { value: 'cat_name', like: true }, + age: { type: 'constant', value: 2 }, + }, + extraOptions: { + order: [['cat_name', 'DESC']], + attributes: ['cat_name', 'age', 'job'], + }, + }, + getList: { + query: { + birthday: { + type: 'varTime', + value: ['start', 'end'], + }, + }, + afterQueryHook: async results => + results.map(item => ({ ...item, description: 'cute cat' })), + }, + create: { + validate: { + cat_name: { name: '猫名', rule: 'required' }, + }, + constantCreate: { age: 2 }, + enableBatch: true, + }, + update: { + pick: ['job'], + afterUpdateHook: async updateItem => { + if (updateItem.job === 'rollback') { + throw new Error('roll back') + } + }, + }, +} + +class CatsController extends LowCodeController { + public constructor() { + super(CatModel, config, null, { + creatorField: 'creator', + updatorField: 'updator', + }) + } +} + +export default new CatsController() +``` + +JavaScript 用法保持不变: + +```js +const { LowCodeController, utils } = require('lowcode-controller') +``` + +## Koa 路由 + +控制器方法会在构造函数中绑定实例,因此可以直接传给路由。 + +```js +const router = require('koa-router')() +const Cat = require('./controller/cats') + +router.get('/api/cats', Cat.pageQuery) +router.get('/api/cats/list', Cat.getList) +router.get('/api/cats/:id', Cat.getSingle) +router.post('/api/cats', Cat.create) +router.put('/api/cats', Cat.update) +router.put('/api/cats/:id', Cat.update) +router.delete('/api/cats/:id', Cat.delete) +``` + +## 全局配置 + +### `setGlobalDBPath(dbPath)` + +加载导出默认 Sequelize 实例的模块。必须在创建控制器实例之前调用。 + +```ts +LowCodeController.setGlobalDBPath('/absolute/path/to/db-module') +``` + +### `setUserNameField(field)` + +设置从上下文中读取创建人和更新人的字段路径,支持 `state.user.name` 这样的嵌套路径。 + +```ts +LowCodeController.setUserNameField('username') +``` + +### `setCustomResField(code, message, data)` + +修改所有自动生成响应所使用的字段名。 + +```ts +LowCodeController.setCustomResField('code', 'message', 'result') +``` + +默认响应结构如下: + +```json +{ + "errno": 0, + "errmsg": "success", + "data": null +} +``` + +## 构造函数 + +```ts +new LowCodeController(model, config, db, options) +``` + +| 参数 | 说明 | +| ---------------------- | ------------------------------------------------------- | +| `model` | 自动生成的处理方法所使用的 Sequelize Model | +| `config` | 各处理方法的配置 | +| `db` | 可选 Sequelize 实例,默认使用全局配置的实例 | +| `options.creatorField` | 新增时写入创建人的 Model 字段 | +| `options.updatorField` | 新增、更新和逻辑删除时写入更新人的 Model 字段 | +| `options.defaultQuery` | 合并到普通查询中的默认条件,默认为 `{ delete_flag: 1 }` | +| `options.updateDelete` | 逻辑删除时写入的字段,默认为 `{ delete_flag: 0 }` | + +## 查询 DSL + +配置对象的每个键都是数据库字段。通常情况下,`value` 表示从请求参数中读取值所使用的字段名。 + +```ts +const query = { + // WHERE cat_name LIKE '%ctx.query.cat_name%' + cat_name: { + value: 'cat_name', + like: true, + require: true, + }, + + // WHERE age = 2 + age: { + type: 'constant', + value: 2, + }, + + // WHERE creator = ctx.username + creator: { + type: 'constant', + ctxField: 'username', + }, + + // WHERE color IN ctx.query.colors + color: { + type: 'varArray', + value: 'colors', + }, + + // WHERE birthday >= startTime AND birthday <= endTime + birthday: { + type: 'varTime', + value: ['startTime', 'endTime'], + }, + + // JSON_CONTAINS(tags, ctx.query.tag) + tags: { + value: 'tag', + json: true, + }, + + // 以下条件使用 OR 连接 + $or: { + status: { + type: 'constant', + operator: '$in', + value: ['ready', 'done'], + }, + height: { + type: 'constant', + operator: '$ne', + value: 30, + }, + }, +} +``` + +支持的配置包括: + +| 配置 | 说明 | +| ------------------- | --------------------------------------------------------- | +| `type: 'constant'` | 使用配置的常量或 `ctxField`,不读取请求参数 | +| `type: 'varArray'` | 将请求数组转换为 `Op.in` 条件 | +| `type: 'varTime'` | 从请求中读取开始和结束字段,生成 `Op.gte` / `Op.lte` 条件 | +| `operator: '$in'` | 生成 `Op.in` 条件 | +| `operator: '$ne'` | 生成 `Op.ne` 条件 | +| `operator: '$time'` | 生成固定开始和结束时间条件 | +| `like` | 使用 `Op.like` 并在值两侧添加 `%` | +| `json` | 使用 MySQL `JSON_CONTAINS` | +| `parseNumber` | 使用 `Number()` 转换请求值 | +| `require` | 请求值不存在时抛出异常 | + +## 控制器配置 + +### `pageQuery` + +从 `ctx.query` 中读取 `size` 和 `page`。偏移量为 `size * page`,因此页码从 0 开始。返回数据为 `{ list, total }`。 + +- `query`:查询 DSL。 +- `extraOptions`:合并到 Sequelize `findAndCountAll` 的配置。 +- `filter`:同步处理每一条查询结果。 +- `beforeQueryHook(query, extraOptions, ctx)`:查询前执行;返回真值时停止后续处理。 +- `afterQueryHook(results, query, extraOptions, ctx)`:查询后执行;返回的真值作为响应数据。 + +### `getList` 和 `getSingle` + +`getList` 使用与 `pageQuery` 相同的查询钩子,并调用 `findAll`。`getSingle` 优先使用路由参数 `id`,没有 `id` 时根据配置构造查询并调用 `findOne`。 + +### `create` + +- `validate`:Validator.js 校验规则,格式为 `{ field: { name, rule } }`。 +- `constantCreate`:覆盖请求数据的固定字段。 +- `pickCreate`:将请求源字段映射到目标 Model 字段。 +- `enableBatch`:请求体为数组时使用 `bulkCreate`。 +- `extraOptions`:传递给 Sequelize 的额外配置。 +- `beforeInsertHook(createItem, ctx)`:插入前执行;返回真值时停止后续处理。 +- `afterInsertHook(insertItem, transaction, ctx)`:在托管事务中执行,必须是异步函数。 + +### `update` + +存在路由参数 `id` 时根据 `id` 更新;否则使用 `ctx.request.body` 和配置的查询 DSL 构建更新条件。 + +- `query`:没有路由 `id` 时使用的查询 DSL。 +- `validate`:更新请求的 Validator.js 校验规则。 +- `pick`:允许更新的请求字段白名单。 +- `itemBlock`:要求当前数据库记录的指定字段符合配置值。 +- `extraOptions`:传递给 Sequelize `update` 的配置。 +- `beforeUpdateHook(updateItem, item, ctx)`:更新前执行;返回真值时停止后续处理。 +- `afterUpdateHook(updateItem, item, raw, transaction, ctx)`:更新后在托管事务中执行,必须是异步函数。 + +### `delete` + +默认执行逻辑删除,写入 `updateDelete` 配置的字段。设置 `physicDelete: true` 时调用 Sequelize `destroy` 执行物理删除。 + +- `query`:可选查询 DSL,配置后从 `ctx.query` 构造条件。 +- `extraOptions`:传递给 Sequelize `update` 或 `destroy` 的配置。 +- `beforeDeleteHook(query, extraOptions, ctx)`:删除前执行;返回真值时停止后续处理。 +- `afterDeleteHook`:删除后在托管事务中执行,必须是异步函数。 + +## 工具函数 + +`utils` 导出控制器内部使用的底层工具: + +```ts +import { utils } from 'lowcode-controller' + +utils.resSuccess(data) +utils.resFail(1, 'message') +utils.timeQuery(['2024-01-01', '2024-12-31']) +utils.validator.validateJson(data, rules) +utils.curdHelper.findByList(model, options) +``` + +## 开发、测试和发布 + +```bash +npm install +npm run typecheck +npm test +npm run build +npm pack --dry-run +``` + +`npm publish` 会通过 `prepublishOnly` 自动执行完整验证,并通过 `prepack` 重新构建 `dist`。 + +需要本地 MySQL 测试环境时,可以运行原项目的集成测试: + +```bash +npm run test:integration +``` + +数据库连接配置位于 `test/instance/config.js`。 + +## License + +ISC diff --git a/index.js b/index.js deleted file mode 100644 index f64bfe8..0000000 --- a/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const LowCodeController = require('./lib/lowcode_controller') -const utils = require('./lib/utils') - -module.exports = { - LowCodeController, - utils, -} diff --git a/lib/lowcode_controller.js b/lib/lowcode_controller.js deleted file mode 100644 index 4a36724..0000000 --- a/lib/lowcode_controller.js +++ /dev/null @@ -1,725 +0,0 @@ -const { - curdHelper, - smartFuncExecute, - resFail, - resSuccess, - setCustomResField, - validator, - isAsyncOrPromise, - errCatch, - timeQuery, -} = require('./utils') -const _ = require('lodash') -const { Sequelize } = require('sequelize') -const { fn, col } = Sequelize -const Op = Sequelize.Op -let sq -let usernameField - -class LowCodeController { - constructor(model, config = {}, db, extraOptions = {}) { - if (!sq) { - throw new Error( - 'no mysql db instance, you should invoke setGlobalDBPath first' - ) - } - this.model = model - this.config = config - this.sq = db || sq - const { creatorField, updatorField, defaultQuery, updateDelete } = - extraOptions - creatorField && (this.creatorField = creatorField) - updatorField && (this.updatorField = updatorField) - this.defaultQuery = defaultQuery || { delete_flag: 1 } - this.updateDelete = updateDelete || { delete_flag: 0 } - this.pageQuery = this.pageQuery.bind(this) - this.getList = this.getList.bind(this) - this.getSingle = this.getSingle.bind(this) - this.create = this.create.bind(this) - this.update = this.update.bind(this) - this.delete = this.delete.bind(this) - } - - static setCustomResField(codeFieldKey = 'errno', msgFieldKey = 'errmsg', dataFieldKey = 'data') { - setCustomResField(codeFieldKey, msgFieldKey, dataFieldKey) - } - - static setGlobalDBPath(dbPath) { - sq = require(dbPath) - } - - static setUserNameField(field) { - usernameField = field - } - - static getQuery(config, field, sourceBody, where = {}, ctx) { - if (config[field]) { - const { query } = config[field] - if (query) { - for (let k in query) { - let queryField = query[k] - if (k === '$time') { - let queryTime = queryField - for (let k in queryTime) { - let start = sourceBody[queryTime[k][0]] - let end = - sourceBody[queryTime[k][1]](start || end) && - (where[k] = {}) - start && (where[k][Op.gte] = start) - end && (where[k][Op.lte] = end) - } - } else if (k === '$or') { - queryField = query[k] - where[Op.or] = [] - for (let f in queryField) { - LowCodeController.setFieldQuery( - queryField[f], - f, - where, - sourceBody, - k, - ctx - ) - } - } else { - LowCodeController.setFieldQuery( - queryField, - k, - where, - sourceBody, - null, - ctx - ) - } - } - } - } - return where - } - - static setFieldQuery( - field, - modelField, - where, - sourceBody, - parentFiled, - ctx - ) { - if (!field) { - return where - } - let { type, value } = field - switch (type) { - case 'constant': { - let { ctxField, operator } = field - ctxField && (value = _.get(ctx, ctxField)) - if (operator === '$in') { - if (parentFiled === '$or') { - where.push({ [modelField]: { [Op.in]: value } }) - } else { - where[modelField] = { [Op.in]: value } - } - } else if (operator === '$ne') { - if (parentFiled === '$or') { - where.push({ [modelField]: { [Op.ne]: value } }) - } else { - where[modelField] = { [Op.ne]: value } - } - } else if (operator === '$time') { - let query = timeQuery(value) - if (parentFiled === '$or') { - where.push({ [modelField]: query }) - } else { - where[modelField] = query - } - } else { - LowCodeController._queryFieldDeal( - field, - where, - modelField, - value, - parentFiled - ) - } - break - } - - case 'varArray': { - let v = sourceBody[value] - if (v) { - if (parentFiled === '$or') { - where.push({ - [modelField]: { [Op.in]: v }, - }) - } else { - where[modelField] = { [Op.in]: v } - } - } - break - } - - case 'varTime': { - let query = timeQuery(value, sourceBody) - if (query) { - if (parentFiled === '$or') { - where.push({ - [modelField]: query, - }) - } else { - where[modelField] = query - } - } - break - } - - //var - default: { - let v = sourceBody[value] - if (v) { - LowCodeController._queryFieldDeal( - field, - where, - modelField, - v, - parentFiled, - ) - } else { - if (field.require) { - throw new Error(`${value}必填`) - } - } - break - } - } - } - - static _queryFieldDeal(field, where, modelField, value, parentFiled) { - const { like, json, parseNumber, time } = field - if (parentFiled === '$or') { - if (like) { - where.push({ [modelField]: { [Op.like]: `%${value}%` } }) - } else if (parseNumber) { - where.push({ [modelField]: Number(value) }) - } else if (json) { - where.push(fn('JSON_CONTAINS', col(modelField), `\"${value}\"`)) - } else { - where.push({ [modelField]: value }) - } - } else { - if (like) { - where[modelField] = { [Op.like]: `%${value}%` } - } else if (parseNumber) { - where[modelField] = Number(value) - } else if (json) { - where[Op.and] = [ - fn('JSON_CONTAINS', col(modelField), `\"${value}\"`), - ] - } else { - where[modelField] = value - } - } - } - - pickFiledFromConfig(path) { - return path ? _.get(this.config, path) : null - } - - validateHelp(source, rules = null) { - if (rules) { - if (_.isArray(source)) { - for (let i = 0; i < source.length; i++) { - let validateResult = validator.validateJson( - source[i], - rules - ) - if (!validateResult.success) { - return validateResult - } - } - } else { - let validateResult = validator.validateJson(source, rules) - if (!validateResult.success) { - return validateResult - } - } - } - return null - } - - async pageQuery(ctx) { - const beforeQueryHook = this.pickFiledFromConfig( - 'pageQuery.beforeQueryHook' - ) - const afterQueryHook = this.pickFiledFromConfig( - 'pageQuery.afterQueryHook' - ) - const extraOptions = this.pickFiledFromConfig('pageQuery.extraOptions') - let filter = this.pickFiledFromConfig('pageQuery.filter') - - const { size, page } = ctx.query - let where = LowCodeController.getQuery( - this.config, - 'pageQuery', - ctx.query, - {}, - ctx - ) - let query = { - size, - page, - query: Object.assign(_.cloneDeep(this.defaultQuery), where), - } - - if (beforeQueryHook) { - const needReturn = await smartFuncExecute.call( - this, - beforeQueryHook, - query, - extraOptions, - ctx, - ) - if (needReturn) { - return null - } - } - - if (afterQueryHook) { - let sourceResults = await curdHelper.findByPage(this.model, { - pageQuery: query, - extraOptions, - filter, - }) - const results = await smartFuncExecute.call( - this, - afterQueryHook, - sourceResults, - query, - extraOptions, - ctx, - ) - ctx.body = resSuccess(results || sourceResults) - } else { - await curdHelper.findByPage(this.model, { - pageQuery: query, - extraOptions, - filter, - ctx, - }) - } - } - - async create(ctx) { - let { body } = ctx.request - let validateResult = this.validateHelp( - body, - this.pickFiledFromConfig('create.validate') - ) - if (validateResult && !validateResult.success) { - return (ctx.body = resFail(1, validateResult.message)) - } - - let constantCreate = this.pickFiledFromConfig('create.constantCreate') - let pickCreate = this.pickFiledFromConfig('create.pickCreate') - const enableBatch = this.pickFiledFromConfig('create.enableBatch') - const beforeInsertHook = this.pickFiledFromConfig( - 'create.beforeInsertHook' - ) - const afterInsertHook = this.pickFiledFromConfig( - 'create.afterInsertHook' - ) - const extraOptions = this.pickFiledFromConfig('create.extraOptions') - - let createItem = _.cloneDeep(body) - - if (usernameField) { - this.creatorField && - (createItem[this.creatorField] = _.get(ctx, usernameField)) - this.updatorField && - (createItem[this.updatorField] = _.get(ctx, usernameField)) - } - - if (constantCreate) { - createItem = Object.assign(createItem, constantCreate) - } - - if (pickCreate) { - for (let k in pickCreate) { - createItem[k] = createItem[pickCreate[k]] - } - } - - if (beforeInsertHook) { - const needReturn = await smartFuncExecute.call( - this, - beforeInsertHook, - createItem, - ctx, - ) - if (needReturn) { - return null - } - } - - let sourceResult = null - if (afterInsertHook) { - isAsyncOrPromise(afterInsertHook) - await this.sq - .transaction(t => { - return curdHelper - .create(this.model, { - saveObj: createItem, - transaction: t, - extraOptions, - enableBatch, - }) - .then(insertItem => { - sourceResult = insertItem - return afterInsertHook.call( - this, - insertItem, - t, - ctx, - ) - }) - }) - .then((result = null) => { - ctx.body = resSuccess(result || sourceResult) - }) - .catch(errCatch(ctx)) - } else { - await curdHelper.create(this.model, { - saveObj: createItem, - ctx, - extraOptions, - enableBatch, - }) - } - } - - async update(ctx) { - const id = ctx.params.id - const { body } = ctx.request - let query = null - let item = null - let updateItem = _.cloneDeep(body) - - let queryConfig = this.pickFiledFromConfig('update.query') - let validate = this.pickFiledFromConfig('update.validate') - const itemBlock = this.pickFiledFromConfig('update.itemBlock') - const pick = this.pickFiledFromConfig('update.pick') - const beforeUpdateHook = this.pickFiledFromConfig( - 'update.beforeUpdateHook' - ) - const afterUpdateHook = this.pickFiledFromConfig( - 'update.afterUpdateHook' - ) - const extraOptions = this.pickFiledFromConfig('update.extraOptions') - - if (id) { - query = Object.assign({ id }, this.defaultQuery) - } else if (queryConfig) { - query = LowCodeController.getQuery( - this.config, - 'update', - body, - { ...this.defaultQuery }, - ctx, - ) - } - item = await curdHelper.getSingle(this.model, { - query, - }) - if (!item) { - return (ctx.body = resFail(1, 'The item is not exists')) - } - if (!query) { - return (ctx.body = resFail( - 1, - 'Updates without query are prohibited' - )) - } - - if (validate) { - let validateResult = this.validateHelp(updateItem, validate) - if (validateResult && !validateResult.success) { - return (ctx.body = resFail(1, validateResult.message)) - } - } - - if (item && itemBlock) { - for (let k in itemBlock) { - if (item[k] !== itemBlock[k]['value']) { - return (ctx.body = resFail(1, itemBlock[k]['message'])) - } - } - } - - if (pick && _.isArray(pick)) { - updateItem = _.pick(updateItem, pick) - } - - if (usernameField) { - this.updatorField && - (updateItem[this.updatorField] = _.get(ctx, usernameField)) - } - - if (beforeUpdateHook) { - const needReturn = await smartFuncExecute.call( - this, - beforeUpdateHook, - updateItem, - item, - ctx, - ) - if (needReturn) { - return null - } - } - - if (afterUpdateHook) { - isAsyncOrPromise(afterUpdateHook) - await this.sq.transaction(t => { - return curdHelper - .update(this.model, { - query, - transaction: t, - updateObj: updateItem, - extraOptions, - }) - .then(raw => { - return afterUpdateHook.call( - this, - updateItem, - item, - raw, - t, - ctx, - ) - }) - .then(result => { - ctx.body = resSuccess(result) - }) - .catch(errCatch(ctx)) - }) - } else { - await curdHelper.update(this.model, { - query, - updateObj: updateItem, - ctx, - extraOptions, - }) - } - } - - async getSingle(ctx) { - let id = ctx.params.id - - let queryConfig = this.pickFiledFromConfig('getSingle.query') - const beforeQueryHook = this.pickFiledFromConfig( - 'getSingle.beforeQueryHook' - ) - const afterQueryHook = this.pickFiledFromConfig( - 'getSingle.afterQueryHook' - ) - const extraOptions = this.pickFiledFromConfig('getSingle.extraOptions') - - let query = {} - id && (query.id = id) - if (!id && queryConfig) { - query = LowCodeController.getQuery( - this.config, - 'getSingle', - ctx.query, - _.cloneDeep(this.defaultQuery), - ctx - ) - } - if (beforeQueryHook) { - const needReturn = await smartFuncExecute.call( - this, - beforeQueryHook, - query, - extraOptions, - ctx, - ) - if (needReturn) { - return null - } - } - if (afterQueryHook) { - let sourceResult = await curdHelper.getSingle(this.model, { - query, - extraOptions, - }) - let result = await smartFuncExecute.call( - this, - afterQueryHook, - sourceResult, - query, - extraOptions, - ctx, - ) - ctx.body = resSuccess(result || sourceResult) - } else { - await curdHelper.getSingle(this.model, { query, ctx, extraOptions }) - } - } - - async getList(ctx) { - let query = LowCodeController.getQuery( - this.config, - 'getList', - ctx.query, - _.cloneDeep(this.defaultQuery), - ctx, - ) - const beforeQueryHook = this.pickFiledFromConfig( - 'getList.beforeQueryHook' - ) - const afterQueryHook = this.pickFiledFromConfig( - 'getList.afterQueryHook' - ) - const extraOptions = this.pickFiledFromConfig('getList.extraOptions') - let filter = this.pickFiledFromConfig('getList.filter') - - if (beforeQueryHook) { - const needReturn = await smartFuncExecute.call( - this, - beforeQueryHook, - query, - extraOptions, - ctx, - ) - if (needReturn) { - return null - } - } - - if (afterQueryHook) { - let sourceResults = await curdHelper.findByList(this.model, { - query, - extraOptions, - filter, - }) - const results = await smartFuncExecute.call( - this, - afterQueryHook, - sourceResults, - query, - extraOptions, - ctx, - ) - ctx.body = resSuccess(results || sourceResults) - } else { - await curdHelper.findByList(this.model, { - query, - extraOptions, - filter, - ctx, - }) - } - } - - async delete(ctx) { - const id = ctx.params.id - let query = {} - id && (query.id = id) - - const beforeDeleteHook = this.pickFiledFromConfig( - 'delete.beforeDeleteHook' - ) - const afterDeleteHook = this.pickFiledFromConfig( - 'delete.afterDeleteHook' - ) - const extraOptions = this.pickFiledFromConfig('delete.extraOptions') - const physicDelete = this.pickFiledFromConfig('delete.physicDelete') - let queryConfig = this.pickFiledFromConfig('delete.query') - - if (queryConfig) { - query = LowCodeController.getQuery( - this.config, - 'delete', - ctx.query, - {}, - ctx - ) - } - - if (beforeDeleteHook) { - const needReturn = await smartFuncExecute.call( - this, - beforeDeleteHook, - query, - extraOptions, - ctx, - ) - if (needReturn) { - return null - } - } - - let updateDelete = this.updateDelete - if (usernameField) { - this.updatorField && - (updateDelete[this.updatorField] = _.get(ctx, usernameField)) - } - - if (afterDeleteHook) { - isAsyncOrPromise(afterDeleteHook) - await this.sq.transaction(t => { - if (physicDelete) { - return curdHelper - .physicDelete(this.model, { - query, - transaction: t, - extraOptions, - }) - .then(() => { - return afterDeleteHook.call( - this, - query, - extraOptions, - t, - ctx, - ) - }) - } else { - return curdHelper - .delete(this.model, { - query, - transaction: t, - updateObj: updateDelete, - extraOptions, - }) - .then(raw => { - return afterDeleteHook.call( - this, - query, - extraOptions, - raw, - t, - ctx, - ) - }) - } - }) - } else { - if (physicDelete) { - return curdHelper.physicDelete(this.model, { - query, - ctx, - extraOptions, - }) - } else { - return curdHelper.delete(this.model, { - query, - ctx, - extraOptions, - updateObj: updateDelete, - }) - } - } - } -} - -module.exports = LowCodeController diff --git a/lib/utils/common.js b/lib/utils/common.js deleted file mode 100644 index 45b191d..0000000 --- a/lib/utils/common.js +++ /dev/null @@ -1,92 +0,0 @@ -const _ = require('lodash') -const Op = require('sequelize').Op -let resField = ['errno', 'errmsg', 'data'] - -exports.isAsyncFunction = fn => { - return Object.prototype.toString.call(fn) === '[object AsyncFunction]' -} - -exports.isPromise = fn => { - return ( - !!fn && - (typeof fn === 'object' || typeof fn === 'function') && - typeof fn.then === 'function' - ) -} - -exports.resSuccess = (data, message) => { - return { - [resField[0]]: 0, - [resField[1]]: message || 'success', - [resField[2]]: data || null, - } -} - -exports.resFail = (code, message, data) => { - return { - [resField[0]]: code, - [resField[1]]: message || 'fail', - [resField[2]]: data || null, - } -} - -exports.setCustomResField = (code = 'errno', msg = 'errcode', data = 'errmsg') => { - resField = [code, msg, data] -} - -exports.smartFuncExecute = async function (func, ...args) { - if (Object.prototype.toString.call(func) === '[object AsyncFunction]') { - return await func.call(this, ...args) - } else { - return func.call(this, ...args) - } -} - -exports.isAsyncOrPromise = fn => { - if (!exports.isAsyncFunction(fn) && !exports.isPromise(fn)) { - throw new Error('afterXXXHook must be one of async function or promise') - } -} - -exports.errCatch = ctx => err => { - if (_.get(ctx, 'logger.error')) { - ctx.logger.error(err) - } else { - console.error(err) - } - if (ctx) { - return (ctx.body = this.resFail(1, err.message, err)) - } -} - -exports.batchAsyncFuncExec = async (asyncFunc, items = [], count = 50) => { - if (!exports.isAsyncFunction(asyncFunc)) { - throw Error('asyncFunc is not a validate async function') - } - let promises = [] - let result = [] - for (let i = 0; i < items.length; i++) { - let item = items[i] - if ((i + 1) % count === 0) { - promises.push(asyncFunc(item)) - result = result.concat(await Promise.all(promises)) - promises = [] - } else { - promises.push(asyncFunc(item)) - } - } - if (promises.length > 0) { - result = result.concat(await Promise.all(promises)) - } - return result -} - -exports.timeQuery = (value, sourceBody) => { - let query = {} - let none = true - let start = (sourceBody && value[0]) ? sourceBody[value[0]] : value[0] - let end = (sourceBody && value[1]) ? sourceBody[value[1]] : value[1] - start && (query[Op.gte] = start) && (none = false) - end && (query[Op.lte] = end) && (none = false) - return none ? null : query -} diff --git a/lib/utils/curd_helper.js b/lib/utils/curd_helper.js deleted file mode 100644 index 3f29836..0000000 --- a/lib/utils/curd_helper.js +++ /dev/null @@ -1,222 +0,0 @@ -const _ = require('lodash') -const utils = require('./common') - -module.exports = { - findByPage: async ( - model, - { pageQuery = {}, extraOptions = {}, filter, ctx = null } - ) => { - const { size = 10, page = 0, query = {} } = pageQuery - const options = { - limit: Number(size), - offset: Number(size) * Number(page), - where: query, - raw: true, - } - const data = await model.findAndCountAll( - Object.assign(options, extraOptions) - ) - const { rows, count } = data - const result = { - list: rows, - total: count, - } - if (rows && rows.length > 0 && filter) { - result.list = result.list.map(filter) - } - if (!ctx) { - return result - } else { - return (ctx.body = utils.resSuccess(result)) - } - }, - findByList: async ( - model, - { query = {}, extraOptions = {}, transaction, filter, ctx = null } - ) => { - const options = Object.assign( - { - where: query, - raw: true, - }, - extraOptions - ) - if (transaction) { - options.transaction = transaction - return model.findAll(options) - } - let results = await model.findAll(options) - if (results && results.length > 0 && filter) { - results = results.map(filter) - } - if (!ctx) { - return results - } else { - return (ctx.body = utils.resSuccess(results)) - } - }, - create: async ( - model, - { - saveObj, - ctx = null, - transaction, - extraOptions = {}, - enableBatch = false, - } - ) => { - let result = null - let options = extraOptions - if (enableBatch && _.isArray(saveObj)) { - if (transaction) { - options.transaction = transaction - return model.bulkCreate(saveObj, options) - } else { - result = (await model.bulkCreate(saveObj, options)).get({ - plain: true, - }) - } - } else { - if (transaction) { - options.transaction = transaction - return model.create(saveObj, options) - } else { - result = (await model.create(saveObj, options)).get({ - plain: true, - }) - } - } - if (!ctx) { - return result - } else { - return (ctx.body = utils.resSuccess(result)) - } - }, - getSingle: async ( - model, - { query, ctx = null, transaction, extraOptions = {} } - ) => { - let result = null - let options = Object.assign( - { - raw: true, - }, - extraOptions - ) - transaction && (options.transaction = transaction) - if (typeof query === 'string') { - if (transaction) { - return model.findByPk(query, options) - } else { - result = await model.findByPk(query, options) - } - } else { - options.where = query - if (transaction) { - return model.findOne(options) - } else { - result = await model.findOne(options) - } - } - if (!ctx) { - return result - } else { - return (ctx.body = utils.resSuccess(result)) - } - }, - update: async ( - model, - { query, updateObj = {}, ctx = null, transaction, extraOptions = {} } - ) => { - let options = Object.assign( - { - where: query, - }, - extraOptions - ) - if (transaction) { - options.transaction = transaction - return model.update(updateObj, options) - } else { - await model.update(updateObj, options) - } - if (!ctx) { - return true - } else { - return (ctx.body = utils.resSuccess()) - } - }, - delete: async ( - model, - { query, ctx = null, transaction, extraOptions = {}, updateObj } - ) => { - let update = updateObj || { delete_flag: 1 } - let options = Object.assign( - { - where: query, - }, - extraOptions - ) - if (transaction) { - options.transaction = transaction - return model.update(update, options) - } else { - await model.update(update, options) - } - if (!ctx) { - return true - } else { - return (ctx.body = utils.resSuccess()) - } - }, - physicDelete: async ( - model, - { query, ctx = null, transaction, extraOptions = {} } - ) => { - let options = Object.assign( - { - where: query, - }, - extraOptions - ) - if (transaction) { - options.transaction = transaction - return model.destroy(options) - } else { - await model.destroy(options) - } - if (!ctx) { - return true - } else { - return (ctx.body = utils.resSuccess()) - } - }, - relateQueryMN: async ( - relateModel, - relateQuery, - filterFnc, - model, - modelFields, - extraModelOptions = {}, - extraRelateOptions = {} - ) => { - let relates = await this.findByList(relateModel, { - query: relateQuery, - extraOptions: extraRelateOptions, - }) - let nextQuery = relates.map(filterFnc) - let query = { - where: { - [modelFields]: { $in: nextQuery }, - }, - } - const { where, attributes, other } = extraModelOptions - where && (query.where = Object.assign(query.where, where)) - attributes && (query.attributes = attributes) - let results = await this.findByList(model, { - query, - extraOptions: other, - }) - return { results, relates } - }, -} diff --git a/lib/utils/index.js b/lib/utils/index.js deleted file mode 100644 index cf5b182..0000000 --- a/lib/utils/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const common = require('./common') -const curdHelper = require('./curd_helper') -const validator = require('./validator') - -module.exports = { - validator, - curdHelper, - ...common, -} diff --git a/lib/utils/validator.js b/lib/utils/validator.js deleted file mode 100644 index 853391d..0000000 --- a/lib/utils/validator.js +++ /dev/null @@ -1,31 +0,0 @@ -const validatorjs = require('validatorjs') -validatorjs.useLang('zh') - -module.exports = { - validateJson: (data, rules) => { - const errMessage = [] - const result = { - message: '', - success: true, - } - const validateRule = {} - const customName = {} - for (let key in rules) { - const { rule, name } = rules[key] - validateRule[key] = rule - customName[key] = name - } - const validator = new validatorjs(data, validateRule) - validator.setAttributeNames(customName) - if (validator.fails()) { - for (let message in validator.errors.all()) { - errMessage.push(validator.errors.first(message)) - } - } - if (errMessage.length > 0) { - result.success = false - result.message = errMessage.join('') - } - return result - }, -} diff --git a/package-lock.json b/package-lock.json index f323209..d955f18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,3041 +1,2263 @@ { - "name": "json-controller", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.nlark.com/@babel/code-frame/download/@babel/code-frame-7.12.11.tgz", - "integrity": "sha1-9K1DWqJj25NbjxDyxVLSP7cWpj8=", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/generator": { - "version": "7.14.9", - "resolved": "https://registry.nlark.com/@babel/generator/download/@babel/generator-7.14.9.tgz?cache=0&sync_timestamp=1627804563759&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fgenerator%2Fdownload%2F%40babel%2Fgenerator-7.14.9.tgz", - "integrity": "sha1-I7GcWX04tPfcLj/kKmnIjZ7PqhY=", - "dev": true, - "requires": { - "@babel/types": "^7.14.9", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-function-name": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/helper-function-name/download/@babel/helper-function-name-7.14.5.tgz", - "integrity": "sha1-ieLEdJcvFdjiM7Uu6MSA4s/NUMQ=", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.14.5", - "@babel/template": "^7.14.5", - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.14.5.tgz", - "integrity": "sha1-Jfv6V5sJN+7h87gF7OTOOYxDGBU=", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/helper-hoist-variables/download/@babel/helper-hoist-variables-7.14.5.tgz", - "integrity": "sha1-4N0nwzp45XfXyIhJFqPn7x98f40=", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.14.5.tgz", - "integrity": "sha1-IrI6VO9RwrdgXYUZMMGXbdC8aTo=", - "dev": true, - "requires": { - "@babel/types": "^7.14.5" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.8", - "resolved": "https://registry.nlark.com/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.14.8.tgz?cache=0&sync_timestamp=1626804295454&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-validator-identifier%2Fdownload%2F%40babel%2Fhelper-validator-identifier-7.14.8.tgz", - "integrity": "sha1-Mr4zp1bynieKDWRPoIosng+Io0w=", - "dev": true - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/highlight/download/@babel/highlight-7.14.5.tgz", - "integrity": "sha1-aGGlLwOWZAUAH2qlNKAaJNmejNk=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.nlark.com/chalk/download/chalk-2.4.2.tgz?cache=0&sync_timestamp=1627646734234&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-2.4.2.tgz", - "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-1.0.5.tgz?cache=0&sync_timestamp=1618677243201&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescape-string-regexp%2Fdownload%2Fescape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } - } - }, - "@babel/parser": { - "version": "7.14.9", - "resolved": "https://registry.nlark.com/@babel/parser/download/@babel/parser-7.14.9.tgz", - "integrity": "sha1-WWwa1nYIBwBY6/jfUMHq9l24laQ=", - "dev": true - }, - "@babel/template": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/template/download/@babel/template-7.14.5.tgz", - "integrity": "sha1-qbydizM1T/blWpxg0RCSAKaJdPQ=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/code-frame/download/@babel/code-frame-7.14.5.tgz", - "integrity": "sha1-I7CNdA6D9JxeWZRfvxtD6Au/Tts=", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - } - } - }, - "@babel/traverse": { - "version": "7.14.9", - "resolved": "https://registry.nlark.com/@babel/traverse/download/@babel/traverse-7.14.9.tgz?cache=0&sync_timestamp=1627804502262&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftraverse%2Fdownload%2F%40babel%2Ftraverse-7.14.9.tgz", - "integrity": "sha1-AWEmszEhC/Bv/ynVKXHu+Dg+VW8=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.14.9", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.14.9", - "@babel/types": "^7.14.9", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.nlark.com/@babel/code-frame/download/@babel/code-frame-7.14.5.tgz", - "integrity": "sha1-I7CNdA6D9JxeWZRfvxtD6Au/Tts=", - "dev": true, - "requires": { - "@babel/highlight": "^7.14.5" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.nlark.com/globals/download/globals-11.12.0.tgz", - "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.14.9", - "resolved": "https://registry.nlark.com/@babel/types/download/@babel/types-7.14.9.tgz?cache=0&sync_timestamp=1627804573112&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Ftypes%2Fdownload%2F%40babel%2Ftypes-7.14.9.tgz", - "integrity": "sha1-8rGcPy93xXCNZ/6PYEbpzqK1A20=", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.nlark.com/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha1-ZlTRcbICT22O4VG/JQlpmRkTHUg=", - "dev": true - } - } - }, - "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.nlark.com/@eslint/eslintrc/download/@eslint/eslintrc-0.4.3.tgz", - "integrity": "sha1-nkKYHvA1vrPdSa3ResuW6P9vOUw=", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - } - }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.nlark.com/@humanwhocodes/config-array/download/@humanwhocodes/config-array-0.5.0.tgz", - "integrity": "sha1-FAeWfUxu7Nc4j4Os8er00Mbljvk=", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.nlark.com/@humanwhocodes/object-schema/download/@humanwhocodes/object-schema-1.2.0.tgz", - "integrity": "sha1-h956+cIxgm/daKxyWPd8Qp4OX88=", - "dev": true - }, - "@types/node": { - "version": "16.4.7", - "resolved": "https://registry.nlark.com/@types/node/download/@types/node-16.4.7.tgz?cache=0&sync_timestamp=1627563812463&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-16.4.7.tgz", - "integrity": "sha1-96+nh2nUtHf1CS18NGji6GU9d5w=" - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.nlark.com/@types/parse-json/download/@types/parse-json-4.0.0.tgz", - "integrity": "sha1-L4u0QUNNFjs1+4/9zNcTiSf/uMA=", - "dev": true - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/@ungap/promise-all-settled/download/@ungap/promise-all-settled-1.1.2.tgz", - "integrity": "sha1-qlgEJxHW4ydd033Fl+XTHowpCkQ=", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", - "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.nlark.com/acorn/download/acorn-7.4.1.tgz", - "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.nlark.com/acorn-jsx/download/acorn-jsx-5.3.2.tgz", - "integrity": "sha1-ftW7VZCLOy8bxVxq8WU7rafweTc=", - "dev": true - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/aggregate-error/download/aggregate-error-3.1.0.tgz?cache=0&sync_timestamp=1618681361248&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Faggregate-error%2Fdownload%2Faggregate-error-3.1.0.tgz", - "integrity": "sha1-kmcP9Q9TWb23o+DUDQ7DDFc3aHo=", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.nlark.com/ajv/download/ajv-6.12.6.tgz", - "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-4.1.1.tgz", - "integrity": "sha1-y7muJWv3UK8eqzRPIpqif+lLo0g=", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.nlark.com/ansi-escapes/download/ansi-escapes-4.3.2.tgz?cache=0&sync_timestamp=1618847144938&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fansi-escapes%2Fdownload%2Fansi-escapes-4.3.2.tgz", - "integrity": "sha1-ayKR0dt9mLZSHV8e+kLQ86n+tl4=", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.nlark.com/type-fest/download/type-fest-0.21.3.tgz?cache=0&sync_timestamp=1627560338147&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.21.3.tgz", - "integrity": "sha1-0mCiSwGYQ24TP6JqUkptZfo7Ljc=", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-5.0.0.tgz", - "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.2.tgz?cache=0&sync_timestamp=1617747502795&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fanymatch%2Fdownload%2Fanymatch-3.1.2.tgz", - "integrity": "sha1-wFV8CWrzLxBhmPT04qODU343hxY=", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/astral-regex/download/astral-regex-2.0.0.tgz", - "integrity": "sha1-SDFDxWeu7UeFdZwIZXhtx319LjE=", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.nlark.com/babel-eslint/download/babel-eslint-10.1.0.tgz", - "integrity": "sha1-aWjlaKkQt4+zd5zdi2rC9HmUMjI=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.nlark.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=", - "dev": true - } - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz", - "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.nlark.com/binary-extensions/download/binary-extensions-2.2.0.tgz", - "integrity": "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.nlark.com/brace-expansion/download/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", - "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.nlark.com/browser-stdout/download/browser-stdout-1.3.1.tgz", - "integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA=", - "dev": true - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz", - "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", - "dev": true - }, - "cache-content-type": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/cache-content-type/download/cache-content-type-1.0.1.tgz", - "integrity": "sha1-A1zeKwjuISn0qDFeqPAKANuhRTw=", - "dev": true, - "requires": { - "mime-types": "^2.1.18", - "ylru": "^1.2.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/call-bind/download/call-bind-1.0.2.tgz?cache=0&sync_timestamp=1610402896029&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcall-bind%2Fdownload%2Fcall-bind-1.0.2.tgz", - "integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/callsites/download/callsites-3.1.0.tgz", - "integrity": "sha1-s2MKvYlDQy9Us/BRkjjjPNffL3M=", - "dev": true - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-6.2.0.tgz?cache=0&sync_timestamp=1603921882890&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-6.2.0.tgz", - "integrity": "sha1-kkr4gcnVJaydh/QNlk5c6pgqGAk=", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.nlark.com/chalk/download/chalk-4.1.2.tgz?cache=0&sync_timestamp=1627646734234&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.2.tgz", - "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", - "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1626715907927&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1626703400240&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz", - "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.nlark.com/chokidar/download/chokidar-3.5.2.tgz", - "integrity": "sha1-26OXb8rbAW9m/TZQIdkWANAcHnU=", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.nlark.com/clean-stack/download/clean-stack-2.2.0.tgz?cache=0&sync_timestamp=1621915070206&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fclean-stack%2Fdownload%2Fclean-stack-2.2.0.tgz", - "integrity": "sha1-7oRy27Ep5yezHooQpCfe6d/kAIs=", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/cli-cursor/download/cli-cursor-3.1.0.tgz", - "integrity": "sha1-JkMFp65JDR0Dvwybp8kl0XU68wc=", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/cli-truncate/download/cli-truncate-2.1.0.tgz", - "integrity": "sha1-w54ovwXtzeW+O5iZKiLe7Vork8c=", - "dev": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", - "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/slice-ansi/download/slice-ansi-3.0.0.tgz?cache=0&sync_timestamp=1618555008681&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslice-ansi%2Fdownload%2Fslice-ansi-3.0.0.tgz", - "integrity": "sha1-Md3BCTCht+C2ewjJbC9Jt3p4l4c=", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - } - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-7.0.4.tgz?cache=0&sync_timestamp=1604880017635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-7.0.4.tgz", - "integrity": "sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08=", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "co-body": { - "version": "6.1.0", - "resolved": "https://registry.nlark.com/co-body/download/co-body-6.1.0.tgz", - "integrity": "sha1-2HqO/DVk+b/jrO2O9c0Ex6h2ZUc=", - "dev": true, - "requires": { - "inflation": "^2.0.0", - "qs": "^6.5.2", - "raw-body": "^2.3.3", - "type-is": "^1.6.16" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-1.9.3.tgz", - "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npm.taobao.org/colorette/download/colorette-1.2.2.tgz?cache=0&sync_timestamp=1614259647923&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolorette%2Fdownload%2Fcolorette-1.2.2.tgz", - "integrity": "sha1-y8x51emcrqLb8Q6zom/Ys+as+pQ=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz", - "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "7.2.0", - "resolved": "https://registry.nlark.com/commander/download/commander-7.2.0.tgz?cache=0&sync_timestamp=1627359190297&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcommander%2Fdownload%2Fcommander-7.2.0.tgz", - "integrity": "sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc=", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz", - "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz", - "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", - "dev": true - }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/cookiejar/download/cookiejar-2.1.2.tgz", - "integrity": "sha1-3YojVTB1L5iPmghE8/xYnjERElw=", - "dev": true - }, - "cookies": { - "version": "0.8.0", - "resolved": "https://registry.npm.taobao.org/cookies/download/cookies-0.8.0.tgz", - "integrity": "sha1-EpPOSzkXQKhAbjyYcOgoxLVPP5A=", - "dev": true, - "requires": { - "depd": "~2.0.0", - "keygrip": "~1.1.0" - } - }, - "copy-to": { - "version": "2.0.1", - "resolved": "https://registry.nlark.com/copy-to/download/copy-to-2.0.1.tgz", - "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=", - "dev": true - }, - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/cosmiconfig/download/cosmiconfig-7.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcosmiconfig%2Fdownload%2Fcosmiconfig-7.0.0.tgz", - "integrity": "sha1-75tE13OVnK5j3ezRIt4jhTtg+NM=", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npm.taobao.org/cross-spawn/download/cross-spawn-7.0.3.tgz", - "integrity": "sha1-9zqFudXUHQRVUcF34ogtSshXKKY=", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.nlark.com/debug/download/debug-4.3.2.tgz", - "integrity": "sha1-8KScGKyHeeMdSgxgKd+3aHPHQos=", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/decamelize/download/decamelize-4.0.0.tgz?cache=0&sync_timestamp=1610348670939&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecamelize%2Fdownload%2Fdecamelize-4.0.0.tgz", - "integrity": "sha1-qkcte/Zg6xXzSU79UxyrfypwmDc=", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npm.taobao.org/dedent/download/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.nlark.com/deep-equal/download/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npm.taobao.org/deep-is/download/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "denque": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/denque/download/denque-1.5.0.tgz", - "integrity": "sha1-dz3gaG/y2Owv+SkUMWpHtzscc94=" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/depd/download/depd-2.0.0.tgz", - "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", - "dev": true - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.nlark.com/diff/download/diff-5.0.0.tgz?cache=0&sync_timestamp=1622685824253&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdiff%2Fdownload%2Fdiff-5.0.0.tgz", - "integrity": "sha1-ftatdthZ0DB4fsNYVfWx2vMdhSs=", - "dev": true - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/doctrine/download/doctrine-3.0.0.tgz", - "integrity": "sha1-rd6+rXKmV023g2OdyHoSF3OXOWE=", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dottie": { - "version": "2.0.2", - "resolved": "https://registry.nlark.com/dottie/download/dottie-2.0.2.tgz", - "integrity": "sha1-zJHAcmzjoFTr8RxV+8kqfyZt0VQ=" - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1614682725186&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz", - "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npm.taobao.org/enquirer/download/enquirer-2.3.6.tgz?cache=0&sync_timestamp=1593693195602&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquirer%2Fdownload%2Fenquirer-2.3.6.tgz", - "integrity": "sha1-Kn/l3WNKHkElqXXsmU/1RW3Dc00=", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npm.taobao.org/error-ex/download/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/escalade/download/escalade-3.1.1.tgz?cache=0&sync_timestamp=1602567261690&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescalade%2Fdownload%2Fescalade-3.1.1.tgz", - "integrity": "sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA=", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-4.0.0.tgz?cache=0&sync_timestamp=1618677243201&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescape-string-regexp%2Fdownload%2Fescape-string-regexp-4.0.0.tgz", - "integrity": "sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ=", - "dev": true - }, - "eslint": { - "version": "7.32.0", - "resolved": "https://registry.nlark.com/eslint/download/eslint-7.32.0.tgz?cache=0&sync_timestamp=1627685851013&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint%2Fdownload%2Feslint-7.32.0.tgz", - "integrity": "sha1-xtMooUvj+wjI0dIeEsAv23oqgS0=", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - } - }, - "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.nlark.com/eslint-config-prettier/download/eslint-config-prettier-8.3.0.tgz?cache=0&sync_timestamp=1619270465166&other_urls=https%3A%2F%2Fregistry.nlark.com%2Feslint-config-prettier%2Fdownload%2Feslint-config-prettier-8.3.0.tgz", - "integrity": "sha1-90cbILb+ipqSVMxoRFQgKIai3Xo=", - "dev": true - }, - "eslint-plugin-prettier": { - "version": "3.4.0", - "resolved": "https://registry.npm.taobao.org/eslint-plugin-prettier/download/eslint-plugin-prettier-3.4.0.tgz", - "integrity": "sha1-zbrTvx29Kxd+mCVzf+Y7R2oI8Mc=", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.nlark.com/eslint-scope/download/eslint-scope-5.1.1.tgz", - "integrity": "sha1-54blmmbLkrP2wfsNUIqrF0hI9Iw=", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.nlark.com/eslint-utils/download/eslint-utils-2.1.0.tgz", - "integrity": "sha1-0t5eA0JOcH3BDHQGjd7a5wh0Gyc=", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.nlark.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.nlark.com/eslint-visitor-keys/download/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha1-9lMoJZMFknOSyTjtROsKXJsr0wM=", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.nlark.com/espree/download/espree-7.3.1.tgz", - "integrity": "sha1-8t8zC3Usb1UBn4vYm3ZgA5wbu7Y=", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.nlark.com/eslint-visitor-keys/download/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz", - "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/esquery/download/esquery-1.4.0.tgz", - "integrity": "sha1-IUj/w4uC6McFff7UhCWz5h8PJKU=", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-5.2.0.tgz?cache=0&sync_timestamp=1596642941915&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-5.2.0.tgz", - "integrity": "sha1-MH30JUfmzHMk088DwVXVzbjFOIA=", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/esrecurse/download/esrecurse-4.3.0.tgz", - "integrity": "sha1-eteWTWeauyi+5yzsY3WLHF0smSE=", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-5.2.0.tgz?cache=0&sync_timestamp=1596642941915&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-5.2.0.tgz", - "integrity": "sha1-MH30JUfmzHMk088DwVXVzbjFOIA=", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/estraverse/download/estraverse-4.3.0.tgz?cache=0&sync_timestamp=1596642941915&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Festraverse%2Fdownload%2Festraverse-4.3.0.tgz", - "integrity": "sha1-OYrT88WiSUi+dyXoPRGn3ijNvR0=", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/esutils/download/esutils-2.0.3.tgz", - "integrity": "sha1-dNLrTeC42hKTcRkQ1Qd1ubcQ72Q=", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.nlark.com/execa/download/execa-5.1.1.tgz?cache=0&sync_timestamp=1622825446570&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fexeca%2Fdownload%2Fexeca-5.1.1.tgz", - "integrity": "sha1-+ArZy/Qpj3vR1MlVXCHpN0HEEd0=", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz?cache=0&sync_timestamp=1591599675178&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-deep-equal%2Fdownload%2Ffast-deep-equal-3.1.3.tgz", - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/fast-diff/download/fast-diff-1.2.0.tgz", - "integrity": "sha1-c+4RmC2Gyq95WYKNUZz+kn+sXwM=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha1-h0v2nG9ATCtdmcSBNBOZ/VWJJjM=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npm.taobao.org/fast-levenshtein/download/fast-levenshtein-2.0.6.tgz?cache=0&sync_timestamp=1595428000133&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-levenshtein%2Fdownload%2Ffast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fast-safe-stringify": { - "version": "2.0.8", - "resolved": "https://registry.nlark.com/fast-safe-stringify/download/fast-safe-stringify-2.0.8.tgz?cache=0&sync_timestamp=1625835811932&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffast-safe-stringify%2Fdownload%2Ffast-safe-stringify-2.0.8.tgz", - "integrity": "sha1-3Cr0jEbPcStoPoSbK71EazLek28=", - "dev": true - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.nlark.com/file-entry-cache/download/file-entry-cache-6.0.1.tgz", - "integrity": "sha1-IRst2WWcsDlLBz5zI6w8kz1SICc=", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", - "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-5.0.0.tgz?cache=0&sync_timestamp=1597170071453&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-5.0.0.tgz", - "integrity": "sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw=", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.nlark.com/flat/download/flat-5.0.2.tgz", - "integrity": "sha1-jKb+MyBp/6nTJMMnGYxZglnOskE=", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npm.taobao.org/flat-cache/download/flat-cache-3.0.4.tgz", - "integrity": "sha1-YbAzgwKy/p+Vfcwy/CqH8cMEixE=", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.2", - "resolved": "https://registry.nlark.com/flatted/download/flatted-3.2.2.tgz", - "integrity": "sha1-ZL/tXLaP48p4s+shStl7Y77c5WE=", - "dev": true - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.nlark.com/form-data/download/form-data-3.0.1.tgz", - "integrity": "sha1-69U3kbeDVqma+aMA1CgsTV65dV8=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.2", - "resolved": "https://registry.npm.taobao.org/formidable/download/formidable-1.2.2.tgz", - "integrity": "sha1-v2muopcpgmdfAIZTQrmCmG9rjdk=", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz", - "integrity": "sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro=", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/functional-red-black-tree/download/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npm.taobao.org/generate-function/download/generate-function-2.3.1.tgz", - "integrity": "sha1-8GlhdpDBDIaOc7hGV0Z2T5fDR58=", - "requires": { - "is-property": "^1.0.2" - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz", - "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz", - "integrity": "sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y=", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/get-own-enumerable-property-symbols/download/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha1-tf3nfyLL4185C04ImSLFC85u9mQ=", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.nlark.com/get-stream/download/get-stream-6.0.1.tgz", - "integrity": "sha1-omLY7vZ6ztV8KFKtYWdSakPL97c=", - "dev": true - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.nlark.com/glob/download/glob-7.1.7.tgz?cache=0&sync_timestamp=1620337382269&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob%2Fdownload%2Fglob-7.1.7.tgz", - "integrity": "sha1-Oxk+kjPwHULQs/eClLvutBj5SpA=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-5.1.2.tgz?cache=0&sync_timestamp=1626760235241&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-5.1.2.tgz", - "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "13.10.0", - "resolved": "https://registry.nlark.com/globals/download/globals-13.10.0.tgz", - "integrity": "sha1-YLpWw6wsqEXPv0+uynJ62d0gRnY=", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.nlark.com/growl/download/growl-1.10.5.tgz", - "integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4=", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.nlark.com/has-flag/download/has-flag-3.0.0.tgz?cache=0&sync_timestamp=1626715907927&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.2.tgz?cache=0&sync_timestamp=1614443577352&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-symbols%2Fdownload%2Fhas-symbols-1.0.2.tgz", - "integrity": "sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM=", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/he/download/he-1.2.0.tgz", - "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=", - "dev": true - }, - "http-assert": { - "version": "1.4.1", - "resolved": "https://registry.npm.taobao.org/http-assert/download/http-assert-1.4.1.tgz", - "integrity": "sha1-xfcl1neqfoc+9zYZm4lobM6zeHg=", - "dev": true, - "requires": { - "deep-equal": "~1.0.1", - "http-errors": "~1.7.2" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.3.tgz?cache=0&sync_timestamp=1593407611415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.3.tgz", - "integrity": "sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - } - } - }, - "http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.8.0.tgz?cache=0&sync_timestamp=1593407611415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.8.0.tgz", - "integrity": "sha1-ddG75JfhBE9R5O6ecEpi8o0zZQc=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.2.0.tgz", - "integrity": "sha1-ZsmiSnP5/CjL5msJ/tPTPcrxtCQ=", - "dev": true - } - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.nlark.com/human-signals/download/human-signals-2.1.0.tgz", - "integrity": "sha1-3JH8ukLk0G5Kuu0zs+ejwC9RTqA=", - "dev": true - }, - "husky": { - "version": "7.0.1", - "resolved": "https://registry.nlark.com/husky/download/husky-7.0.1.tgz?cache=0&sync_timestamp=1625567309348&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhusky%2Fdownload%2Fhusky-7.0.1.tgz", - "integrity": "sha1-V59BgLXaRSAmPocTzIMpQrSOHxw=", - "dev": true - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.6.3.tgz", - "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz?cache=0&sync_timestamp=1590809380232&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fignore%2Fdownload%2Fignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npm.taobao.org/import-fresh/download/import-fresh-3.3.0.tgz?cache=0&sync_timestamp=1608469532269&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimport-fresh%2Fdownload%2Fimport-fresh-3.3.0.tgz", - "integrity": "sha1-NxYsJfy566oublPVtNiM4X2eDCs=", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npm.taobao.org/imurmurhash/download/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/indent-string/download/indent-string-4.0.0.tgz?cache=0&sync_timestamp=1618679578258&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Findent-string%2Fdownload%2Findent-string-4.0.0.tgz", - "integrity": "sha1-Yk+PRJfWGbLZdoUx1Y9BIoVNclE=", - "dev": true - }, - "inflation": { - "version": "2.0.0", - "resolved": "https://registry.nlark.com/inflation/download/inflation-2.0.0.tgz", - "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=", - "dev": true - }, - "inflection": { - "version": "1.13.1", - "resolved": "https://registry.nlark.com/inflection/download/inflection-1.13.1.tgz", - "integrity": "sha1-xcrdgIiKkM+EwuluNA1+3IXV8Ms=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", - "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npm.taobao.org/is-arrayish/download/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz", - "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.nlark.com/is-core-module/download/is-core-module-2.5.0.tgz", - "integrity": "sha1-91SENhfHC/0pt72HMnQAzaXBhJE=", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz?cache=0&sync_timestamp=1618552469710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", - "dev": true - }, - "is-generator-function": { - "version": "1.0.9", - "resolved": "https://registry.nlark.com/is-generator-function/download/is-generator-function-1.0.9.tgz", - "integrity": "sha1-5fgsIyNnPn/K09EoWMg8QDn2OZw=", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz", - "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz", - "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", - "dev": true - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/is-obj/download/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.nlark.com/is-plain-obj/download/is-plain-obj-2.1.0.tgz", - "integrity": "sha1-ReQuN/zPH0Dajl927iFRWEDAkoc=", - "dev": true - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/is-property/download/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/is-regexp/download/is-regexp-1.0.0.tgz?cache=0&sync_timestamp=1617816642607&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-regexp%2Fdownload%2Fis-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.nlark.com/is-stream/download/is-stream-2.0.1.tgz?cache=0&sync_timestamp=1627296766028&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fis-stream%2Fdownload%2Fis-stream-2.0.1.tgz", - "integrity": "sha1-+sHj1TuXrVqdCunO8jifWBClwHc=", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.nlark.com/is-unicode-supported/download/is-unicode-supported-0.1.0.tgz", - "integrity": "sha1-PybHaoCVk7Ur+i7LVxDtJ3m1Iqc=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz", - "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npm.taobao.org/js-yaml/download/js-yaml-3.14.1.tgz?cache=0&sync_timestamp=1618434911653&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-yaml%2Fdownload%2Fjs-yaml-3.14.1.tgz", - "integrity": "sha1-2ugS/bOCX6MGYJqHFzg8UMNqBTc=", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npm.taobao.org/jsesc/download/jsesc-2.5.2.tgz?cache=0&sync_timestamp=1603892968504&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjsesc%2Fdownload%2Fjsesc-2.5.2.tgz", - "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npm.taobao.org/json-parse-even-better-errors/download/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha1-fEeAWpQxmSjgV3dAXcEuH3pO4C0=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/json-stable-stringify-without-jsonify/download/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "keygrip": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/keygrip/download/keygrip-1.1.0.tgz", - "integrity": "sha1-hxsWgdXhWcYqRFsMdLYV4JF+ciY=", - "dev": true, - "requires": { - "tsscmp": "1.0.6" - } - }, - "koa": { - "version": "2.13.1", - "resolved": "https://registry.npm.taobao.org/koa/download/koa-2.13.1.tgz", - "integrity": "sha1-YnUXKHWye8/h1FQ1altrn1qbEFE=", - "dev": true, - "requires": { - "accepts": "^1.3.5", - "cache-content-type": "^1.0.0", - "content-disposition": "~0.5.2", - "content-type": "^1.0.4", - "cookies": "~0.8.0", - "debug": "~3.1.0", - "delegates": "^1.0.0", - "depd": "^2.0.0", - "destroy": "^1.0.4", - "encodeurl": "^1.0.2", - "escape-html": "^1.0.3", - "fresh": "~0.5.2", - "http-assert": "^1.3.0", - "http-errors": "^1.6.3", - "is-generator-function": "^1.0.7", - "koa-compose": "^4.1.0", - "koa-convert": "^1.2.0", - "on-finished": "^2.3.0", - "only": "~0.0.2", - "parseurl": "^1.3.2", - "statuses": "^1.5.0", - "type-is": "^1.6.16", - "vary": "^1.1.2" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.nlark.com/debug/download/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "koa-bodyparser": { - "version": "4.3.0", - "resolved": "https://registry.npm.taobao.org/koa-bodyparser/download/koa-bodyparser-4.3.0.tgz", - "integrity": "sha1-J0x3hVX/SPoiHufzap+9us4idZo=", - "dev": true, - "requires": { - "co-body": "^6.0.0", - "copy-to": "^2.0.1" - } - }, - "koa-compose": { - "version": "4.1.0", - "resolved": "https://registry.nlark.com/koa-compose/download/koa-compose-4.1.0.tgz", - "integrity": "sha1-UHMGuTcZAdtBEhyBLpI9DWfT6Hc=", - "dev": true - }, - "koa-convert": { - "version": "1.2.0", - "resolved": "https://registry.npm.taobao.org/koa-convert/download/koa-convert-1.2.0.tgz", - "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", - "dev": true, - "requires": { - "co": "^4.6.0", - "koa-compose": "^3.0.0" - }, - "dependencies": { - "koa-compose": { - "version": "3.2.1", - "resolved": "https://registry.nlark.com/koa-compose/download/koa-compose-3.2.1.tgz", - "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", - "dev": true, - "requires": { - "any-promise": "^1.1.0" - } - } - } - }, - "koa-router": { - "version": "10.0.0", - "resolved": "https://registry.npm.taobao.org/koa-router/download/koa-router-10.0.0.tgz", - "integrity": "sha1-e8dqAxCFcx5h/JLBaDaHsvRN5qQ=", - "dev": true, - "requires": { - "debug": "^4.1.1", - "http-errors": "^1.7.3", - "koa-compose": "^4.1.0", - "methods": "^1.1.2", - "path-to-regexp": "^6.1.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npm.taobao.org/levn/download/levn-0.4.1.tgz", - "integrity": "sha1-rkViwAdHO5MqYgDUAyaN0v/8at4=", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npm.taobao.org/lines-and-columns/download/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "lint-staged": { - "version": "11.1.1", - "resolved": "https://registry.nlark.com/lint-staged/download/lint-staged-11.1.1.tgz?cache=0&sync_timestamp=1627124878378&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flint-staged%2Fdownload%2Flint-staged-11.1.1.tgz", - "integrity": "sha1-nCAYuHJlTPgLKx/1oQtrdK724wA=", - "dev": true, - "requires": { - "chalk": "^4.1.1", - "cli-truncate": "^2.1.0", - "commander": "^7.2.0", - "cosmiconfig": "^7.0.0", - "debug": "^4.3.1", - "dedent": "^0.7.0", - "enquirer": "^2.3.6", - "execa": "^5.0.0", - "listr2": "^3.8.2", - "log-symbols": "^4.1.0", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "please-upgrade-node": "^3.2.0", - "string-argv": "0.3.1", - "stringify-object": "^3.3.0" - } - }, - "listr2": { - "version": "3.11.0", - "resolved": "https://registry.nlark.com/listr2/download/listr2-3.11.0.tgz?cache=0&sync_timestamp=1626978156161&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flistr2%2Fdownload%2Flistr2-3.11.0.tgz", - "integrity": "sha1-l3GwJAeHWqeOc9bg/2VBu+wKruk=", - "dev": true, - "requires": { - "cli-truncate": "^2.1.0", - "colorette": "^1.2.2", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rxjs": "^6.6.7", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-6.0.0.tgz?cache=0&sync_timestamp=1597081904643&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flocate-path%2Fdownload%2Flocate-path-6.0.0.tgz", - "integrity": "sha1-VTIeswn+u8WcSAHZMackUqaB0oY=", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.nlark.com/lodash/download/lodash-4.17.21.tgz", - "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npm.taobao.org/lodash.clonedeep/download/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npm.taobao.org/lodash.merge/download/lodash.merge-4.6.2.tgz", - "integrity": "sha1-VYqlO0O2YeGSWgr9+japoQhf5Xo=", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npm.taobao.org/lodash.truncate/download/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/log-symbols/download/log-symbols-4.1.0.tgz", - "integrity": "sha1-P727lbRoOsn8eFER55LlWNSr1QM=", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "log-update": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/log-update/download/log-update-4.0.0.tgz", - "integrity": "sha1-WJ7NNSRx8qHAxXAodUOmTf0g4KE=", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", - "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz", - "integrity": "sha1-6Tk7oHEC5skaOyIUePAlfNKFblM=", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz", - "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594427519396&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz", - "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", - "requires": { - "yallist": "^4.0.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/merge-stream/download/merge-stream-2.0.0.tgz", - "integrity": "sha1-UoI2KaFN0AyXcPtq1H3GMQ8sH2A=", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.nlark.com/micromatch/download/micromatch-4.0.4.tgz", - "integrity": "sha1-iW1Rnf6dsl/OlM63pQCRm/iB6/k=", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npm.taobao.org/mime/download/mime-2.5.2.tgz", - "integrity": "sha1-bj3GzCuVEGQ4MOXxnVy3U9pe6r4=", - "dev": true - }, - "mime-db": { - "version": "1.49.0", - "resolved": "https://registry.nlark.com/mime-db/download/mime-db-1.49.0.tgz?cache=0&sync_timestamp=1627335450684&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmime-db%2Fdownload%2Fmime-db-1.49.0.tgz", - "integrity": "sha1-89/eYMmenPO8lwHWh3ePU3ABy+0=", - "dev": true - }, - "mime-types": { - "version": "2.1.32", - "resolved": "https://registry.nlark.com/mime-types/download/mime-types-2.1.32.tgz", - "integrity": "sha1-HQDonn3n/gIAjbYQAdngKFJnD9U=", - "dev": true, - "requires": { - "mime-db": "1.49.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.nlark.com/mimic-fn/download/mimic-fn-2.1.0.tgz", - "integrity": "sha1-ftLCzMyvhNP/y3pptXcR/CCDQBs=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "mocha": { - "version": "9.0.3", - "resolved": "https://registry.nlark.com/mocha/download/mocha-9.0.3.tgz?cache=0&sync_timestamp=1627230567467&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmocha%2Fdownload%2Fmocha-9.0.3.tgz", - "integrity": "sha1-EozWu9PuCtza73FfNX927B5iJ8c=", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.23", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/argparse/download/argparse-2.0.1.tgz", - "integrity": "sha1-JG9Q88p4oyQPbJl+ipvR6sSeSzg=", - "dev": true - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.nlark.com/debug/download/debug-4.3.1.tgz", - "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz", - "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", - "dev": true - } - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1626715907927&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npm.taobao.org/js-yaml/download/js-yaml-4.1.0.tgz?cache=0&sync_timestamp=1618434911653&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-yaml%2Fdownload%2Fjs-yaml-4.1.0.tgz", - "integrity": "sha1-wftl+PUBeQHN0slRhkuhhFihBgI=", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.3.tgz", - "integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.nlark.com/supports-color/download/supports-color-8.1.1.tgz?cache=0&sync_timestamp=1626703400240&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-8.1.1.tgz", - "integrity": "sha1-zW/BfihQDP9WwbhsCn/UpUpzAFw=", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "moment": { - "version": "2.29.1", - "resolved": "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz?cache=0&sync_timestamp=1601983423917&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmoment%2Fdownload%2Fmoment-2.29.1.tgz", - "integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M=" - }, - "moment-timezone": { - "version": "0.5.33", - "resolved": "https://registry.nlark.com/moment-timezone/download/moment-timezone-0.5.33.tgz", - "integrity": "sha1-slL9a7V/NBybWaWrYajlGnO70iw=", - "requires": { - "moment": ">= 2.9.0" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz", - "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" - }, - "mysql2": { - "version": "2.2.5", - "resolved": "https://registry.npm.taobao.org/mysql2/download/mysql2-2.2.5.tgz", - "integrity": "sha1-cmJP+0gW+A+Wucl/7djACTX580A=", - "requires": { - "denque": "^1.4.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.2", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - } - }, - "named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/named-placeholders/download/named-placeholders-1.1.2.tgz", - "integrity": "sha1-zrH7/1C2szSStc8hTM9eOc7z0Og=", - "requires": { - "lru-cache": "^4.1.3" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427519396&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", - "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.nlark.com/nanoid/download/nanoid-3.1.23.tgz", - "integrity": "sha1-90QIbOfCvEfuCoRyV01ceOQYOoE=", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz", - "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", - "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npm.taobao.org/npm-run-path/download/npm-run-path-4.0.1.tgz", - "integrity": "sha1-t+zR5e1T2o43pV4cImnguX7XSOo=", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.nlark.com/object-inspect/download/object-inspect-1.11.0.tgz", - "integrity": "sha1-nc6xRs7dQUig2eUauI00z1CZIrE=", - "dev": true - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/onetime/download/onetime-5.1.2.tgz", - "integrity": "sha1-0Oluu1awdHbfHdnEgG5SN5hcpF4=", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "only": { - "version": "0.0.2", - "resolved": "https://registry.npm.taobao.org/only/download/only-0.0.2.tgz", - "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=", - "dev": true - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npm.taobao.org/optionator/download/optionator-0.9.1.tgz", - "integrity": "sha1-TyNqY3Pa4FZqbUPhMmZ09QwpFJk=", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/p-limit/download/p-limit-3.1.0.tgz?cache=0&sync_timestamp=1606288333421&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-limit%2Fdownload%2Fp-limit-3.1.0.tgz", - "integrity": "sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs=", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-5.0.0.tgz?cache=0&sync_timestamp=1597081785924&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-locate%2Fdownload%2Fp-locate-5.0.0.tgz", - "integrity": "sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ=", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.nlark.com/p-map/download/p-map-4.0.0.tgz?cache=0&sync_timestamp=1627082385032&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fp-map%2Fdownload%2Fp-map-4.0.0.tgz", - "integrity": "sha1-uy+Vpe2i7BaOySdOBqdHw+KQTSs=", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/parent-module/download/parent-module-1.0.1.tgz", - "integrity": "sha1-aR0nCeeMefrjoVZiJFLQB2LKqqI=", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npm.taobao.org/parse-json/download/parse-json-5.2.0.tgz", - "integrity": "sha1-x2/Gbe5UIxyWKyK8yKcs8vmXU80=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz", - "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/path-key/download/path-key-3.1.1.tgz?cache=0&sync_timestamp=1617971632960&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-key%2Fdownload%2Fpath-key-3.1.1.tgz", - "integrity": "sha1-WB9q3mWMu6ZaDTOA3ndTKVBU83U=", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.nlark.com/path-parse/download/path-parse-1.0.7.tgz", - "integrity": "sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU=", - "dev": true - }, - "path-to-regexp": { - "version": "6.2.0", - "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-6.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-to-regexp%2Fdownload%2Fpath-to-regexp-6.2.0.tgz", - "integrity": "sha1-97OAMzYQTDRoia3s5hRmkjBkXzg=", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/path-type/download/path-type-4.0.0.tgz", - "integrity": "sha1-hO0BwKe6OAr+CdkKjBgNzZ0DBDs=", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz", - "integrity": "sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI=", - "dev": true - }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npm.taobao.org/please-upgrade-node/download/please-upgrade-node-3.2.0.tgz", - "integrity": "sha1-rt3T+ZTJM+StmLmdmlVu+g4v6UI=", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.2.1.tgz", - "integrity": "sha1-3rxkidem5rDnYRiIzsiAM30xY5Y=", - "dev": true - }, - "prettier": { - "version": "2.3.2", - "resolved": "https://registry.nlark.com/prettier/download/prettier-2.3.2.tgz?cache=0&sync_timestamp=1624696259185&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fprettier%2Fdownload%2Fprettier-2.3.2.tgz", - "integrity": "sha1-7ygKBewlNxLkhiM9tcbyNEHnNC0=", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/prettier-linter-helpers/download/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha1-0j1B/hN1ZG3i0BBNNFSjAIgCz3s=", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npm.taobao.org/progress/download/progress-2.0.3.tgz", - "integrity": "sha1-foz42PW48jnBvGi+tOt4Vn1XLvg=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/punycode/download/punycode-2.1.1.tgz", - "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=", - "dev": true - }, - "qs": { - "version": "6.10.1", - "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.10.1.tgz", - "integrity": "sha1-STFIL6jWR6Wqt5nFJx0hM7mB+2o=", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz", - "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "raw-body": { - "version": "2.4.1", - "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.1.tgz", - "integrity": "sha1-MKyC+Yu1rowVLmcUnayNVRU7Fow=", - "dev": true, - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.3", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.3.tgz?cache=0&sync_timestamp=1593407611415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.3.tgz", - "integrity": "sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.4.24.tgz", - "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", - "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-3.6.0.tgz?cache=0&sync_timestamp=1615717369278&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freaddirp%2Fdownload%2Freaddirp-3.6.0.tgz", - "integrity": "sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc=", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.nlark.com/regexpp/download/regexpp-3.2.0.tgz", - "integrity": "sha1-BCWido2PI7rXDKS5BGH6LxIT4bI=", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/require-from-string/download/require-from-string-2.0.2.tgz", - "integrity": "sha1-iaf92TgmEmcxjq/hT5wy5ZjDaQk=", - "dev": true - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npm.taobao.org/resolve/download/resolve-1.20.0.tgz", - "integrity": "sha1-YpoBP7P3B1XW8LeTXMHCxTeLGXU=", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npm.taobao.org/restore-cursor/download/restore-cursor-3.1.0.tgz", - "integrity": "sha1-OfZ8VLOnpYzqUjbZXPADQjljH34=", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "retry-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.nlark.com/retry-as-promised/download/retry-as-promised-3.2.0.tgz", - "integrity": "sha1-dp9j1Ta+xHg1SdsHd8tW2t2dhUM=", - "requires": { - "any-promise": "^1.3.0" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-3.0.2.tgz", - "integrity": "sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho=", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.nlark.com/rxjs/download/rxjs-6.6.7.tgz", - "integrity": "sha1-kKwBisq/SRv2UEQjXVhjxNq4BMk=", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1616463608061&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz", - "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/semver-compare/download/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npm.taobao.org/seq-queue/download/seq-queue-0.0.5.tgz", - "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" - }, - "sequelize": { - "version": "6.6.5", - "resolved": "https://registry.nlark.com/sequelize/download/sequelize-6.6.5.tgz", - "integrity": "sha1-b2GOmfPfH8gfKHCeijE5zsPvHww=", - "requires": { - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.13.1", - "lodash": "^4.17.20", - "moment": "^2.26.0", - "moment-timezone": "^0.5.31", - "retry-as-promised": "^3.2.0", - "semver": "^7.3.2", - "sequelize-pool": "^6.0.0", - "toposort-class": "^1.0.1", - "uuid": "^8.1.0", - "validator": "^13.6.0", - "wkx": "^0.5.0" - } - }, - "sequelize-pool": { - "version": "6.1.0", - "resolved": "https://registry.nlark.com/sequelize-pool/download/sequelize-pool-6.1.0.tgz", - "integrity": "sha1-yqoMHjJNPCw6OZ/tLHmYlwkl1mg=" - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.nlark.com/serialize-javascript/download/serialize-javascript-6.0.0.tgz", - "integrity": "sha1-765diPRdeSQUHai1w6en5mP+/rg=", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz", - "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-command/download/shebang-command-2.0.0.tgz", - "integrity": "sha1-zNCvT4g1+9wmW4JGGq8MNmY/NOo=", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npm.taobao.org/shebang-regex/download/shebang-regex-3.0.0.tgz", - "integrity": "sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=", - "dev": true - }, - "should": { - "version": "13.2.3", - "resolved": "https://registry.npm.taobao.org/should/download/should-13.2.3.tgz", - "integrity": "sha1-ltjlrPPpe0nYm1H+qlro0H71jxA=", - "dev": true, - "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/should-equal/download/should-equal-2.0.0.tgz", - "integrity": "sha1-YHLPgwRzYIZ+aOmLCdcRQ9BO4MM=", - "dev": true, - "requires": { - "should-type": "^1.4.0" - } - }, - "should-format": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/should-format/download/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "should-type": { - "version": "1.4.0", - "resolved": "https://registry.npm.taobao.org/should-type/download/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", - "dev": true - }, - "should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npm.taobao.org/should-type-adaptors/download/should-type-adaptors-1.1.0.tgz", - "integrity": "sha1-QB5/M7VTMDOUTVzYvytlAneS4no=", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npm.taobao.org/should-util/download/should-util-1.0.1.tgz", - "integrity": "sha1-+w1xM49TKjoUkhNjni0yy+qLyyg=", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npm.taobao.org/side-channel/download/side-channel-1.0.4.tgz", - "integrity": "sha1-785cj9wQTudRslxY1CkAEfpeos8=", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npm.taobao.org/signal-exit/download/signal-exit-3.0.3.tgz", - "integrity": "sha1-oUEMLt2PB3sItOJTyOrPyvBXRhw=", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/slice-ansi/download/slice-ansi-4.0.0.tgz?cache=0&sync_timestamp=1618555008681&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslice-ansi%2Fdownload%2Fslice-ansi-4.0.0.tgz", - "integrity": "sha1-UA6N0P1VsFgVCGJVsxla3ypF/ms=", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", - "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npm.taobao.org/sprintf-js/download/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sqlstring": { - "version": "2.3.2", - "resolved": "https://registry.npm.taobao.org/sqlstring/download/sqlstring-2.3.2.tgz", - "integrity": "sha1-za5xaTiaE3WxjohfLmCz5GCAlRQ=" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1609654066899&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npm.taobao.org/string-argv/download/string-argv-0.3.1.tgz", - "integrity": "sha1-leL77AQnrhkYSTX4FtdKqkxcGdo=", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.2.tgz", - "integrity": "sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU=", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.3.0.tgz", - "integrity": "sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4=", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz", - "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", - "dev": true - } - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npm.taobao.org/stringify-object/download/stringify-object-3.3.0.tgz", - "integrity": "sha1-cDBlrvyhkwDTzoivT1s5VtdVZik=", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.nlark.com/strip-ansi/download/strip-ansi-6.0.0.tgz", - "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.nlark.com/strip-final-newline/download/strip-final-newline-2.0.0.tgz?cache=0&sync_timestamp=1620046746851&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fstrip-final-newline%2Fdownload%2Fstrip-final-newline-2.0.0.tgz", - "integrity": "sha1-ibhS+y/L6Tb29LMYevsKEsGrWK0=", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.1.tgz?cache=0&sync_timestamp=1594567582667&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-3.1.1.tgz", - "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=", - "dev": true - }, - "superagent": { - "version": "6.1.0", - "resolved": "https://registry.npm.taobao.org/superagent/download/superagent-6.1.0.tgz", - "integrity": "sha1-CfCIB7xBEI7xZM+0vik869SA9KY=", - "dev": true, - "requires": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.2", - "methods": "^1.1.2", - "mime": "^2.4.6", - "qs": "^6.9.4", - "readable-stream": "^3.6.0", - "semver": "^7.3.2" - } - }, - "supertest": { - "version": "6.1.4", - "resolved": "https://registry.nlark.com/supertest/download/supertest-6.1.4.tgz?cache=0&sync_timestamp=1626841166051&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupertest%2Fdownload%2Fsupertest-6.1.4.tgz", - "integrity": "sha1-6olTND4MoxboDpdbOTQJNPdU6wY=", - "dev": true, - "requires": { - "methods": "^1.1.2", - "superagent": "^6.1.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.nlark.com/supports-color/download/supports-color-5.5.0.tgz?cache=0&sync_timestamp=1626703400240&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-5.5.0.tgz", - "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.nlark.com/table/download/table-6.7.1.tgz", - "integrity": "sha1-7gVZK3FDgxqMlPPO5qrkwczvM+I=", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.2", - "resolved": "https://registry.nlark.com/ajv/download/ajv-8.6.2.tgz", - "integrity": "sha1-L7ReDl/LwIEzJsHD2lNdGIG7BXE=", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-1.0.0.tgz", - "integrity": "sha1-rnvLNlard6c7pcSb9lTzjmtoYOI=", - "dev": true - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npm.taobao.org/text-table/download/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npm.taobao.org/through/download/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/to-fast-properties/download/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz", - "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", - "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", - "dev": true - }, - "toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.nlark.com/toposort-class/download/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.nlark.com/tslib/download/tslib-1.14.1.tgz?cache=0&sync_timestamp=1623450901878&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftslib%2Fdownload%2Ftslib-1.14.1.tgz", - "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=", - "dev": true - }, - "tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npm.taobao.org/tsscmp/download/tsscmp-1.0.6.tgz", - "integrity": "sha1-hbmVg6w1iexL/vgltQAKqRHWBes=", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npm.taobao.org/type-check/download/type-check-0.4.0.tgz", - "integrity": "sha1-B7ggO/pwVsBlcFDjzNLDdzC6uPE=", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.nlark.com/type-fest/download/type-fest-0.20.2.tgz?cache=0&sync_timestamp=1627560338147&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftype-fest%2Fdownload%2Ftype-fest-0.20.2.tgz", - "integrity": "sha1-G/IH9LKPkVg2ZstfvTJ4hzAc1fQ=", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz", - "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npm.taobao.org/uri-js/download/uri-js-4.4.1.tgz", - "integrity": "sha1-mxpSWVIlhZ5V9mnZKPiMbFfyp34=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.nlark.com/uuid/download/uuid-8.3.2.tgz", - "integrity": "sha1-gNW1ztJxu5r2xEXyGhoExgbO++I=" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npm.taobao.org/v8-compile-cache/download/v8-compile-cache-2.3.0.tgz?cache=0&sync_timestamp=1614993639567&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fv8-compile-cache%2Fdownload%2Fv8-compile-cache-2.3.0.tgz", - "integrity": "sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=", - "dev": true - }, - "validator": { - "version": "13.6.0", - "resolved": "https://registry.nlark.com/validator/download/validator-13.6.0.tgz", - "integrity": "sha1-HnGJnBTNx7IGhGPLJMHMFvbscFk=" - }, - "validatorjs": { - "version": "3.22.1", - "resolved": "https://registry.nlark.com/validatorjs/download/validatorjs-3.22.1.tgz", - "integrity": "sha1-E9u+ZVbPSrh3WRBdE7HTGppUzlQ=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz", - "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npm.taobao.org/wide-align/download/wide-align-1.1.3.tgz", - "integrity": "sha1-rgdOa9wMFKQx6ATmJFScYzsABFc=", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz?cache=0&sync_timestamp=1618552469710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.nlark.com/strip-ansi/download/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "wkx": { - "version": "0.5.0", - "resolved": "https://registry.npm.taobao.org/wkx/download/wkx-0.5.0.tgz", - "integrity": "sha1-xsNwGaz0DlF8xrlGV6JaPUqjPow=", - "requires": { - "@types/node": "*" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz", - "integrity": "sha1-YQY29rH3A4kb00dxzLF/uTtHB5w=", - "dev": true - }, - "workerpool": { - "version": "6.1.5", - "resolved": "https://registry.nlark.com/workerpool/download/workerpool-6.1.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fworkerpool%2Fdownload%2Fworkerpool-6.1.5.tgz", - "integrity": "sha1-D3zwdrYhX9fh2pA/9vIt3RiGtYE=", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-7.0.0.tgz", - "integrity": "sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM=", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", - "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", - "dev": true + "name": "lowcode-controller", + "version": "1.0.9", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lowcode-controller", + "version": "1.0.9", + "license": "ISC", + "dependencies": { + "lodash": "^4.17.21", + "mysql2": "^2.2.5", + "sequelize": "^6.6.5", + "validatorjs": "^3.22.1" + }, + "devDependencies": { + "@types/lodash": "^4.17.24", + "@types/node": "^25.9.3", + "@types/validatorjs": "^3.15.5", + "koa": "^2.13.1", + "koa-bodyparser": "^4.3.0", + "koa-router": "^10.0.0", + "mocha": "^9.0.3", + "prettier": "^3.8.4", + "should": "^13.2.3", + "supertest": "^6.1.4", + "typescript": "^6.0.3" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/validatorjs": { + "version": "3.15.5", + "resolved": "https://registry.npmmirror.com/@types/validatorjs/-/validatorjs-3.15.5.tgz", + "integrity": "sha512-yb4ADqCqy6EzBMMLJ7mvBzFR/bCtivTPRvuvRwjdM10hpxPSdHybK6SW0ZTLPad5FGPqiZk/g70EIybxmaBAEA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/@ungap/promise-all-settled/download/@ungap/promise-all-settled-1.1.2.tgz", + "integrity": "sha1-qlgEJxHW4ydd033Fl+XTHowpCkQ=", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", + "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", + "dev": true, + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npm.taobao.org/ansi-colors/download/ansi-colors-4.1.1.tgz", + "integrity": "sha1-y7muJWv3UK8eqzRPIpqif+lLo0g=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-5.0.0.tgz", + "integrity": "sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npm.taobao.org/anymatch/download/anymatch-3.1.2.tgz?cache=0&sync_timestamp=1617747502795&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fanymatch%2Fdownload%2Fanymatch-3.1.2.tgz", + "integrity": "sha1-wFV8CWrzLxBhmPT04qODU343hxY=", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.2.tgz", + "integrity": "sha1-6D46fj8wCzTLnYf2FfoMvzV2kO4=", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.nlark.com/binary-extensions/download/binary-extensions-2.2.0.tgz", + "integrity": "sha1-dfUC7q+f/eQvyYgpZFvk6na9ni0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.nlark.com/brace-expansion/download/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npm.taobao.org/braces/download/braces-3.0.2.tgz", + "integrity": "sha1-NFThpGLujVmeI23zNs2epPiv4Qc=", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.nlark.com/browser-stdout/download/browser-stdout-1.3.1.tgz", + "integrity": "sha1-uqVZ7hTO1zRSIputcyZGfGH6vWA=", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz", + "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/cache-content-type/download/cache-content-type-1.0.1.tgz", + "integrity": "sha1-A1zeKwjuISn0qDFeqPAKANuhRTw=", + "dev": true, + "dependencies": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/call-bind/download/call-bind-1.0.2.tgz?cache=0&sync_timestamp=1610402896029&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcall-bind%2Fdownload%2Fcall-bind-1.0.2.tgz", + "integrity": "sha1-sdTonmiBGcPJqQOtMKuy9qkZvjw=", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-6.2.0.tgz?cache=0&sync_timestamp=1603921882890&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-6.2.0.tgz", + "integrity": "sha1-kkr4gcnVJaydh/QNlk5c6pgqGAk=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.nlark.com/chalk/download/chalk-4.1.2.tgz?cache=0&sync_timestamp=1627646734234&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fchalk%2Fdownload%2Fchalk-4.1.2.tgz", + "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1626715907927&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", + "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1626703400240&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz", + "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.nlark.com/chokidar/download/chokidar-3.5.2.tgz", + "integrity": "sha1-26OXb8rbAW9m/TZQIdkWANAcHnU=", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-7.0.4.tgz?cache=0&sync_timestamp=1604880017635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-7.0.4.tgz", + "integrity": "sha1-oCZe5lVHb8gHrqnfPfjfd4OAi08=", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/co-body": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/co-body/download/co-body-6.1.0.tgz", + "integrity": "sha1-2HqO/DVk+b/jrO2O9c0Ex6h2ZUc=", + "dev": true, + "dependencies": { + "inflation": "^2.0.0", + "qs": "^6.5.2", + "raw-body": "^2.3.3", + "type-is": "^1.6.16" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.8.tgz", + "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz", + "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz", + "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", + "dev": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/cookiejar/download/cookiejar-2.1.2.tgz", + "integrity": "sha1-3YojVTB1L5iPmghE8/xYnjERElw=", + "dev": true + }, + "node_modules/cookies": { + "version": "0.8.0", + "resolved": "https://registry.npm.taobao.org/cookies/download/cookies-0.8.0.tgz", + "integrity": "sha1-EpPOSzkXQKhAbjyYcOgoxLVPP5A=", + "dev": true, + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/copy-to": { + "version": "2.0.1", + "resolved": "https://registry.nlark.com/copy-to/download/copy-to-2.0.1.tgz", + "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.nlark.com/debug/download/debug-4.3.2.tgz", + "integrity": "sha1-8KScGKyHeeMdSgxgKd+3aHPHQos=", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/decamelize/download/decamelize-4.0.0.tgz?cache=0&sync_timestamp=1610348670939&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdecamelize%2Fdownload%2Fdecamelize-4.0.0.tgz", + "integrity": "sha1-qkcte/Zg6xXzSU79UxyrfypwmDc=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/deep-equal/download/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/denque": { + "version": "1.5.0", + "resolved": "https://registry.npm.taobao.org/denque/download/denque-1.5.0.tgz", + "integrity": "sha1-dz3gaG/y2Owv+SkUMWpHtzscc94=", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/depd/download/depd-2.0.0.tgz", + "integrity": "sha1-tpYWPMdXVg0JzyLMj60Vcbeedt8=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.nlark.com/diff/download/diff-5.0.0.tgz?cache=0&sync_timestamp=1622685824253&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdiff%2Fdownload%2Fdiff-5.0.0.tgz", + "integrity": "sha1-ftatdthZ0DB4fsNYVfWx2vMdhSs=", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dottie": { + "version": "2.0.2", + "resolved": "https://registry.nlark.com/dottie/download/dottie-2.0.2.tgz", + "integrity": "sha1-zJHAcmzjoFTr8RxV+8kqfyZt0VQ=" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npm.taobao.org/emoji-regex/download/emoji-regex-8.0.0.tgz?cache=0&sync_timestamp=1614682725186&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Femoji-regex%2Fdownload%2Femoji-regex-8.0.0.tgz", + "integrity": "sha1-6Bj9ac5cz8tARZT4QpY79TFkzDc=", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/escalade/download/escalade-3.1.1.tgz?cache=0&sync_timestamp=1602567261690&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescalade%2Fdownload%2Fescalade-3.1.1.tgz", + "integrity": "sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA=", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/escape-string-regexp/download/escape-string-regexp-4.0.0.tgz?cache=0&sync_timestamp=1618677243201&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fescape-string-regexp%2Fdownload%2Fescape-string-regexp-4.0.0.tgz", + "integrity": "sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.0.8", + "resolved": "https://registry.nlark.com/fast-safe-stringify/download/fast-safe-stringify-2.0.8.tgz?cache=0&sync_timestamp=1625835811932&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ffast-safe-stringify%2Fdownload%2Ffast-safe-stringify-2.0.8.tgz", + "integrity": "sha1-3Cr0jEbPcStoPoSbK71EazLek28=", + "dev": true + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npm.taobao.org/fill-range/download/fill-range-7.0.1.tgz", + "integrity": "sha1-GRmmp8df44ssfHflGYU12prN2kA=", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npm.taobao.org/find-up/download/find-up-5.0.0.tgz?cache=0&sync_timestamp=1597170071453&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffind-up%2Fdownload%2Ffind-up-5.0.0.tgz", + "integrity": "sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw=", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.nlark.com/flat/download/flat-5.0.2.tgz", + "integrity": "sha1-jKb+MyBp/6nTJMMnGYxZglnOskE=", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.nlark.com/form-data/download/form-data-3.0.1.tgz", + "integrity": "sha1-69U3kbeDVqma+aMA1CgsTV65dV8=", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "1.2.2", + "resolved": "https://registry.npm.taobao.org/formidable/download/formidable-1.2.2.tgz", + "integrity": "sha1-v2muopcpgmdfAIZTQrmCmG9rjdk=", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "dev": true, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npm.taobao.org/fsevents/download/fsevents-2.3.2.tgz", + "integrity": "sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro=", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/function-bind/download/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "dev": true + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npm.taobao.org/generate-function/download/generate-function-2.3.1.tgz", + "integrity": "sha1-8GlhdpDBDIaOc7hGV0Z2T5fDR58=", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npm.taobao.org/get-caller-file/download/get-caller-file-2.0.5.tgz", + "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz", + "integrity": "sha1-FfWfN2+FXERpY5SPDSTNNje0q8Y=", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.nlark.com/glob/download/glob-7.1.7.tgz?cache=0&sync_timestamp=1620337382269&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob%2Fdownload%2Fglob-7.1.7.tgz", + "integrity": "sha1-Oxk+kjPwHULQs/eClLvutBj5SpA=", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.nlark.com/glob-parent/download/glob-parent-5.1.2.tgz?cache=0&sync_timestamp=1626760235241&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fglob-parent%2Fdownload%2Fglob-parent-5.1.2.tgz", + "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.nlark.com/growl/download/growl-1.10.5.tgz", + "integrity": "sha1-8nNdwig2dPpnR4sQGBBZNVw2nl4=", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npm.taobao.org/has/download/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/has-symbols/download/has-symbols-1.0.2.tgz?cache=0&sync_timestamp=1614443577352&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-symbols%2Fdownload%2Fhas-symbols-1.0.2.tgz", + "integrity": "sha1-Fl0wcMADCXUqEjakeTMeOsVvFCM=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/he/download/he-1.2.0.tgz", + "integrity": "sha1-hK5l+n6vsWX922FWauFLrwVmTw8=", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-assert": { + "version": "1.4.1", + "resolved": "https://registry.npm.taobao.org/http-assert/download/http-assert-1.4.1.tgz", + "integrity": "sha1-xfcl1neqfoc+9zYZm4lobM6zeHg=", + "dev": true, + "dependencies": { + "deep-equal": "~1.0.1", + "http-errors": "~1.7.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-assert/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-assert/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.3.tgz?cache=0&sync_timestamp=1593407611415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.3.tgz", + "integrity": "sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY=", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "1.8.0", + "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.8.0.tgz?cache=0&sync_timestamp=1593407611415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.8.0.tgz", + "integrity": "sha1-ddG75JfhBE9R5O6ecEpi8o0zZQc=", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.2.0.tgz", + "integrity": "sha1-ZsmiSnP5/CjL5msJ/tPTPcrxtCQ=", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.6.3.tgz", + "integrity": "sha1-pS+AvzjaGVLrXGgXkHGYcaGnJQE=", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflation": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/inflation/download/inflation-2.0.0.tgz", + "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/inflection": { + "version": "1.13.1", + "resolved": "https://registry.nlark.com/inflection/download/inflection-1.13.1.tgz", + "integrity": "sha1-xcrdgIiKkM+EwuluNA1+3IXV8Ms=", + "engines": [ + "node >= 0.4.0" + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz", + "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w=", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/is-binary-path/download/is-binary-path-2.1.0.tgz", + "integrity": "sha1-6h9/O4DwZCNug0cPhsCcJU+0Wwk=", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/is-extglob/download/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-3.0.0.tgz?cache=0&sync_timestamp=1618552469710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha1-8Rb4Bk/pCz94RKOJl8C3UFEmnx0=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.9", + "resolved": "https://registry.nlark.com/is-generator-function/download/is-generator-function-1.0.9.tgz", + "integrity": "sha1-5fgsIyNnPn/K09EoWMg8QDn2OZw=", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npm.taobao.org/is-glob/download/is-glob-4.0.1.tgz", + "integrity": "sha1-dWfb6fL14kZ7x3q4PEopSCQHpdw=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npm.taobao.org/is-number/download/is-number-7.0.0.tgz", + "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.nlark.com/is-plain-obj/download/is-plain-obj-2.1.0.tgz", + "integrity": "sha1-ReQuN/zPH0Dajl927iFRWEDAkoc=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/is-property/download/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.nlark.com/is-unicode-supported/download/is-unicode-supported-0.1.0.tgz", + "integrity": "sha1-PybHaoCVk7Ur+i7LVxDtJ3m1Iqc=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/keygrip/download/keygrip-1.1.0.tgz", + "integrity": "sha1-hxsWgdXhWcYqRFsMdLYV4JF+ciY=", + "dev": true, + "dependencies": { + "tsscmp": "1.0.6" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/koa": { + "version": "2.13.1", + "resolved": "https://registry.npm.taobao.org/koa/download/koa-2.13.1.tgz", + "integrity": "sha1-YnUXKHWye8/h1FQ1altrn1qbEFE=", + "dev": true, + "dependencies": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.8.0", + "debug": "~3.1.0", + "delegates": "^1.0.0", + "depd": "^2.0.0", + "destroy": "^1.0.4", + "encodeurl": "^1.0.2", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^1.2.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + }, + "engines": { + "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" + } + }, + "node_modules/koa-bodyparser": { + "version": "4.3.0", + "resolved": "https://registry.npm.taobao.org/koa-bodyparser/download/koa-bodyparser-4.3.0.tgz", + "integrity": "sha1-J0x3hVX/SPoiHufzap+9us4idZo=", + "dev": true, + "dependencies": { + "co-body": "^6.0.0", + "copy-to": "^2.0.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.nlark.com/koa-compose/download/koa-compose-4.1.0.tgz", + "integrity": "sha1-UHMGuTcZAdtBEhyBLpI9DWfT6Hc=", + "dev": true + }, + "node_modules/koa-convert": { + "version": "1.2.0", + "resolved": "https://registry.npm.taobao.org/koa-convert/download/koa-convert-1.2.0.tgz", + "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "dev": true, + "dependencies": { + "co": "^4.6.0", + "koa-compose": "^3.0.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/koa-convert/node_modules/koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.nlark.com/koa-compose/download/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "dev": true, + "dependencies": { + "any-promise": "^1.1.0" + } + }, + "node_modules/koa-router": { + "version": "10.0.0", + "resolved": "https://registry.npm.taobao.org/koa-router/download/koa-router-10.0.0.tgz", + "integrity": "sha1-e8dqAxCFcx5h/JLBaDaHsvRN5qQ=", + "deprecated": "Please use @koa/router instead, starting from v9! ", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "koa-compose": "^4.1.0", + "methods": "^1.1.2", + "path-to-regexp": "^6.1.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/koa/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.nlark.com/debug/download/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/koa/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npm.taobao.org/locate-path/download/locate-path-6.0.0.tgz?cache=0&sync_timestamp=1597081904643&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flocate-path%2Fdownload%2Flocate-path-6.0.0.tgz", + "integrity": "sha1-VTIeswn+u8WcSAHZMackUqaB0oY=", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.nlark.com/lodash/download/lodash-4.17.21.tgz", + "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npm.taobao.org/log-symbols/download/log-symbols-4.1.0.tgz", + "integrity": "sha1-P727lbRoOsn8eFER55LlWNSr1QM=", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz", + "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594427519396&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npm.taobao.org/mime/download/mime-2.5.2.tgz", + "integrity": "sha1-bj3GzCuVEGQ4MOXxnVy3U9pe6r4=", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.49.0", + "resolved": "https://registry.nlark.com/mime-db/download/mime-db-1.49.0.tgz?cache=0&sync_timestamp=1627335450684&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmime-db%2Fdownload%2Fmime-db-1.49.0.tgz", + "integrity": "sha1-89/eYMmenPO8lwHWh3ePU3ABy+0=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.32", + "resolved": "https://registry.nlark.com/mime-types/download/mime-types-2.1.32.tgz", + "integrity": "sha1-HQDonn3n/gIAjbYQAdngKFJnD9U=", + "dev": true, + "dependencies": { + "mime-db": "1.49.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha": { + "version": "9.0.3", + "resolved": "https://registry.nlark.com/mocha/download/mocha-9.0.3.tgz?cache=0&sync_timestamp=1627230567467&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmocha%2Fdownload%2Fmocha-9.0.3.tgz", + "integrity": "sha1-EozWu9PuCtza73FfNX927B5iJ8c=", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.23", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/argparse/download/argparse-2.0.1.tgz", + "integrity": "sha1-JG9Q88p4oyQPbJl+ipvR6sSeSzg=", + "dev": true + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.nlark.com/debug/download/debug-4.3.1.tgz", + "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=", + "dev": true + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1626715907927&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz", + "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npm.taobao.org/js-yaml/download/js-yaml-4.1.0.tgz?cache=0&sync_timestamp=1618434911653&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjs-yaml%2Fdownload%2Fjs-yaml-4.1.0.tgz", + "integrity": "sha1-wftl+PUBeQHN0slRhkuhhFihBgI=", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.3.tgz", + "integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.nlark.com/supports-color/download/supports-color-8.1.1.tgz?cache=0&sync_timestamp=1626703400240&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupports-color%2Fdownload%2Fsupports-color-8.1.1.tgz", + "integrity": "sha1-zW/BfihQDP9WwbhsCn/UpUpzAFw=", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz?cache=0&sync_timestamp=1601983423917&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmoment%2Fdownload%2Fmoment-2.29.1.tgz", + "integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M=", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.33", + "resolved": "https://registry.nlark.com/moment-timezone/download/moment-timezone-0.5.33.tgz", + "integrity": "sha1-slL9a7V/NBybWaWrYajlGnO70iw=", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz", + "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" + }, + "node_modules/mysql2": { + "version": "2.2.5", + "resolved": "https://registry.npm.taobao.org/mysql2/download/mysql2-2.2.5.tgz", + "integrity": "sha1-cmJP+0gW+A+Wucl/7djACTX580A=", + "dependencies": { + "denque": "^1.4.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.2", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/named-placeholders/download/named-placeholders-1.1.2.tgz", + "integrity": "sha1-zrH7/1C2szSStc8hTM9eOc7z0Og=", + "dependencies": { + "lru-cache": "^4.1.3" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-4.1.5.tgz?cache=0&sync_timestamp=1594427519396&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-4.1.5.tgz", + "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/named-placeholders/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/nanoid": { + "version": "3.1.23", + "resolved": "https://registry.nlark.com/nanoid/download/nanoid-3.1.23.tgz", + "integrity": "sha1-90QIbOfCvEfuCoRyV01ceOQYOoE=", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz", + "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npm.taobao.org/normalize-path/download/normalize-path-3.0.0.tgz", + "integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.nlark.com/object-inspect/download/object-inspect-1.11.0.tgz", + "integrity": "sha1-nc6xRs7dQUig2eUauI00z1CZIrE=", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/only": { + "version": "0.0.2", + "resolved": "https://registry.npm.taobao.org/only/download/only-0.0.2.tgz", + "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=", + "dev": true + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npm.taobao.org/p-limit/download/p-limit-3.1.0.tgz?cache=0&sync_timestamp=1606288333421&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-limit%2Fdownload%2Fp-limit-3.1.0.tgz", + "integrity": "sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs=", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npm.taobao.org/p-locate/download/p-locate-5.0.0.tgz?cache=0&sync_timestamp=1597081785924&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fp-locate%2Fdownload%2Fp-locate-5.0.0.tgz", + "integrity": "sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ=", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz", + "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-4.0.0.tgz", + "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "6.2.0", + "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-6.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpath-to-regexp%2Fdownload%2Fpath-to-regexp-6.2.0.tgz", + "integrity": "sha1-97OAMzYQTDRoia3s5hRmkjBkXzg=", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.nlark.com/picomatch/download/picomatch-2.3.0.tgz", + "integrity": "sha1-8fBh3o9qS/AiiS4tEoI0+5gwKXI=", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "3.8.4", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/pseudomap/download/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/qs": { + "version": "6.10.1", + "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.10.1.tgz", + "integrity": "sha1-STFIL6jWR6Wqt5nFJx0hM7mB+2o=", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz", + "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.1.tgz", + "integrity": "sha1-MKyC+Yu1rowVLmcUnayNVRU7Fow=", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.3.tgz?cache=0&sync_timestamp=1593407611415&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.3.tgz", + "integrity": "sha1-bGGeT5xgMIw4UZSYwU+7EKrOuwY=", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.nlark.com/iconv-lite/download/iconv-lite-0.4.24.tgz", + "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-3.6.0.tgz", + "integrity": "sha1-M3u9o63AcGvT4CRCaihtS0sskZg=", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npm.taobao.org/readdirp/download/readdirp-3.6.0.tgz?cache=0&sync_timestamp=1615717369278&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freaddirp%2Fdownload%2Freaddirp-3.6.0.tgz", + "integrity": "sha1-dKNwvYVxFuJFspzJc0DNQxoCpsc=", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/require-directory/download/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.nlark.com/retry-as-promised/download/retry-as-promised-3.2.0.tgz", + "integrity": "sha1-dp9j1Ta+xHg1SdsHd8tW2t2dhUM=", + "dependencies": { + "any-promise": "^1.3.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.5.tgz?cache=0&sync_timestamp=1616463608061&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.5.tgz", + "integrity": "sha1-C2Ich5NI2JmOSw5L6Us/EuYBjvc=", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npm.taobao.org/seq-queue/download/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" + }, + "node_modules/sequelize": { + "version": "6.6.5", + "resolved": "https://registry.nlark.com/sequelize/download/sequelize-6.6.5.tgz", + "integrity": "sha1-b2GOmfPfH8gfKHCeijE5zsPvHww=", + "dependencies": { + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.13.1", + "lodash": "^4.17.20", + "moment": "^2.26.0", + "moment-timezone": "^0.5.31", + "retry-as-promised": "^3.2.0", + "semver": "^7.3.2", + "sequelize-pool": "^6.0.0", + "toposort-class": "^1.0.1", + "uuid": "^8.1.0", + "validator": "^13.6.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-pool": { + "version": "6.1.0", + "resolved": "https://registry.nlark.com/sequelize-pool/download/sequelize-pool-6.1.0.tgz", + "integrity": "sha1-yqoMHjJNPCw6OZ/tLHmYlwkl1mg=", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.nlark.com/serialize-javascript/download/serialize-javascript-6.0.0.tgz", + "integrity": "sha1-765diPRdeSQUHai1w6en5mP+/rg=", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz", + "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=", + "dev": true + }, + "node_modules/should": { + "version": "13.2.3", + "resolved": "https://registry.npm.taobao.org/should/download/should-13.2.3.tgz", + "integrity": "sha1-ltjlrPPpe0nYm1H+qlro0H71jxA=", + "dev": true, + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/should-equal/download/should-equal-2.0.0.tgz", + "integrity": "sha1-YHLPgwRzYIZ+aOmLCdcRQ9BO4MM=", + "dev": true, + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "resolved": "https://registry.npm.taobao.org/should-format/download/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "resolved": "https://registry.npm.taobao.org/should-type/download/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "resolved": "https://registry.npm.taobao.org/should-type-adaptors/download/should-type-adaptors-1.1.0.tgz", + "integrity": "sha1-QB5/M7VTMDOUTVzYvytlAneS4no=", + "dev": true, + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "resolved": "https://registry.npm.taobao.org/should-util/download/should-util-1.0.1.tgz", + "integrity": "sha1-+w1xM49TKjoUkhNjni0yy+qLyyg=", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npm.taobao.org/side-channel/download/side-channel-1.0.4.tgz", + "integrity": "sha1-785cj9wQTudRslxY1CkAEfpeos8=", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sqlstring": { + "version": "2.3.2", + "resolved": "https://registry.npm.taobao.org/sqlstring/download/sqlstring-2.3.2.tgz", + "integrity": "sha1-za5xaTiaE3WxjohfLmCz5GCAlRQ=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1609654066899&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.3.0.tgz", + "integrity": "sha1-QvEUWUpGzxqOMLCoT1bHjD7awh4=", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz", + "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-4.2.2.tgz", + "integrity": "sha1-2v1PlVmnWFz7pSnGoKT3NIjr1MU=", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.nlark.com/strip-ansi/download/strip-ansi-6.0.0.tgz", + "integrity": "sha1-CxVx3XZpzNTz4G4U7x7tJiJa5TI=", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npm.taobao.org/strip-json-comments/download/strip-json-comments-3.1.1.tgz?cache=0&sync_timestamp=1594567582667&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-json-comments%2Fdownload%2Fstrip-json-comments-3.1.1.tgz", + "integrity": "sha1-MfEoGzgyYwQ0gxwxDAHMzajL4AY=", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "6.1.0", + "resolved": "https://registry.npm.taobao.org/superagent/download/superagent-6.1.0.tgz", + "integrity": "sha1-CfCIB7xBEI7xZM+0vik869SA9KY=", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 7.0.0" + } + }, + "node_modules/supertest": { + "version": "6.1.4", + "resolved": "https://registry.nlark.com/supertest/download/supertest-6.1.4.tgz?cache=0&sync_timestamp=1626841166051&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fsupertest%2Fdownload%2Fsupertest-6.1.4.tgz", + "integrity": "sha1-6olTND4MoxboDpdbOTQJNPdU6wY=", + "deprecated": "Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net", + "dev": true, + "dependencies": { + "methods": "^1.1.2", + "superagent": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npm.taobao.org/to-regex-range/download/to-regex-range-5.0.1.tgz", + "integrity": "sha1-FkjESq58jZiKMmAY7XL1tN0DkuQ=", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", + "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.nlark.com/toposort-class/download/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npm.taobao.org/tsscmp/download/tsscmp-1.0.6.tgz", + "integrity": "sha1-hbmVg6w1iexL/vgltQAKqRHWBes=", + "dev": true, + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz", + "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.nlark.com/uuid/download/uuid-8.3.2.tgz", + "integrity": "sha1-gNW1ztJxu5r2xEXyGhoExgbO++I=", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.6.0", + "resolved": "https://registry.nlark.com/validator/download/validator-13.6.0.tgz", + "integrity": "sha1-HnGJnBTNx7IGhGPLJMHMFvbscFk=", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validatorjs": { + "version": "3.22.1", + "resolved": "https://registry.nlark.com/validatorjs/download/validatorjs-3.22.1.tgz", + "integrity": "sha1-E9u+ZVbPSrh3WRBdE7HTGppUzlQ=" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npm.taobao.org/which/download/which-2.0.2.tgz", + "integrity": "sha1-fGqN0KY2oDJ+ELWckobu6T8/UbE=", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npm.taobao.org/wide-align/download/wide-align-1.1.3.tgz", + "integrity": "sha1-rgdOa9wMFKQx6ATmJFScYzsABFc=", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.nlark.com/ansi-regex/download/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npm.taobao.org/is-fullwidth-code-point/download/is-fullwidth-code-point-2.0.0.tgz?cache=0&sync_timestamp=1618552469710&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-fullwidth-code-point%2Fdownload%2Fis-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npm.taobao.org/string-width/download/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.nlark.com/strip-ansi/download/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npm.taobao.org/wkx/download/wkx-0.5.0.tgz", + "integrity": "sha1-xsNwGaz0DlF8xrlGV6JaPUqjPow=", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/workerpool": { + "version": "6.1.5", + "resolved": "https://registry.nlark.com/workerpool/download/workerpool-6.1.5.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fworkerpool%2Fdownload%2Fworkerpool-6.1.5.tgz", + "integrity": "sha1-D3zwdrYhX9fh2pA/9vIt3RiGtYE=", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-7.0.0.tgz", + "integrity": "sha1-Z+FFz/UQpqaYS98RUpEdadLrnkM=", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.nlark.com/ansi-styles/download/ansi-styles-4.3.0.tgz", + "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz", + "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz", + "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.nlark.com/y18n/download/y18n-5.0.8.tgz", + "integrity": "sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.nlark.com/yargs/download/yargs-16.2.0.tgz?cache=0&sync_timestamp=1626358476652&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fyargs%2Fdownload%2Fyargs-16.2.0.tgz", + "integrity": "sha1-HIK/D2tqZur85+8w43b0mhJHf2Y=", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.nlark.com/yargs-parser/download/yargs-parser-20.2.4.tgz", + "integrity": "sha1-tCiQ8UVmeW+Fro46JSkNIF8VSlQ=", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.nlark.com/yargs-unparser/download/yargs-unparser-2.0.0.tgz", + "integrity": "sha1-8TH5ImkRrl2a04xDL+gJNmwjJes=", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ylru": { + "version": "1.2.1", + "resolved": "https://registry.npm.taobao.org/ylru/download/ylru-1.2.1.tgz", + "integrity": "sha1-9Xa2M0FUeYnB3nuiiHYJI7J/6E8=", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npm.taobao.org/yocto-queue/download/yocto-queue-0.1.0.tgz?cache=0&sync_timestamp=1606290212047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyocto-queue%2Fdownload%2Fyocto-queue-0.1.0.tgz", + "integrity": "sha1-ApTrPe4FAo0x7hpfosVWpqrxChs=", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.nlark.com/wrappy/download/wrappy-1.0.2.tgz?cache=0&sync_timestamp=1619133505879&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fwrappy%2Fdownload%2Fwrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.nlark.com/y18n/download/y18n-5.0.8.tgz", - "integrity": "sha1-f0k00PfKjFb5UxSTndzS3ZHOHVU=", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz", - "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=" - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.nlark.com/yaml/download/yaml-1.10.2.tgz?cache=0&sync_timestamp=1626517649204&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fyaml%2Fdownload%2Fyaml-1.10.2.tgz", - "integrity": "sha1-IwHF/78StGfejaIzOkWeKeeSDks=", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.nlark.com/yargs/download/yargs-16.2.0.tgz?cache=0&sync_timestamp=1626358476652&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fyargs%2Fdownload%2Fyargs-16.2.0.tgz", - "integrity": "sha1-HIK/D2tqZur85+8w43b0mhJHf2Y=", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.nlark.com/yargs-parser/download/yargs-parser-20.2.4.tgz", - "integrity": "sha1-tCiQ8UVmeW+Fro46JSkNIF8VSlQ=", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.nlark.com/yargs-unparser/download/yargs-unparser-2.0.0.tgz", - "integrity": "sha1-8TH5ImkRrl2a04xDL+gJNmwjJes=", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "ylru": { - "version": "1.2.1", - "resolved": "https://registry.npm.taobao.org/ylru/download/ylru-1.2.1.tgz", - "integrity": "sha1-9Xa2M0FUeYnB3nuiiHYJI7J/6E8=", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npm.taobao.org/yocto-queue/download/yocto-queue-0.1.0.tgz?cache=0&sync_timestamp=1606290212047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyocto-queue%2Fdownload%2Fyocto-queue-0.1.0.tgz", - "integrity": "sha1-ApTrPe4FAo0x7hpfosVWpqrxChs=", - "dev": true } - } } diff --git a/package.json b/package.json index 6ec6eb0..6c6275a 100644 --- a/package.json +++ b/package.json @@ -1,43 +1,66 @@ { - "name": "lowcode-controller", - "version": "1.0.7", - "description": "a low-code controller util, you can use json write your controller code", - "keywords": ["lowcode controller", "lowcode", "controller"], - "main": "index.js", - "files": ["./index", "/lib"], - "scripts": { - "test": "mocha ./test/*.test.js", - "lint": "eslint ./ --fix" - }, - "author": "wrfighting", - "license": "ISC", - "dependencies": { - "lodash": "^4.17.21", - "mysql2": "^2.2.5", - "sequelize": "^6.6.5", - "validatorjs": "^3.22.1" - }, - "devDependencies": { - "babel-eslint": "^10.1.0", - "eslint": "^7.32.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^3.4.0", - "husky": "^7.0.1", - "koa": "^2.13.1", - "koa-bodyparser": "^4.3.0", - "koa-router": "^10.0.0", - "lint-staged": "^11.1.1", - "mocha": "^9.0.3", - "prettier": "^2.3.2", - "should": "^13.2.3", - "supertest": "^6.1.4" - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" + "name": "lowcode-controller", + "version": "1.0.8", + "description": "Build Sequelize CRUD controllers from declarative JSON configuration.", + "keywords": [ + "low-code", + "controller", + "sequelize", + "crud", + "typescript" + ], + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "files": [ + "dist", + "readme.md", + "README.zh-CN.md" + ], + "sideEffects": false, + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig.json --noEmit", + "typecheck:package": "npm run build && tsc --ignoreConfig --noEmit --strict --skipLibCheck --target ES2019 --module Node16 --moduleResolution Node16 ./test/types.test.ts", + "test": "npm run build && mocha ./test/core.test.js", + "test:integration": "npm run build && mocha ./test/index.test.js", + "lint": "npm run typecheck", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.{js,ts}\" \"*.json\" \"*.md\"", + "verify": "npm run typecheck && npm test && npm run typecheck:package", + "prepack": "npm run build", + "prepublishOnly": "npm run verify" + }, + "author": "wrfighting", + "license": "ISC", + "publishConfig": { + "access": "public" + }, + "dependencies": { + "lodash": "^4.17.21", + "mysql2": "^2.2.5", + "sequelize": "^6.6.5", + "validatorjs": "^3.22.1" + }, + "devDependencies": { + "@types/lodash": "^4.17.24", + "@types/node": "^25.9.3", + "@types/validatorjs": "^3.15.5", + "koa": "^2.13.1", + "koa-bodyparser": "^4.3.0", + "koa-router": "^10.0.0", + "mocha": "^9.0.3", + "prettier": "^3.8.4", + "should": "^13.2.3", + "supertest": "^6.1.4", + "typescript": "^6.0.3" + }, + "engines": { + "node": ">= 10.0.0" } - }, - "engines": { - "node": ">= 10.0.0" - } } diff --git a/readme.md b/readme.md index b8d55ef..da5bd6d 100644 --- a/readme.md +++ b/readme.md @@ -1,322 +1,274 @@ # lowcode-controller -lowcode-controller是一个可以用json来配置化的生成对应的controller逻辑的工具,它允许配置化的生成分页查询、查询单条、查询列表、新增、更新、删除逻辑,能够覆盖大部分crud场景 -你也可以通过class的方法重写和定义自己的逻辑处理 -它也提供了各个阶段的生命周期,你可以在对应的生命周期定义自己的逻辑 +[English](./readme.md) | [简体中文](./README.zh-CN.md) -## 安装 ## +`lowcode-controller` builds common Sequelize CRUD controller logic from a +declarative configuration object. It supports paginated, list, and single-item +queries, creation, updates, soft or physical deletion, validation, lifecycle +hooks, and custom response fields. -```` -npm install --save lowcode-controller -```` +The package is written in strict TypeScript and publishes CommonJS JavaScript, +source maps, and generated type declarations. Existing JavaScript consumers +can continue to use `require()`. -## 基本使用 +## Installation -```javascript -//in your controller /controller/cats.js -const { LowCodeController } = require('lowcode-controller') -const cats_model = require('../model/cat_model') -const path = require('path') +```bash +npm install lowcode-controller +``` -LowCodeController.setGlobalDBPath(path.join(__dirname, '../db/mysql')) // 设置数据库文件 -LowCodeController.setUserNameField('username') // 可以设置用户名的字段key -LowCodeController.setCustomResField('code', 'msg', 'data') // 允许自定义返回的字段key,默认是 { errno: 0, errmsg: 'success', data: null } +## Basic usage -class CatsController extends LowCodeController { - constructor(model, config, db, extraOptions) { - super(model, config, null, extraOptions) - } +```ts +import path from 'node:path' +import { + LowCodeController, + type LowCodeControllerConfig, +} from 'lowcode-controller' - async sayHello(ctx) { - ctx.body = { errno: 0, message: 'hello world', data: 'hello world' } - } -} +import CatModel from '../model/cat_model' -const Cats = new CatsController( - cats_model, - { - pageQuery: { - query: { - cat_name: { - like: true, - value: 'cat_name', - }, - age: { - type: 'constant', - value: 2, - }, - }, - extraOptions: { - order: [['cat_name', 'DESC']], - attributes: ['cat_name', 'age', 'job'], - }, - beforeQueryHook: async function (ctx) { - console.log('before query hook') - return null - }, +LowCodeController.setGlobalDBPath(path.join(__dirname, '../db/mysql')) +LowCodeController.setUserNameField('username') + +const config: LowCodeControllerConfig = { + pageQuery: { + query: { + cat_name: { value: 'cat_name', like: true }, + age: { type: 'constant', value: 2 }, }, - getList: { - extraOptions: { - order: [['cat_name', 'DESC']], - attributes: ['cat_name', 'age', 'job'], - }, - afterQueryHook: async function (ctx, sourceResults) { - sourceResults.forEach(item => { - item.desc = 'cute cat' - }) - return sourceResults - }, + extraOptions: { + order: [['cat_name', 'DESC']], + attributes: ['cat_name', 'age', 'job'], }, - create: { - validate: { - cat_name: { - name: 'cat name', - rule: 'required', - }, - }, - constantCreate: { - age: 2, + }, + getList: { + query: { + birthday: { + type: 'varTime', + value: ['start', 'end'], }, - enableBatch: true, }, - update: { - pick: ['job'], - query: { - job: 'student', - }, - afterUpdateHook: async function (ctx, t, updateItem) { - if (updateItem.job === 'rollback') { - throw new Error('roll back') - } - }, + afterQueryHook: async results => + results.map(item => ({ ...item, description: 'cute cat' })), + }, + create: { + validate: { + cat_name: { name: 'cat name', rule: 'required' }, + }, + constantCreate: { age: 2 }, + enableBatch: true, + }, + update: { + pick: ['job'], + afterUpdateHook: async updateItem => { + if (updateItem.job === 'rollback') { + throw new Error('roll back') + } }, }, - null, - { - creatorField: 'creator', - updatorField: 'updator', +} + +class CatsController extends LowCodeController { + public constructor() { + super(CatModel, config, null, { + creatorField: 'creator', + updatorField: 'updator', + }) } -) +} -module.exports = Cats +export default new CatsController() ``` -```javascript -//router.js +JavaScript usage remains unchanged: -//you can choose the routing module you like +```js +const { LowCodeController, utils } = require('lowcode-controller') +``` + +## Koa routes + +Controller methods are bound to their instance and can be passed directly to a +router. + +```js const router = require('koa-router')() const Cat = require('./controller/cats') -router.get('/public/cats/hello', Cat.sayHello) router.get('/api/cats', Cat.pageQuery) -router.post('/api/cats', Cat.create) router.get('/api/cats/list', Cat.getList) router.get('/api/cats/:id', Cat.getSingle) +router.post('/api/cats', Cat.create) router.put('/api/cats', Cat.update) router.put('/api/cats/:id', Cat.update) router.delete('/api/cats/:id', Cat.delete) - -module.exports = router ``` -```javascript -//app.js -const Koa = require('koa') -const bodyParser = require('koa-bodyparser') -const router = require('./router') +## Global configuration -const app = new Koa() +### `setGlobalDBPath(dbPath)` -app.use(async (ctx, next) => { - ctx.username = 'admin' - await next() -}) -//lowcode-controller need ctx.query and ctx.request.body -app.use(bodyParser()) +Loads the module exporting the default Sequelize instance. Call it before +constructing a controller. -//you can choose the routing module you like -app.use(router.routes()).use(router.allowedMethods()) - -const server = app.listen(3000, function () { - console.log('server is listen on 3000') -}) -``` +### `setUserNameField(field)` +Sets the context path used for creator and updater audit values. Nested paths +such as `state.user.name` are supported. +### `setCustomResField(code, message, data)` -## 方法 - -### 构造函数 +Changes the keys used by generated responses. The default response shape is: -| 参数名 | 二级参数 | 说明 | -| ------------ | ------------ | ----------------------- | -| model | | 数据库model | -| config | 参考二级参数 | 各个方法的配置 | -| | pageQuery | | -| | create | | -| | update | | -| | getSingle | | -| | getList | | -| | delete | | -| db | | mysql sequelize实例 | -| extraOptions | 参考二级参数 | | -| | creatorField | String 创建人字段 | -| | updatorField | String 创建人字段 | -| | defaultQuery | Object 默认查询条件 | -| | updateDelete | Object 逻辑删除更新字段 | - -### 静态方法 - -#### setGlobalDBPath - -| 参数名 | 说明 | -| ------ | ------------------------------ | -| dbPath | 设置全局db sequelize实例的路径 | - -#### setUserNameField - -| 参数名 | 说明 | -| ------ | -------------------------------------------------- | -| field | 设置从ctx里取出的用户唯一表示字段,支持xxx.xxx形式 | - -#### setCustomResField - -| 参数名 | 说明 | -| ------ | ----------------- | -| code | code对应的字段key | -| msg | msg对应的字段key | -| data | data对应的字段key | - -### 实例方法 - -所有路由类实例方法参数都是ctx - -#### pageQuery - -对应到构造函数中的config.pageQuery,配置项说明如下 - -| 参数名 | 类型 | 说明 | -| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| query | Object | 查询条件,具体字段见后面的说明 | -| beforeQueryHook | function\|async function(query, extraOptions, ctx) | 在执行数据库查询之前执行,函数里return将会阻断后续执行 | -| afterQueryHook | function\|async function(sourceResults, query, extraOptions, ctx) | 在执行数据库查询之后执行,函数里return的值将会作为最后的接口data的返回结果 sourceResults是从数据库查出来的数据 | -| filter | function | 查询数据库后,将结果放到filter函数执行过滤操作 | -| extraOptions | Object | 额外设置,会透传给sequelize执行 | - -#### create - -| 参数名 | 类型 | 说明 | -| ---------------- | ------------------------------------------------------ | ------------------------------------------------------------ | -| validate | Object | 参数验证配置 | -| beforeInsertHook | function\|async function(createItem, ctx) | 在执行数据库插入之前执行,createItem为插入数据库的实体对象 | -| afterInsertHook | function\|async function(insertItem, transaction, ctx) | 在执行数据库插入之后执行,insertItem为插入数据库的实体对象, transaction是sequelize事务标志 | -| constantCreate | Object | 用该对象的字段覆盖插入的字段值 | -| extraOptions | Object | 额外设置,会透传给sequelize执行 | -| pickCreate | Object | 举例{age: 'newAge'} 从createItem中的newAge值覆盖到createItem中的age字段上 | -| enbaleBatch | Boolean | 默认false,开启后,支持传数组,进行批量插入 | - -#### update - -| 参数名 | 类型 | 说明 | -| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| query | Object | 查询条件,具体字段见后面的说明 | -| beforeUpdateHook | function\|async function(updateItem, item, ctx) | 在执行数据库更新之前执行,updateItem为传参的更新内容,item为数据库查询的更新内容 | -| afterUpdateHook | function\|async function(updateItem, item, raw, transaction, ctx) | 在执行数据库更新之后执行,updateItem为传参的更新内容,item为数据库查询的更新内容,raw为数据库update返回值,t为事务标志 | -| filter | function | 查询数据库后,将结果放到filter函数执行过滤操作 | -| extraOptions | Object | 额外设置,会透传给sequelize执行 | -| validate | Object | 参数验证配置 | -| itemBlock | Object | 配置更新对象的字段,不符合预期直接返回错误,比如{age: { value: 12, message: 'wrong age' }} | -| pick | Array | 从传参里提取哪些字段进行更新 | - -#### getSingle - -| 参数名 | 类型 | 说明 | -| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| query | Object | 查询条件,具体字段见后面的说明 | -| beforeQueryHook | function\|async function(query, extraOptions, ctx) | 在执行数据库查询之前执行,函数里return将会阻断后续执行 | -| afterQueryHook | function\|async function(sourceResults, query, extraOptions, ctx) | 在执行数据库查询之后执行,函数里return的值将会作为最后的接口data的返回结果 sourceResults是从数据库查出来的数据 | -| filter | function | 查询数据库后,将结果放到filter函数执行过滤操作 | -| extraOptions | Object | 额外设置,会透传给sequelize执行 | - -#### getList - -| 参数名 | 类型 | 说明 | -| --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| query | Object | 查询条件,具体字段见后面的说明 | -| beforeQueryHook | function\|async function( query, extraOptions, ctx) | 在执行数据库查询之前执行,函数里return将会阻断后续执行 | -| afterQueryHook | function\|async function(sourceResults, query, extraOptions, ctx) | 在执行数据库查询之后执行,函数里return的值将会作为最后的接口data的返回结果 sourceResults是从数据库查出来的数据 | -| filter | function | 查询数据库后,将结果放到filter函数执行过滤操作 | -| extraOptions | Object | 额外设置,会透传给sequelize执行 | - -#### delete - -| 参数名 | 类型 | 说明 | -| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------ | -| query | Object | 查询条件,具体字段见后面的说明 | -| beforeDeleteHook | function\|async function(query, extraOptions, ctx) | 在执行数据库查询之前执行,函数里return将会阻断后续执行 | -| afterDeleteHook | function\|async function(query, extraOptions, transaction, ctx) | 在执行数据库查询之后执行,t为事务标志 | -| extraOptions | Object | 额外设置,会透传给sequelize执行 | -| physicDelete | Boolean | 是否进行物理删除,true是,false否,默认false | - -#### query #### - -````javascript +```json { - //比如请求传过来的cat_name为haha,就模糊查询数据库里cat_name为haha的内容 - 'cat_name': { //查询字段名cat_name - 'like': true, //是否模糊查询 - 'value': 'cat_name', //从请求参数里取cat_name字段作为查询条件值 - 'require': true //请求参数里的cat_name字段必须有值 - }, - //查询数据库中age为2的内容 - 'age': { - 'type': 'constant', //查询的value为一个常量 - 'value': 2 //常量值为2 - }, - //查询数据库字段cat_job里包含了请求传过来的job的内容 - 'cat_job': { //数据库字段为cat_job - 'value': 'job', //从请求参数里取job字段作为查询条件值 - 'json': true //数据库cat_job是一个json类型,启用JSON_CONTAINS进行查询 - }, - //查询数据库字段creator的值为ctx里的username的内容 - 'creator': { - 'type': 'constant', - 'ctxField': 'username' - }, - //查询数据库字段birthday,大于等于请求参数里的startTime,小于等于endTime的字段 - 'birthday': { - 'type': 'varTime', //时间字段查询 - 'value': ['startTime', 'endTime'] //从请求参数里取数组第一个字段为开始时间值,第二个为结束时间值 - } - //以上条件没加特殊操作符,默认都是and - - //以下查询条件都是or - '$or': { - //从请求参数里取为color的字段比如['black', 'white'],然后查询数据库字段color为这两种颜色之一的内容 - 'color': { - 'type': 'varArray', //表面查询条件是一个数组 - 'value': 'color' - }, - //查询数据库字段height不等于30的内容 - 'height': { - 'type': 'constant',//查询的value为一个常量 - 'operator': '$ne', - 'value': 30 //常量值不等于30 + "errno": 0, + "errmsg": "success", + "data": null +} +``` + +## Constructor + +```ts +new LowCodeController(model, config, db, options) +``` + +| Parameter | Description | +| ---------------------- | -------------------------------------------------------------------- | +| `model` | Sequelize model used by generated handlers | +| `config` | Per-handler configuration described below | +| `db` | Optional Sequelize instance; the global instance is the default | +| `options.creatorField` | Model field populated from the username path on create | +| `options.updatorField` | Model field populated on create, update, and soft delete | +| `options.defaultQuery` | Conditions merged into normal queries; default: `{ delete_flag: 1 }` | +| `options.updateDelete` | Values written during soft delete; default: `{ delete_flag: 0 }` | + +## Query DSL + +Each key is a model field. `value` normally identifies the request field from +which the condition is read. + +```ts +const query = { + cat_name: { + value: 'cat_name', + like: true, + require: true, + }, + age: { + type: 'constant', + value: 2, + }, + creator: { + type: 'constant', + ctxField: 'username', + }, + color: { + type: 'varArray', + value: 'colors', }, - //查询数据库字段weight为50或者100的内容 - 'weight': { - 'type': 'constant', - 'operator': '$in', - 'value': [50, 100] + birthday: { + type: 'varTime', + value: ['startTime', 'endTime'], + }, + tags: { + value: 'tag', + json: true, + }, + $or: { + status: { + type: 'constant', + operator: '$in', + value: ['ready', 'done'], + }, + height: { + type: 'constant', + operator: '$ne', + value: 30, + }, }, - //查询数据库字段birthday小于等于2000-10-11的内容 - 'birthday': { - 'type': 'constant', - 'operator': '$time', //时间字段查询 - 'value': [null, '2000-10-11'] //数组第一项为空无开始时间,第二项作为结束时间 - } - } - //以上条件总的为查询(cat_name、age、cat_job creator birthday) and (or (color height weight birthday)) } -```` +``` + +Supported options are `constant`, `varArray`, `varTime`, `$in`, `$ne`, +`$time`, `like`, `json`, `parseNumber`, `ctxField`, and `require`. + +## Handler configuration + +### `pageQuery` + +Reads `size` and `page` from `ctx.query`. The offset is `size * page`, so page +numbering starts at zero. Response data is `{ list, total }`. + +- `query`: query DSL configuration. +- `extraOptions`: merged into Sequelize `findAndCountAll` options. +- `filter`: synchronous mapper applied to each row. +- `beforeQueryHook(query, extraOptions, ctx)`: a truthy return stops handling. +- `afterQueryHook(results, query, extraOptions, ctx)`: a truthy return becomes + response data. + +### `getList` and `getSingle` + +`getList` uses the same query hooks and calls `findAll`. `getSingle` uses the +route `id` when present, otherwise it builds a query and calls `findOne`. + +### `create` + +- `validate`: Validator.js rules in `{ field: { name, rule } }` form. +- `constantCreate`: values assigned over request values. +- `pickCreate`: maps destination fields to source request fields. +- `enableBatch`: uses `bulkCreate` when the body is an array. +- `extraOptions`: passed to Sequelize. +- `beforeInsertHook(createItem, ctx)`: a truthy return stops handling. +- `afterInsertHook(insertItem, transaction, ctx)`: runs in a managed + transaction and must be async. + +### `update` + +An `id` route parameter is used when present. Otherwise the configured query is +built from `ctx.request.body`. + +- `query`, `validate`, `extraOptions`: query, validation, and Sequelize options. +- `pick`: allowlist of fields that may be updated. +- `itemBlock`: requires current model fields to match configured values. +- `beforeUpdateHook(updateItem, item, ctx)`: a truthy return stops handling. +- `afterUpdateHook(updateItem, item, raw, transaction, ctx)`: runs in a managed + transaction and must be async. + +### `delete` + +Deletion is soft by default. `physicDelete: true` uses Sequelize `destroy`. +The handler supports `query`, `extraOptions`, `beforeDeleteHook`, and an async +transactional `afterDeleteHook`. + +## Utilities + +```ts +import { utils } from 'lowcode-controller' + +utils.resSuccess(data) +utils.resFail(1, 'message') +utils.timeQuery(['2024-01-01', '2024-12-31']) +utils.validator.validateJson(data, rules) +utils.curdHelper.findByList(model, options) +``` + +## Development and publishing + +```bash +npm install +npm run typecheck +npm test +npm run build +npm pack --dry-run +``` + +`npm publish` runs the verification suite through `prepublishOnly` and rebuilds +`dist` through `prepack`. The existing MySQL-backed example suite is available +with `npm run test:integration` and uses `test/instance/config.js`. + +## License + +ISC diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..b37257e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,3 @@ +export { LowCodeController } from './lowcode_controller' +export * as utils from './utils' +export type * from './types' diff --git a/src/lowcode_controller.ts b/src/lowcode_controller.ts new file mode 100644 index 0000000..cd3d9b9 --- /dev/null +++ b/src/lowcode_controller.ts @@ -0,0 +1,745 @@ +import _ from 'lodash' +import { Sequelize, Op } from 'sequelize' + +import type { + AnyRecord, + ControllerContext, + ControllerModel, + LowCodeControllerConfig, + LowCodeControllerOptions, + QueryFieldConfig, + SequelizeInstance, + ValidationRules, +} from './types' +import { + curdHelper, + errCatch, + isAsyncOrPromise, + resFail, + resSuccess, + setCustomResField, + smartFuncExecute, + timeQuery, + validator, +} from './utils' + +const { fn, col } = Sequelize +let globalSequelize: SequelizeInstance | undefined +let usernameField: string | undefined + +/** + * Builds Koa-compatible CRUD handlers from a declarative configuration. + * Methods are bound in the constructor so instances can be passed directly to routers. + */ +export class LowCodeController { + public readonly model: ControllerModel + public readonly config: LowCodeControllerConfig + public readonly sq: SequelizeInstance + public creatorField?: string + public updatorField?: string + public defaultQuery: AnyRecord + public updateDelete: AnyRecord + + public constructor( + model: ControllerModel, + config: LowCodeControllerConfig = {}, + db?: SequelizeInstance | null, + extraOptions: LowCodeControllerOptions = {} + ) { + // Retain the historical requirement that global DB setup happens first. + if (!globalSequelize) { + throw new Error( + 'no mysql db instance, you should invoke setGlobalDBPath first' + ) + } + this.model = model + this.config = config + this.sq = db || globalSequelize + const { creatorField, updatorField, defaultQuery, updateDelete } = + extraOptions + if (creatorField) this.creatorField = creatorField + if (updatorField) this.updatorField = updatorField + this.defaultQuery = defaultQuery || { delete_flag: 1 } + this.updateDelete = updateDelete || { delete_flag: 0 } + + this.pageQuery = this.pageQuery.bind(this) + this.getList = this.getList.bind(this) + this.getSingle = this.getSingle.bind(this) + this.create = this.create.bind(this) + this.update = this.update.bind(this) + this.delete = this.delete.bind(this) + } + + public static setCustomResField( + codeFieldKey = 'errno', + msgFieldKey = 'errmsg', + dataFieldKey = 'data' + ): void { + setCustomResField(codeFieldKey, msgFieldKey, dataFieldKey) + } + + public static setGlobalDBPath(dbPath: string): void { + // eslint-disable-next-line @typescript-eslint/no-require-imports + globalSequelize = require(dbPath) as SequelizeInstance + } + + public static setUserNameField(field: string): void { + usernameField = field + } + + /** Convert the public JSON query DSL into a Sequelize where object. */ + public static getQuery( + config: LowCodeControllerConfig, + field: keyof LowCodeControllerConfig, + sourceBody: AnyRecord, + where: AnyRecord = {}, + ctx?: ControllerContext + ): AnyRecord { + const actionConfig = config[field] as { query?: AnyRecord } | undefined + const query = actionConfig?.query + if (!query) return where + + for (const key of Object.keys(query)) { + const queryField = query[key] + if (key === '$time') { + const queryTime = queryField as Record< + string, + readonly [string, string] + > + for (const modelField of Object.keys(queryTime)) { + const fields = queryTime[modelField] + if (!fields) continue + const start = sourceBody[fields[0]] + const end = sourceBody[fields[1]] + if (start || end) where[modelField] = {} + if (start) where[modelField][Op.gte] = start + if (end) where[modelField][Op.lte] = end + } + } else if (key === '$or') { + where[Op.or] = [] + for (const modelField of Object.keys(queryField)) { + LowCodeController.setFieldQuery( + queryField[modelField], + modelField, + where[Op.or], + sourceBody, + key, + ctx + ) + } + } else { + LowCodeController.setFieldQuery( + queryField, + key, + where, + sourceBody, + undefined, + ctx + ) + } + } + return where + } + + public static setFieldQuery( + field: QueryFieldConfig, + modelField: string, + where: AnyRecord | AnyRecord[], + sourceBody: AnyRecord, + parentField?: string, + ctx?: ControllerContext + ): AnyRecord | AnyRecord[] { + if (!field) return where + let { type, value } = field + switch (type) { + case 'constant': { + const { ctxField, operator } = field + if (ctxField) value = _.get(ctx, ctxField) + if (operator === '$in') { + LowCodeController.assignQueryValue( + where, + modelField, + { [Op.in]: value }, + parentField + ) + } else if (operator === '$ne') { + LowCodeController.assignQueryValue( + where, + modelField, + { [Op.ne]: value }, + parentField + ) + } else if (operator === '$time') { + const query = timeQuery(value) + LowCodeController.assignQueryValue( + where, + modelField, + query, + parentField + ) + } else { + LowCodeController.queryFieldDeal( + field, + where, + modelField, + value, + parentField + ) + } + break + } + case 'varArray': { + const sourceValue = sourceBody[value] + if (sourceValue) { + LowCodeController.assignQueryValue( + where, + modelField, + { [Op.in]: sourceValue }, + parentField + ) + } + break + } + case 'varTime': { + const query = timeQuery(value, sourceBody) + if (query) { + LowCodeController.assignQueryValue( + where, + modelField, + query, + parentField + ) + } + break + } + default: { + const sourceValue = sourceBody[value] + if (sourceValue) { + LowCodeController.queryFieldDeal( + field, + where, + modelField, + sourceValue, + parentField + ) + } else if (field.require) { + throw new Error(`${value}必填`) + } + break + } + } + return where + } + + private static assignQueryValue( + where: AnyRecord | AnyRecord[], + modelField: string, + value: any, + parentField?: string + ): void { + if (parentField === '$or') { + ;(where as AnyRecord[]).push({ [modelField]: value }) + } else { + ;(where as AnyRecord)[modelField] = value + } + } + + private static queryFieldDeal( + field: QueryFieldConfig, + where: AnyRecord | AnyRecord[], + modelField: string, + value: any, + parentField?: string + ): void { + const { like, json, parseNumber } = field + if (parentField === '$or') { + const target = where as AnyRecord[] + if (like) { + target.push({ [modelField]: { [Op.like]: `%${value}%` } }) + } else if (parseNumber) { + target.push({ [modelField]: Number(value) }) + } else if (json) { + target.push( + fn('JSON_CONTAINS', col(modelField), `\"${value}\"`) + ) + } else { + target.push({ [modelField]: value }) + } + } else { + const target = where as AnyRecord + if (like) { + target[modelField] = { [Op.like]: `%${value}%` } + } else if (parseNumber) { + target[modelField] = Number(value) + } else if (json) { + target[Op.and] = [ + fn('JSON_CONTAINS', col(modelField), `\"${value}\"`), + ] + } else { + target[modelField] = value + } + } + } + + public pickFiledFromConfig(path?: string): T | null { + return path ? (_.get(this.config, path) as T) : null + } + + public validateHelp( + source: AnyRecord | AnyRecord[], + rules: ValidationRules | null = null + ): validator.ValidationResult | null { + if (!rules) return null + if (_.isArray(source)) { + for (const item of source) { + const result = validator.validateJson(item, rules) + if (!result.success) return result + } + } else { + const result = validator.validateJson(source, rules) + if (!result.success) return result + } + return null + } + + public async pageQuery(ctx: ControllerContext): Promise { + const beforeQueryHook = this.pickFiledFromConfig( + 'pageQuery.beforeQueryHook' + ) + const afterQueryHook = this.pickFiledFromConfig( + 'pageQuery.afterQueryHook' + ) + const extraOptions = this.pickFiledFromConfig('pageQuery.extraOptions') + const filter = this.pickFiledFromConfig('pageQuery.filter') + const { size, page } = ctx.query + const where = LowCodeController.getQuery( + this.config, + 'pageQuery', + ctx.query, + {}, + ctx + ) + const query = { + size, + page, + query: Object.assign(_.cloneDeep(this.defaultQuery), where), + } + + if (beforeQueryHook) { + const needReturn = await smartFuncExecute.call( + this, + beforeQueryHook, + query, + extraOptions, + ctx + ) + if (needReturn) return null + } + if (afterQueryHook) { + const sourceResults = await curdHelper.findByPage(this.model, { + pageQuery: query, + extraOptions, + filter, + }) + const results = await smartFuncExecute.call( + this, + afterQueryHook, + sourceResults, + query, + extraOptions, + ctx + ) + ctx.body = resSuccess(results || sourceResults) + } else { + await curdHelper.findByPage(this.model, { + pageQuery: query, + extraOptions, + filter, + ctx, + }) + } + } + + public async create(ctx: ControllerContext): Promise { + const { body } = ctx.request + const validateResult = this.validateHelp( + body, + this.pickFiledFromConfig('create.validate') + ) + if (validateResult && !validateResult.success) { + ctx.body = resFail(1, validateResult.message) + return + } + const constantCreate = this.pickFiledFromConfig('create.constantCreate') + const pickCreate = this.pickFiledFromConfig('create.pickCreate') + const enableBatch = this.pickFiledFromConfig('create.enableBatch') + const beforeInsertHook = this.pickFiledFromConfig( + 'create.beforeInsertHook' + ) + const afterInsertHook = this.pickFiledFromConfig( + 'create.afterInsertHook' + ) + const extraOptions = this.pickFiledFromConfig('create.extraOptions') + let createItem = _.cloneDeep(body) + + if (usernameField) { + if (this.creatorField) { + createItem[this.creatorField] = _.get(ctx, usernameField) + } + if (this.updatorField) { + createItem[this.updatorField] = _.get(ctx, usernameField) + } + } + if (constantCreate) { + createItem = Object.assign(createItem, constantCreate) + } + if (pickCreate) { + for (const key of Object.keys(pickCreate)) { + createItem[key] = createItem[pickCreate[key]] + } + } + if (beforeInsertHook) { + const needReturn = await smartFuncExecute.call( + this, + beforeInsertHook, + createItem, + ctx + ) + if (needReturn) return null + } + + let sourceResult: any = null + if (afterInsertHook) { + isAsyncOrPromise(afterInsertHook) + await this.sq + .transaction(transaction => + curdHelper + .create(this.model, { + saveObj: createItem, + transaction, + extraOptions, + enableBatch, + }) + .then(insertItem => { + sourceResult = insertItem + return afterInsertHook.call( + this, + insertItem, + transaction, + ctx + ) + }) + ) + .then((result: any = null) => { + ctx.body = resSuccess(result || sourceResult) + }) + .catch(errCatch(ctx)) + } else { + await curdHelper.create(this.model, { + saveObj: createItem, + ctx, + extraOptions, + enableBatch, + }) + } + } + + public async update(ctx: ControllerContext): Promise { + const id = ctx.params.id + const { body } = ctx.request + let query: AnyRecord | null = null + let updateItem = _.cloneDeep(body) + const queryConfig = this.pickFiledFromConfig('update.query') + const validate = this.pickFiledFromConfig('update.validate') + const itemBlock = this.pickFiledFromConfig('update.itemBlock') + const pick = this.pickFiledFromConfig('update.pick') + const beforeUpdateHook = this.pickFiledFromConfig( + 'update.beforeUpdateHook' + ) + const afterUpdateHook = this.pickFiledFromConfig( + 'update.afterUpdateHook' + ) + const extraOptions = this.pickFiledFromConfig('update.extraOptions') + + if (id) { + query = Object.assign({ id }, this.defaultQuery) + } else if (queryConfig) { + query = LowCodeController.getQuery( + this.config, + 'update', + body, + { ...this.defaultQuery }, + ctx + ) + } + const item = await curdHelper.getSingle(this.model, { query }) + if (!item) { + ctx.body = resFail(1, 'The item is not exists') + return + } + if (!query) { + ctx.body = resFail(1, 'Updates without query are prohibited') + return + } + if (validate) { + const validateResult = this.validateHelp(updateItem, validate) + if (validateResult && !validateResult.success) { + ctx.body = resFail(1, validateResult.message) + return + } + } + if (itemBlock) { + for (const key of Object.keys(itemBlock)) { + if (item[key] !== itemBlock[key].value) { + ctx.body = resFail(1, itemBlock[key].message) + return + } + } + } + if (pick && _.isArray(pick)) updateItem = _.pick(updateItem, pick) + if (usernameField && this.updatorField) { + updateItem[this.updatorField] = _.get(ctx, usernameField) + } + if (beforeUpdateHook) { + const needReturn = await smartFuncExecute.call( + this, + beforeUpdateHook, + updateItem, + item, + ctx + ) + if (needReturn) return null + } + + if (afterUpdateHook) { + isAsyncOrPromise(afterUpdateHook) + await this.sq.transaction(transaction => + curdHelper + .update(this.model, { + query, + transaction, + updateObj: updateItem, + extraOptions, + }) + .then(raw => + afterUpdateHook.call( + this, + updateItem, + item, + raw, + transaction, + ctx + ) + ) + .then(result => { + ctx.body = resSuccess(result) + }) + .catch(errCatch(ctx)) + ) + } else { + await curdHelper.update(this.model, { + query, + updateObj: updateItem, + ctx, + extraOptions, + }) + } + } + + public async getSingle(ctx: ControllerContext): Promise { + const id = ctx.params.id + const queryConfig = this.pickFiledFromConfig('getSingle.query') + const beforeQueryHook = this.pickFiledFromConfig( + 'getSingle.beforeQueryHook' + ) + const afterQueryHook = this.pickFiledFromConfig( + 'getSingle.afterQueryHook' + ) + const extraOptions = this.pickFiledFromConfig('getSingle.extraOptions') + let query: AnyRecord = {} + if (id) query.id = id + if (!id && queryConfig) { + query = LowCodeController.getQuery( + this.config, + 'getSingle', + ctx.query, + _.cloneDeep(this.defaultQuery), + ctx + ) + } + if (beforeQueryHook) { + const needReturn = await smartFuncExecute.call( + this, + beforeQueryHook, + query, + extraOptions, + ctx + ) + if (needReturn) return null + } + if (afterQueryHook) { + const sourceResult = await curdHelper.getSingle(this.model, { + query, + extraOptions, + }) + const result = await smartFuncExecute.call( + this, + afterQueryHook, + sourceResult, + query, + extraOptions, + ctx + ) + ctx.body = resSuccess(result || sourceResult) + } else { + await curdHelper.getSingle(this.model, { + query, + ctx, + extraOptions, + }) + } + } + + public async getList(ctx: ControllerContext): Promise { + const query = LowCodeController.getQuery( + this.config, + 'getList', + ctx.query, + _.cloneDeep(this.defaultQuery), + ctx + ) + const beforeQueryHook = this.pickFiledFromConfig( + 'getList.beforeQueryHook' + ) + const afterQueryHook = this.pickFiledFromConfig( + 'getList.afterQueryHook' + ) + const extraOptions = this.pickFiledFromConfig('getList.extraOptions') + const filter = this.pickFiledFromConfig('getList.filter') + if (beforeQueryHook) { + const needReturn = await smartFuncExecute.call( + this, + beforeQueryHook, + query, + extraOptions, + ctx + ) + if (needReturn) return null + } + if (afterQueryHook) { + const sourceResults = await curdHelper.findByList(this.model, { + query, + extraOptions, + filter, + }) + const results = await smartFuncExecute.call( + this, + afterQueryHook, + sourceResults, + query, + extraOptions, + ctx + ) + ctx.body = resSuccess(results || sourceResults) + } else { + await curdHelper.findByList(this.model, { + query, + extraOptions, + filter, + ctx, + }) + } + } + + public async delete(ctx: ControllerContext): Promise { + const id = ctx.params.id + let query: AnyRecord = {} + if (id) query.id = id + const beforeDeleteHook = this.pickFiledFromConfig( + 'delete.beforeDeleteHook' + ) + const afterDeleteHook = this.pickFiledFromConfig( + 'delete.afterDeleteHook' + ) + const extraOptions = this.pickFiledFromConfig('delete.extraOptions') + const physicDelete = this.pickFiledFromConfig('delete.physicDelete') + const queryConfig = this.pickFiledFromConfig('delete.query') + if (queryConfig) { + query = LowCodeController.getQuery( + this.config, + 'delete', + ctx.query, + {}, + ctx + ) + } + if (beforeDeleteHook) { + const needReturn = await smartFuncExecute.call( + this, + beforeDeleteHook, + query, + extraOptions, + ctx + ) + if (needReturn) return null + } + const updateDelete = this.updateDelete + if (usernameField && this.updatorField) { + updateDelete[this.updatorField] = _.get(ctx, usernameField) + } + if (afterDeleteHook) { + isAsyncOrPromise(afterDeleteHook) + return this.sq.transaction(transaction => { + if (physicDelete) { + return curdHelper + .physicDelete(this.model, { + query, + transaction, + extraOptions, + }) + .then(() => + afterDeleteHook.call( + this, + query, + extraOptions, + transaction, + ctx + ) + ) + } + return curdHelper + .delete(this.model, { + query, + transaction, + updateObj: updateDelete, + extraOptions, + }) + .then(raw => + afterDeleteHook.call( + this, + query, + extraOptions, + raw, + transaction, + ctx + ) + ) + }) + } + if (physicDelete) { + return curdHelper.physicDelete(this.model, { + query, + ctx, + extraOptions, + }) + } + return curdHelper.delete(this.model, { + query, + ctx, + extraOptions, + updateObj: updateDelete, + }) + } +} + +export default LowCodeController diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..2b81680 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,184 @@ +import type { + CreateOptions, + DestroyOptions, + FindAndCountOptions, + FindOptions, + Sequelize, + Transaction, + UpdateOptions, + WhereOptions, +} from 'sequelize' + +export type AnyRecord = Record +/** Structural subset of a Sequelize model used by this package. */ +export interface ControllerModel { + findAndCountAll( + options?: AnyRecord + ): Promise<{ rows: any[]; count: number }> + findAll(options?: AnyRecord): Promise + findByPk(identifier: any, options?: AnyRecord): Promise + findOne(options?: AnyRecord): Promise + create(values: AnyRecord, options?: AnyRecord): Promise + bulkCreate(values: AnyRecord[], options?: AnyRecord): Promise + update(values: AnyRecord, options: AnyRecord): Promise + destroy(options: AnyRecord): Promise +} + +/** Minimal Koa-compatible context consumed by the generated handlers. */ +export interface ControllerContext extends AnyRecord { + body?: unknown + params: Record + query: Record + request: { + body: any + [key: string]: any + } + logger?: { + error(error: unknown): void + } +} + +export type MaybePromise = T | Promise +export type Hook = (...args: any[]) => MaybePromise + +export type QueryType = 'constant' | 'varArray' | 'varTime' +export type QueryOperator = '$in' | '$ne' | '$time' + +/** A field in the JSON query DSL. Unknown strings remain accepted for compatibility. */ +export interface QueryFieldConfig { + type?: QueryType | (string & {}) + value?: any + ctxField?: string + operator?: QueryOperator | (string & {}) + like?: boolean + json?: boolean + parseNumber?: boolean + time?: boolean + require?: boolean +} + +export type QueryConfig = Record< + string, + QueryFieldConfig | Record | any +> + +export interface QueryActionConfig { + query?: QueryConfig + beforeQueryHook?: Hook + afterQueryHook?: Hook + filter?: (value: any, index: number, array: any[]) => any + extraOptions?: FindOptions +} + +export interface ValidationRule { + name: string + rule: string | string[] +} + +export type ValidationRules = Record + +export interface CreateActionConfig { + validate?: ValidationRules + beforeInsertHook?: Hook + afterInsertHook?: Hook + constantCreate?: AnyRecord + extraOptions?: CreateOptions + pickCreate?: Record + enableBatch?: boolean +} + +export interface UpdateActionConfig { + query?: QueryConfig + validate?: ValidationRules + itemBlock?: Record + pick?: string[] + beforeUpdateHook?: Hook + afterUpdateHook?: Hook + filter?: Hook + extraOptions?: Partial +} + +export interface DeleteActionConfig { + query?: QueryConfig + beforeDeleteHook?: Hook + afterDeleteHook?: Hook + extraOptions?: Partial | Partial + physicDelete?: boolean +} + +export interface LowCodeControllerConfig { + pageQuery?: QueryActionConfig + getList?: QueryActionConfig + getSingle?: QueryActionConfig + create?: CreateActionConfig + update?: UpdateActionConfig + delete?: DeleteActionConfig + [key: string]: unknown +} + +export interface LowCodeControllerOptions { + creatorField?: string + updatorField?: string + defaultQuery?: AnyRecord + updateDelete?: AnyRecord +} + +export interface PageQuery { + size?: string | number + page?: string | number + query?: WhereOptions +} + +export interface PageResult { + list: T[] + total: number +} + +export interface CrudFindPageOptions { + pageQuery?: PageQuery + extraOptions?: FindAndCountOptions + filter?: (value: any, index: number, array: any[]) => any + ctx?: ControllerContext | null +} + +export interface CrudFindListOptions { + query?: WhereOptions + extraOptions?: FindOptions + transaction?: Transaction + filter?: (value: any, index: number, array: any[]) => any + ctx?: ControllerContext | null +} + +export interface CrudCreateOptions { + saveObj: AnyRecord | AnyRecord[] + ctx?: ControllerContext | null + transaction?: Transaction + extraOptions?: CreateOptions + enableBatch?: boolean +} + +export interface CrudGetSingleOptions { + query?: string | WhereOptions | null + ctx?: ControllerContext | null + transaction?: Transaction + extraOptions?: FindOptions +} + +export interface CrudUpdateOptions { + query?: WhereOptions | null + updateObj?: AnyRecord + ctx?: ControllerContext | null + transaction?: Transaction + extraOptions?: Partial +} + +export interface CrudDeleteOptions extends CrudUpdateOptions {} + +export interface CrudPhysicalDeleteOptions { + query?: WhereOptions | null + ctx?: ControllerContext | null + transaction?: Transaction + extraOptions?: Partial +} + +export type SequelizeInstance = Pick diff --git a/src/utils/common.ts b/src/utils/common.ts new file mode 100644 index 0000000..d008865 --- /dev/null +++ b/src/utils/common.ts @@ -0,0 +1,112 @@ +import _ from 'lodash' +import { Op } from 'sequelize' + +import type { AnyRecord, ControllerContext } from '../types' + +let resField: [string, string, string] = ['errno', 'errmsg', 'data'] + +export const isAsyncFunction = ( + fn: unknown +): fn is (...args: any[]) => Promise => + Object.prototype.toString.call(fn) === '[object AsyncFunction]' + +export const isPromise = (value: unknown): value is PromiseLike => + !!value && + (typeof value === 'object' || typeof value === 'function') && + typeof (value as PromiseLike).then === 'function' + +export const resSuccess = (data?: unknown, message?: string): AnyRecord => ({ + [resField[0]]: 0, + [resField[1]]: message || 'success', + [resField[2]]: data || null, +}) + +export const resFail = ( + code: number, + message?: string, + data?: unknown +): AnyRecord => ({ + [resField[0]]: code, + [resField[1]]: message || 'fail', + [resField[2]]: data || null, +}) + +export const setCustomResField = ( + code = 'errno', + msg = 'errcode', + data = 'errmsg' +): void => { + resField = [code, msg, data] +} + +export async function smartFuncExecute( + this: unknown, + func: (...args: any[]) => T | Promise, + ...args: any[] +): Promise { + return await func.call(this, ...args) +} + +/** Transactional after-hooks must be async so Sequelize can await them. */ +export const isAsyncOrPromise = (fn: unknown): void => { + if (!isAsyncFunction(fn) && !isPromise(fn)) { + throw new Error('afterXXXHook must be one of async function or promise') + } +} + +export const errCatch = + (ctx?: ControllerContext | null) => + (error: any): AnyRecord | undefined => { + if (_.get(ctx, 'logger.error')) { + ctx?.logger?.error(error) + } else { + console.error(error) + } + if (ctx) { + return (ctx.body = resFail(1, error.message, error)) as AnyRecord + } + return undefined + } + +export const batchAsyncFuncExec = async ( + asyncFunc: (item: T) => Promise, + items: T[] = [], + count = 50 +): Promise => { + if (!isAsyncFunction(asyncFunc)) { + throw new Error('asyncFunc is not a validate async function') + } + let promises: Array> = [] + let result: R[] = [] + for (let i = 0; i < items.length; i += 1) { + const item = items[i] as T + promises.push(asyncFunc(item)) + if ((i + 1) % count === 0) { + result = result.concat(await Promise.all(promises)) + promises = [] + } + } + if (promises.length > 0) { + result = result.concat(await Promise.all(promises)) + } + return result +} + +export const timeQuery = ( + value: readonly [any?, any?], + sourceBody?: AnyRecord +): AnyRecord | null => { + const query: AnyRecord = {} + let none = true + const start = sourceBody && value[0] ? sourceBody[value[0]] : value[0] + const end = sourceBody && value[1] ? sourceBody[value[1]] : value[1] + if (start) { + query[Op.gte] = start + none = false + } + if (end) { + query[Op.lte] = end + none = false + } + return none ? null : query +} diff --git a/src/utils/curd_helper.ts b/src/utils/curd_helper.ts new file mode 100644 index 0000000..cd9dfa0 --- /dev/null +++ b/src/utils/curd_helper.ts @@ -0,0 +1,244 @@ +import _ from 'lodash' + +import type { + AnyRecord, + ControllerModel, + CrudCreateOptions, + CrudDeleteOptions, + CrudFindListOptions, + CrudFindPageOptions, + CrudGetSingleOptions, + CrudPhysicalDeleteOptions, + CrudUpdateOptions, + PageResult, +} from '../types' +import { resSuccess } from './common' + +const toPlain = (row: any): AnyRecord => row.get({ plain: true }) + +export const curdHelper = { + async findByPage( + model: ControllerModel, + { + pageQuery = {}, + extraOptions = {}, + filter, + ctx = null, + }: CrudFindPageOptions + ): Promise { + const { size = 10, page = 0, query = {} } = pageQuery + const options = Object.assign( + { + limit: Number(size), + offset: Number(size) * Number(page), + where: query, + raw: true, + }, + extraOptions + ) + const { rows, count } = await model.findAndCountAll(options) + const result: PageResult = { + list: rows as any[], + total: count as number, + } + if (rows.length > 0 && filter) { + result.list = result.list.map(filter) + } + if (!ctx) { + return result + } + ctx.body = resSuccess(result) + return ctx.body as AnyRecord + }, + + async findByList( + model: ControllerModel, + { + query = {}, + extraOptions = {}, + transaction, + filter, + ctx = null, + }: CrudFindListOptions + ): Promise { + const options = Object.assign({ where: query, raw: true }, extraOptions) + if (transaction) { + options.transaction = transaction + return model.findAll(options) + } + let results = await model.findAll(options) + if (results.length > 0 && filter) { + results = results.map(filter) as typeof results + } + if (!ctx) { + return results + } + ctx.body = resSuccess(results) + return ctx.body as AnyRecord + }, + + async create( + model: ControllerModel, + { + saveObj, + ctx = null, + transaction, + extraOptions = {}, + enableBatch = false, + }: CrudCreateOptions + ): Promise { + // Preserve the original helper's option passthrough and transaction behavior. + const options = extraOptions + let result: AnyRecord | AnyRecord[] + if (enableBatch && _.isArray(saveObj)) { + if (transaction) { + options.transaction = transaction + return model.bulkCreate(saveObj, options) + } + result = (await model.bulkCreate(saveObj, options)).map(toPlain) + } else { + if (transaction) { + options.transaction = transaction + return model.create(saveObj as AnyRecord, options) + } + result = toPlain(await model.create(saveObj as AnyRecord, options)) + } + if (!ctx) { + return result + } + ctx.body = resSuccess(result) + return ctx.body + }, + + async getSingle( + model: ControllerModel, + { + query, + ctx = null, + transaction, + extraOptions = {}, + }: CrudGetSingleOptions + ): Promise { + const options = Object.assign({ raw: true }, extraOptions) + if (transaction) { + options.transaction = transaction + } + let result: any + if (typeof query === 'string') { + if (transaction) { + return model.findByPk(query, options) + } + result = await model.findByPk(query, options) + } else { + options.where = query as any + if (transaction) { + return model.findOne(options) + } + result = await model.findOne(options) + } + if (!ctx) { + return result + } + ctx.body = resSuccess(result) + return ctx.body + }, + + async update( + model: ControllerModel, + { + query, + updateObj = {}, + ctx = null, + transaction, + extraOptions = {}, + }: CrudUpdateOptions + ): Promise { + const options = Object.assign({ where: query }, extraOptions) + if (transaction) { + options.transaction = transaction + return model.update(updateObj, options as any) + } + await model.update(updateObj, options as any) + if (!ctx) { + return true + } + ctx.body = resSuccess() + return ctx.body + }, + + async delete( + model: ControllerModel, + { + query, + ctx = null, + transaction, + extraOptions = {}, + updateObj, + }: CrudDeleteOptions + ): Promise { + const update = updateObj || { delete_flag: 1 } + const options = Object.assign({ where: query }, extraOptions) + if (transaction) { + options.transaction = transaction + return model.update(update, options as any) + } + await model.update(update, options as any) + if (!ctx) { + return true + } + ctx.body = resSuccess() + return ctx.body + }, + + async physicDelete( + model: ControllerModel, + { + query, + ctx = null, + transaction, + extraOptions = {}, + }: CrudPhysicalDeleteOptions + ): Promise { + const options = Object.assign({ where: query }, extraOptions) + if (transaction) { + options.transaction = transaction + return model.destroy(options as any) + } + await model.destroy(options as any) + if (!ctx) { + return true + } + ctx.body = resSuccess() + return ctx.body + }, + + async relateQueryMN( + relateModel: ControllerModel, + relateQuery: AnyRecord, + filterFnc: (item: any) => any, + model: ControllerModel, + modelFields: string, + extraModelOptions: AnyRecord = {}, + extraRelateOptions: AnyRecord = {} + ): Promise<{ results: any; relates: any[] }> { + const relates = (await curdHelper.findByList(relateModel, { + query: relateQuery, + extraOptions: extraRelateOptions, + })) as any[] + const nextQuery = relates.map(filterFnc) + const query: AnyRecord = { + where: { + // The legacy utility intentionally exposes Sequelize's old $in syntax. + [modelFields]: { $in: nextQuery }, + }, + } + const { where, attributes, other } = extraModelOptions + if (where) query.where = Object.assign(query.where, where) + if (attributes) query.attributes = attributes + const results = await curdHelper.findByList(model, { + query, + extraOptions: other, + }) + return { results, relates } + }, +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..de28179 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,3 @@ +export * as validator from './validator' +export { curdHelper } from './curd_helper' +export * from './common' diff --git a/src/utils/validator.ts b/src/utils/validator.ts new file mode 100644 index 0000000..09a3bb9 --- /dev/null +++ b/src/utils/validator.ts @@ -0,0 +1,41 @@ +import Validator from 'validatorjs' + +import type { AnyRecord, ValidationRules } from '../types' + +Validator.useLang('zh') + +export interface ValidationResult { + message: string + success: boolean +} + +export const validateJson = ( + data: AnyRecord, + rules: ValidationRules +): ValidationResult => { + const errorMessages: string[] = [] + const validateRule: Record = {} + const customName: Record = {} + + for (const key of Object.keys(rules)) { + const rule = rules[key] + if (rule) { + validateRule[key] = rule.rule + customName[key] = rule.name + } + } + + const validator = new Validator(data, validateRule) + validator.setAttributeNames(customName) + if (validator.fails()) { + for (const field of Object.keys(validator.errors.all())) { + const message = validator.errors.first(field) + if (message) errorMessages.push(message) + } + } + + return { + success: errorMessages.length === 0, + message: errorMessages.join(''), + } +} diff --git a/test/core.test.js b/test/core.test.js new file mode 100644 index 0000000..6b0286e --- /dev/null +++ b/test/core.test.js @@ -0,0 +1,308 @@ +'use strict' + +const assert = require('node:assert/strict') +const path = require('node:path') +const { Op } = require('sequelize') + +const { LowCodeController, utils } = require('../dist') + +const fakeDbModule = require('./fixtures/fake-db') + +function createModel(overrides = {}) { + return { + async findAndCountAll() { + return { rows: [], count: 0 } + }, + async findAll() { + return [] + }, + async findByPk() { + return null + }, + async findOne() { + return null + }, + async create(value) { + return { get: () => ({ id: 1, ...value }) } + }, + async bulkCreate(values) { + return values.map((value, index) => ({ + get: () => ({ id: index + 1, ...value }), + })) + }, + async update() { + return [1] + }, + async destroy() { + return 1 + }, + ...overrides, + } +} + +function createContext({ body = {}, params = {}, query = {} } = {}) { + return { + username: 'admin', + params, + query, + request: { body }, + } +} + +describe('TypeScript build', function () { + before(function () { + LowCodeController.setGlobalDBPath( + path.join(__dirname, 'fixtures/fake-db.js') + ) + LowCodeController.setUserNameField('username') + }) + + it('exports the controller, utilities, and generated declarations', function () { + assert.equal(typeof LowCodeController, 'function') + assert.equal(typeof utils.curdHelper.findByPage, 'function') + assert.equal(typeof utils.validator.validateJson, 'function') + }) + + it('converts the query DSL into Sequelize conditions', function () { + const where = LowCodeController.getQuery( + { + getList: { + query: { + name: { value: 'keyword', like: true }, + owner: { type: 'constant', ctxField: 'username' }, + birthday: { + type: 'varTime', + value: ['start', 'end'], + }, + $or: { + state: { + type: 'constant', + operator: '$in', + value: ['ready', 'done'], + }, + score: { value: 'score', parseNumber: true }, + }, + }, + }, + }, + 'getList', + { + keyword: 'cat', + start: '2020-01-01', + end: '2020-12-31', + score: '7', + }, + {}, + createContext() + ) + + assert.deepEqual(where.name, { [Op.like]: '%cat%' }) + assert.equal(where.owner, 'admin') + assert.deepEqual(where.birthday, { + [Op.gte]: '2020-01-01', + [Op.lte]: '2020-12-31', + }) + assert.deepEqual(where[Op.or], [ + { state: { [Op.in]: ['ready', 'done'] } }, + { score: 7 }, + ]) + }) + + it('keeps pagination, default queries, filters, and response shape', async function () { + let receivedOptions + const model = createModel({ + async findAndCountAll(options) { + receivedOptions = options + return { rows: [{ id: 1, name: 'milo' }], count: 1 } + }, + }) + const controller = new LowCodeController(model, { + pageQuery: { + query: { name: { value: 'name' } }, + filter: item => ({ ...item, filtered: true }), + }, + }) + const ctx = createContext({ + query: { name: 'milo', size: '5', page: '2' }, + }) + + await controller.pageQuery(ctx) + + assert.equal(receivedOptions.limit, 5) + assert.equal(receivedOptions.offset, 10) + assert.deepEqual(receivedOptions.where, { + delete_flag: 1, + name: 'milo', + }) + assert.deepEqual(ctx.body, { + errno: 0, + errmsg: 'success', + data: { + list: [{ id: 1, name: 'milo', filtered: true }], + total: 1, + }, + }) + }) + + it('supports batch creation and returns plain records', async function () { + const result = await utils.curdHelper.create(createModel(), { + saveObj: [{ name: 'a' }, { name: 'b' }], + enableBatch: true, + }) + + assert.deepEqual(result, [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + ]) + }) + + it('rejects invalid create input before calling the model', async function () { + let createCalled = false + const model = createModel({ + async create() { + createCalled = true + }, + }) + const controller = new LowCodeController(model, { + create: { + validate: { + name: { name: 'name', rule: 'required' }, + }, + }, + }) + const ctx = createContext({ body: {} }) + + await controller.create(ctx) + + assert.equal(createCalled, false) + assert.equal(ctx.body.errno, 1) + assert.match(ctx.body.errmsg, /name/) + }) + + it('applies create configuration and awaits transactional hooks', async function () { + let inserted + let hookTransaction + const model = createModel({ + async create(value, options) { + inserted = { value, options } + return { id: 3, ...value, get: () => ({ id: 3, ...value }) } + }, + }) + const controller = new LowCodeController( + model, + { + create: { + constantCreate: { age: 2 }, + pickCreate: { display_name: 'name' }, + afterInsertHook: async (_item, transaction) => { + hookTransaction = transaction + }, + }, + }, + { transaction: fakeDbModule.run }, + { creatorField: 'creator', updatorField: 'updator' } + ) + const ctx = createContext({ body: { name: 'luna', age: 9 } }) + + await controller.create(ctx) + + assert.deepEqual(inserted.value, { + name: 'luna', + age: 2, + creator: 'admin', + updator: 'admin', + display_name: 'luna', + }) + assert.equal(inserted.options.transaction, fakeDbModule.transaction) + assert.equal(hookTransaction, fakeDbModule.transaction) + assert.equal(ctx.body.errno, 0) + assert.equal(ctx.body.data.id, 3) + }) + + it('keeps soft-delete behavior and updater auditing', async function () { + let updated + const model = createModel({ + async update(value, options) { + updated = { value, options } + return [1] + }, + }) + const controller = new LowCodeController(model, {}, null, { + updatorField: 'updator', + }) + const ctx = createContext({ params: { id: '9' } }) + + await controller.delete(ctx) + + assert.deepEqual(updated, { + value: { delete_flag: 0, updator: 'admin' }, + options: { where: { id: '9' } }, + }) + assert.deepEqual(ctx.body, { + errno: 0, + errmsg: 'success', + data: null, + }) + }) + + it('restricts updates to configured fields', async function () { + let updated + const model = createModel({ + async findOne() { + return { id: 5, job: 'student' } + }, + async update(value, options) { + updated = { value, options } + return [1] + }, + }) + const controller = new LowCodeController( + model, + { update: { pick: ['job'] } }, + null, + { updatorField: 'updator' } + ) + const ctx = createContext({ + params: { id: '5' }, + body: { job: 'worker', admin: true }, + }) + + await controller.update(ctx) + + assert.deepEqual(updated.value, { job: 'worker', updator: 'admin' }) + assert.deepEqual(updated.options.where, { + id: '5', + delete_flag: 1, + }) + assert.equal(ctx.body.errno, 0) + }) + + it('supports physical deletion', async function () { + let destroyed + const model = createModel({ + async destroy(options) { + destroyed = options + return 1 + }, + }) + const controller = new LowCodeController(model, { + delete: { physicDelete: true }, + }) + const ctx = createContext({ params: { id: '12' } }) + + await controller.delete(ctx) + + assert.deepEqual(destroyed, { where: { id: '12' } }) + assert.equal(ctx.body.errno, 0) + }) + + it('supports custom response field names', function () { + LowCodeController.setCustomResField('code', 'message', 'result') + assert.deepEqual(utils.resSuccess('ok'), { + code: 0, + message: 'success', + result: 'ok', + }) + LowCodeController.setCustomResField() + }) +}) diff --git a/test/fixtures/fake-db.js b/test/fixtures/fake-db.js new file mode 100644 index 0000000..e8d38a1 --- /dev/null +++ b/test/fixtures/fake-db.js @@ -0,0 +1,10 @@ +'use strict' + +const transaction = { id: 'test-transaction' } + +module.exports = { + transaction, + async run(callback) { + return callback(transaction) + }, +} diff --git a/test/index.test.js b/test/index.test.js index 8fafe40..c4b82c0 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,9 +1,56 @@ const app = require('./instance/app') -const agent = require('supertest').agent(app) +const http = require('http') +const request = require('supertest') const should = require('should') +const { Op } = require('sequelize') +const Cats = require('./instance/model/cat_model') var catId +var server +var agent +var seedCatName +var createdCatName +var databaseReady = false describe('cats api test', function () { + this.timeout(10000) + + before(async function () { + await Cats.ready + databaseReady = true + seedCatName = `integration_seed_${Date.now()}` + await Cats.create({ + cat_name: seedCatName, + creator: 'integration-test', + upator: 'integration-test', + age: 2, + job: 'student', + birthday: '2000-10-11 00:00:00', + delete_flag: 1, + }) + + server = http.createServer(app) + await new Promise((resolve, reject) => { + server.once('error', reject) + server.listen(0, '127.0.0.1', resolve) + }) + agent = request(server) + }) + + after(async function () { + const names = [seedCatName, createdCatName].filter(Boolean) + if (databaseReady && names.length > 0) { + await Cats.destroy({ + where: { cat_name: { [Op.in]: names } }, + force: true, + }) + } + if (server && server.listening) { + await new Promise((resolve, reject) => { + server.close(error => (error ? reject(error) : resolve())) + }) + } + }) + describe('GET /public/cats/hello', function () { it('should cats say hello', function (done) { agent @@ -22,7 +69,7 @@ describe('cats api test', function () { describe('GET /api/cats', function () { it('should get cats page query', function (done) { agent - .get('/api/cats?cat_name=haha') + .get(`/api/cats?cat_name=${encodeURIComponent(seedCatName)}`) .expect(200) .end(function (err, res) { if (err) return done(err) @@ -36,12 +83,13 @@ describe('cats api test', function () { }) describe('POST /api/cats', function () { it('should add cat', function (done) { + createdCatName = `integration_created_${Date.now()}` agent .post('/api/cats') .send({ - cat_name: `haha_${Date.now()}`, + cat_name: createdCatName, job: 'student', - birthday: '2000-10-11 00:00:00' + birthday: '2000-10-11 00:00:00', }) .expect(200) .end(function (err, res) { diff --git a/test/instance/app.js b/test/instance/app.js index 2c9eaf0..449866c 100644 --- a/test/instance/app.js +++ b/test/instance/app.js @@ -13,8 +13,5 @@ app.use(bodyParser()) app.use(router.routes()).use(router.allowedMethods()) -const server = app.listen(3000, function () { - console.log('server is listen on 3000') -}) - -module.exports = server +// Supertest can drive the callback directly, avoiding a fixed local port. +module.exports = app.callback() diff --git a/test/instance/controller/cats.js b/test/instance/controller/cats.js index 008ca90..968a211 100644 --- a/test/instance/controller/cats.js +++ b/test/instance/controller/cats.js @@ -1,4 +1,4 @@ -const { LowCodeController } = require('../../../index') +const { LowCodeController } = require('../../../') const cats_model = require('../model/cat_model') const path = require('path') diff --git a/test/instance/model/cat_model.js b/test/instance/model/cat_model.js index 29b0ced..45a9b7c 100644 --- a/test/instance/model/cat_model.js +++ b/test/instance/model/cat_model.js @@ -53,13 +53,14 @@ const Cats = sq.define( { name: 'idx_name', method: 'BTREE', - fields: ['name'], + fields: ['cat_name'], }, ], version: true, } ) -// Cats.sync() +// Expose initialization so integration tests do not race the asynchronous sync. +Cats.ready = Cats.sync() module.exports = Cats diff --git a/test/types.test.ts b/test/types.test.ts new file mode 100644 index 0000000..1bdd5fe --- /dev/null +++ b/test/types.test.ts @@ -0,0 +1,25 @@ +import { DataTypes, Sequelize } from 'sequelize' + +import { LowCodeController } from '..' +import type { ControllerContext, LowCodeControllerConfig } from '..' + +const sequelize = new Sequelize('sqlite::memory:', { logging: false }) +const model = sequelize.define('item', { + name: DataTypes.STRING, +}) + +const config: LowCodeControllerConfig = { + getList: { + query: { + name: { value: 'name', like: true }, + }, + }, +} + +declare const ctx: ControllerContext + +LowCodeController.setUserNameField('state.user.name') +const pageHandler: (context: ControllerContext) => Promise = + new LowCodeController(model, config).pageQuery + +void pageHandler(ctx) diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2cc19a5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2019", + "module": "Node16", + "moduleResolution": "Node16", + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "strict": true, + "noImplicitOverride": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["dist", "node_modules", "test"] +}