ee-core 2.11.1 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/app/application.js +31 -0
  2. package/app/boot.js +81 -0
  3. package/app/dir.js +27 -0
  4. package/app/events.js +56 -0
  5. package/app/index.js +7 -0
  6. package/config/config_loader.js +66 -0
  7. package/config/default_config.js +110 -0
  8. package/config/index.js +21 -83
  9. package/const/channel.js +26 -16
  10. package/const/index.js +0 -4
  11. package/controller/controller_loader.js +78 -0
  12. package/controller/index.js +18 -19
  13. package/core/index.js +6 -5
  14. package/core/{lib/loader → loader}/file_loader.js +39 -156
  15. package/core/utils/index.js +83 -0
  16. package/core/{lib/utils → utils}/timing.js +3 -2
  17. package/cross/cross.js +152 -0
  18. package/cross/index.js +6 -181
  19. package/cross/spawnProcess.js +34 -51
  20. package/electron/app/index.js +38 -54
  21. package/electron/index.js +13 -17
  22. package/electron/window/index.js +260 -65
  23. package/exception/index.js +34 -32
  24. package/html/index.js +7 -10
  25. package/index.js +4 -52
  26. package/jobs/child/app.js +9 -9
  27. package/jobs/child/forkProcess.js +29 -45
  28. package/jobs/child/index.js +13 -10
  29. package/jobs/child-pool/index.js +13 -11
  30. package/jobs/index.js +2 -4
  31. package/loader/index.js +91 -144
  32. package/log/index.js +74 -57
  33. package/log/logger.js +76 -84
  34. package/message/childMessage.js +12 -13
  35. package/message/index.js +7 -16
  36. package/package.json +2 -2
  37. package/ps/index.js +137 -223
  38. package/socket/httpServer.js +46 -43
  39. package/socket/index.js +52 -69
  40. package/socket/ipcServer.js +80 -94
  41. package/socket/socketServer.js +31 -24
  42. package/storage/index.js +5 -37
  43. package/storage/sqliteStorage.js +18 -18
  44. package/utils/extend.js +10 -5
  45. package/utils/helper.js +38 -42
  46. package/utils/index.js +40 -23
  47. package/utils/ip.js +5 -45
  48. package/utils/is.js +107 -141
  49. package/utils/json.js +15 -7
  50. package/utils/pargv.js +5 -1
  51. package/utils/{get-port → port}/index.js +4 -26
  52. package/utils/wrap.js +8 -3
  53. package/addon/index.js +0 -35
  54. package/addon/window/index.js +0 -99
  55. package/bin/tools.js +0 -8
  56. package/config/cache.js +0 -42
  57. package/config/config.default.js +0 -331
  58. package/controller/baseContextClass.js +0 -25
  59. package/core/lib/ee.js +0 -216
  60. package/core/lib/loader/context_loader.js +0 -106
  61. package/core/lib/loader/ee_loader.js +0 -435
  62. package/core/lib/loader/mixin/addon.js +0 -32
  63. package/core/lib/loader/mixin/config.js +0 -130
  64. package/core/lib/loader/mixin/controller.js +0 -125
  65. package/core/lib/loader/mixin/service.js +0 -28
  66. package/core/lib/utils/base_context_class.js +0 -34
  67. package/core/lib/utils/function.js +0 -30
  68. package/core/lib/utils/index.js +0 -133
  69. package/core/lib/utils/sequencify.js +0 -59
  70. package/ee/appLoader.js +0 -48
  71. package/ee/application.js +0 -100
  72. package/ee/baseApp.js +0 -104
  73. package/ee/eeApp.js +0 -409
  74. package/ee/index.js +0 -58
  75. package/electron/window/winState.js +0 -186
  76. package/httpclient/index.js +0 -161
  77. package/jobs/baseJobClass.js +0 -16
  78. package/jobs/renderer/index.js +0 -141
  79. package/jobs/renderer/loadView.js +0 -41
  80. package/jobs/unification.js +0 -64
  81. package/main/index.js +0 -57
  82. package/old-utils/index.js +0 -91
  83. package/services/baseContextClass.js +0 -24
  84. package/services/index.js +0 -41
  85. package/socket/io.js +0 -28
  86. package/storage/jsondb/adapters/Base.js +0 -23
  87. package/storage/jsondb/adapters/FileSync.js +0 -64
  88. package/storage/jsondb/main.js +0 -55
  89. package/storage/jsondbStorage.js +0 -196
  90. package/utils/co.js +0 -237
  91. package/utils/copyto.js +0 -161
  92. package/utils/depd/index.js +0 -538
  93. package/utils/depd/lib/browser/index.js +0 -77
  94. package/utils/get-port/index.d.ts +0 -64
  95. package/utils/time/index.js +0 -20
  96. package/utils/time/ms.js +0 -162
package/socket/index.js CHANGED
@@ -3,80 +3,63 @@
3
3
  const IoServer = require('socket.io');
4
4
  const IoClient = require('socket.io-client');
5
5
  const Koa = require('koa');
6
- const EESocketServer = Symbol('Ee#SocketServer');
7
- const EEIpcServer = Symbol('Ee#IpcServer');
8
- const EEHttpServer = Symbol('Ee#HttpServer');
9
-
10
- const EeSocket = {
11
-
12
- /**
13
- * 提供基础库 - 避免用户重复安装
14
- */
15
- Koa,
16
- IoServer,
17
- IoClient,
18
-
19
- /**
20
- * 启动所有服务
21
- */
22
- startAll(app) {
23
- this._createSocketServer(app);
24
- this._createHttpServer(app);
25
- this._createIpcServer(app);
26
- },
27
-
28
- /**
29
- * 创建SocketServer
30
- */
31
- _createSocketServer(app) {
32
- const SocketServer = require('./socketServer');
33
- this[EESocketServer] = new SocketServer(app);
34
-
35
- return this[EESocketServer];
36
- },
37
-
38
- /**
39
- * 获取 Socket Server
40
- */
41
- getSocketServer() {
42
- return this[EESocketServer] || null;
43
- },
44
-
45
- /**
46
- * 创建 Http Server
47
- */
48
- _createHttpServer(app) {
49
- const HttpServer = require('./httpServer');
50
- this[EEHttpServer] = new HttpServer(app);
51
-
52
- return this[EEHttpServer];
53
- },
6
+ const { SocketServer } = require('./socketServer');
7
+ const { HttpServer } = require('./httpServer');
8
+ const { IpcServer } = require('./ipcServer');
9
+
10
+ const Instance = {
11
+ socketServer: null,
12
+ httpServer: null,
13
+ coreLogger: null,
14
+ };
15
+
16
+ // create SocketServer
17
+ function createSocketServer() {
18
+ Instance.socketServer = new SocketServer();
19
+ return Instance.socketServer;
20
+ }
54
21
 
55
- /**
56
- * 获取 Http Server
57
- */
58
- getHttpServer() {
59
- return this[EEHttpServer] || null;
60
- },
22
+ // socketServer
23
+ function getSocketServer() {
24
+ return Instance.socketServer;
25
+ }
61
26
 
62
- /**
63
- * 创建 IPC Server
64
- */
65
- _createIpcServer(app) {
66
- const IpcServer = require('./ipcServer');
67
- this[EEIpcServer] = new IpcServer(app);
27
+ // create Http Server
28
+ function createHttpServer() {
29
+ Instance.httpServer = new HttpServer();
30
+ return Instance.httpServer;
31
+ }
68
32
 
69
- return this[EEIpcServer];
70
- },
33
+ // httpServer
34
+ function getHttpServer() {
35
+ return Instance.httpServer;
36
+ }
71
37
 
72
- /**
73
- * 获取 IPC Server
74
- */
75
- getIpcServer() {
76
- return this[EEIpcServer] || null;
77
- },
38
+ // create IPC Server
39
+ function createIpcServer() {
40
+ Instance.ipcServer = new IpcServer();
41
+ return Instance.ipcServer;
42
+ }
78
43
 
44
+ // ipcServer
45
+ function getIpcServer() {
46
+ return Instance.ipcServer;
79
47
  }
80
48
 
81
49
 
82
- module.exports = EeSocket;
50
+ // load socket server
51
+ function loadSocket() {
52
+ createSocketServer();
53
+ createHttpServer();
54
+ createIpcServer();
55
+ }
56
+
57
+ module.exports = {
58
+ Koa,
59
+ IoServer,
60
+ IoClient,
61
+ loadSocket,
62
+ getSocketServer,
63
+ getHttpServer,
64
+ getIpcServer
65
+ };
@@ -1,113 +1,99 @@
1
- const debug = require('debug')('ee-core:ipcServer');
1
+ 'use strict';
2
+
3
+ const debug = require('debug')('ee-core:socket:ipcServer');
2
4
  const is = require('is-type-of');
3
5
  const { ipcMain } = require('electron');
4
- const path = require('path');
5
- const fs = require('fs');
6
- const globby = require('globby');
7
- const Utils = require('../core/lib/utils');
8
- const Wrap = require('../utils/wrap');
9
- const Log = require('../log');
6
+ const { coreLogger } = require('../log');
7
+ const { getController } = require('../controller');
8
+ const { EXPORTS } = require('../core/loader/file_loader');
10
9
 
11
10
  class IpcServer {
12
- constructor (app) {
13
- this.app = app;
14
- this.register();
11
+ constructor () {
12
+ this.directory = 'controller';
13
+ this.init();
15
14
  }
16
15
 
17
- register () {
18
- const self = this;
19
- // 遍历方法
20
- const files = Utils.filePatterns();
21
- const directory = path.join(this.app.config.baseDir, 'controller');
22
- const filepaths = globby.sync(files, { cwd: directory });
23
-
24
- for (const filepath of filepaths) {
25
- const fullpath = path.join(directory, filepath);
26
- if (!fs.statSync(fullpath).isFile()) continue;
27
-
28
- const properties = Wrap.getProperties(filepath, {caseStyle: 'lower'});
29
- const pathName = directory.split(/[/\\]/).slice(-1) + '.' + properties.join('.');
30
-
31
- let fileObj = Utils.loadFile(fullpath);
32
- const fns = {};
33
- // 为了统一,仅支持class文件
34
- if (is.class(fileObj) || Utils.isBytecodeClass(fileObj)) {
35
- let proto = fileObj.prototype;
36
- // 不遍历父类的方法
37
- //while (proto !== Object.prototype) {
38
- const keys = Object.getOwnPropertyNames(proto);
39
- for (const key of keys) {
40
- if (key === 'constructor') {
41
- continue;
42
- }
43
- const d = Object.getOwnPropertyDescriptor(proto, key);
44
- if (is.function(d.value) && !fns.hasOwnProperty(key)) {
45
- fns[key] = 1;
46
- }
47
- }
48
- //proto = Object.getPrototypeOf(proto);
49
- //}
16
+ loop(obj, pathname) {
17
+ const keys = Object.keys(obj);
18
+ // debug("[loop] keys: %j", keys);
19
+ for (const key of keys) {
20
+ if (key === 'constructor') {
21
+ continue;
50
22
  }
23
+ let subObj = obj[key];
24
+ let propertyChain = pathname + '.' + key;
25
+ if (subObj && subObj[EXPORTS] === true) {
26
+ this.register(subObj, propertyChain);
27
+ } else if (typeof subObj === 'object') {
28
+ // 如果子对象依然是对象,则递归调用继续判断
29
+ this.loop(subObj, propertyChain);
30
+ }
31
+ }
32
+ }
51
33
 
52
- debug('register class %s fns %j', pathName, fns);
34
+ register(exportObj, propertyChain) {
35
+ const controller = getController();
36
+ const keys = Object.keys(exportObj);
37
+ for (const key of keys) {
38
+ const channel = `${propertyChain}.${key}`;
39
+ debug('[register] channel %s', channel);
53
40
 
54
- for (const key in fns) {
55
- let channel = pathName + '.' + key;
56
- debug('register channel %s', channel);
41
+ // send/on model
42
+ ipcMain.on(channel, async (event, params) => {
43
+ try {
44
+ const fn = this.findFn(controller, channel);
45
+ const result = await fn.call(controller, params, event);
57
46
 
58
- function findFn (app, c) {
59
- try {
60
- // 找函数
61
- const cmd = c;
62
- let fn = null;
63
- if (is.string(cmd)) {
64
- const actions = cmd.split('.');
65
- let obj = app;
66
- actions.forEach(key => {
67
- obj = obj[key];
68
- if (!obj) throw new Error(`class or function '${key}' not exists`);
69
- });
70
- fn = obj;
71
- }
72
- if (!fn) throw new Error('function not exists');
73
-
74
- return fn;
75
- } catch (err) {
76
- Log.coreLogger.error('[ee-core] [socket/IpcServer] throw error:', err);
77
- }
78
- return null;
47
+ event.returnValue = result;
48
+ event.reply(`${channel}`, result);
49
+ } catch(e) {
50
+ coreLogger.error('[ee-core] [socket/IpcServer] send/on throw error:', e);
79
51
  }
52
+ });
80
53
 
81
- // send/on 模型
82
- ipcMain.on(channel, async (event, params) => {
83
- try {
84
- const fn = findFn(self.app, channel);
85
- const result = await fn.call(self.app, params, event);
86
-
87
- event.returnValue = result;
88
- event.reply(`${channel}`, result);
89
- } catch(e) {
90
- Log.coreLogger.error('[ee-core] [socket/IpcServer] send/on throw error:', e);
91
- // event.returnValue = e;
92
- // event.reply(`${channel}`, e);
93
- }
94
- });
54
+ // invoke/handle model
55
+ ipcMain.handle(channel, async (event, params) => {
56
+ try {
57
+ const fn = this.findFn(controller, channel);
58
+ const result = await fn.call(controller, params, event);
95
59
 
96
- // invoke/handle 模型
97
- ipcMain.handle(channel, async (event, params) => {
98
- try {
99
- const fn = findFn(self.app, channel);
100
- const result = await fn.call(self.app, params, event);
101
-
102
- return result;
103
- } catch(e) {
104
- Log.coreLogger.error('[ee-core] [socket/IpcServer] invoke/handle throw error:', e);
105
- return e
106
- }
60
+ return result;
61
+ } catch(e) {
62
+ coreLogger.error('[ee-core] [socket/IpcServer] invoke/handle throw error:', e);
63
+ }
64
+ });
65
+ }
66
+ }
67
+
68
+ findFn (controller, c) {
69
+ try {
70
+ // 找函数
71
+ const cmd = c;
72
+ let fn = null;
73
+ if (is.string(cmd)) {
74
+ const actions = cmd.split('.');
75
+ let obj = { controller };
76
+ actions.forEach(key => {
77
+ obj = obj[key];
78
+ if (!obj) throw new Error(`class or function '${key}' not exists`);
107
79
  });
80
+ fn = obj;
108
81
  }
82
+ if (!fn) throw new Error('function not exists');
83
+
84
+ return fn;
85
+ } catch (err) {
86
+ coreLogger.error('[ee-core] [socket/IpcServer] throw error:', err);
109
87
  }
88
+ return null;
89
+ }
90
+
91
+ init() {
92
+ const controller = getController();
93
+ this.loop(controller, this.directory);
110
94
  }
111
95
  }
112
96
 
113
- module.exports = IpcServer;
97
+ module.exports = {
98
+ IpcServer
99
+ };
@@ -1,52 +1,57 @@
1
1
  'use strict';
2
2
 
3
- const { Server } = require('socket.io');
4
3
  const is = require('is-type-of');
5
- const Log = require('../log');
6
- const Conf = require('../config/cache');
7
- const Ps = require('../ps');
8
- const Channel = require('../const/channel');
4
+ const { Server } = require('socket.io');
5
+ const { coreLogger } = require('../log');
6
+ const { getConfig } = require('../config');
7
+ const { SocketIO } = require('../const/channel');
8
+ const { getController } = require('../controller');
9
+ const { getPort } = require('../utils/port');
9
10
 
10
11
  /**
11
12
  * socket server
12
13
  */
13
14
  class SocketServer {
14
- constructor (app) {
15
- this.app = app;
15
+ constructor () {
16
16
  this.socket = undefined;
17
- const options = Conf.getValue('socketServer');
17
+ this.io = undefined;
18
+ this.config = getConfig().socketServer;
19
+ this.init();
20
+ }
18
21
 
19
- if (options.enable == false) {
22
+ async init() {
23
+ if (this.config.enable == false) {
20
24
  return;
21
25
  }
22
26
 
23
- let port = Ps.getSocketPort();
27
+ const port = await getPort({port: parseInt(this.config.port)});
24
28
  if (!port) {
25
29
  throw new Error('[ee-core] [socket/socketServer] socekt port required, and must be a number !');
26
30
  }
31
+ coreLogger.info('[ee-core] [socket/socketServer] port is:', port);
27
32
 
28
- Log.coreLogger.info('[ee-core] [socket/socketServer] port is:', port);
29
-
30
- this.io = new Server(port, options);
31
- this.connec(options);
33
+ process.env.EE_SOCKET_PORT = port;
34
+ this.config.port = port;
35
+ this.io = new Server(port, this.config);
36
+ this.connect();
32
37
  }
33
38
 
34
- connec (opt = {}) {
35
- const app = this.app;
39
+ connect () {
40
+ const controller = getController();
36
41
  this.io.on('connection', (socket) => {
37
- const channel = opt.channel || Channel.socketIo.partySoftware;
42
+ const channel = this.config.channel || SocketIO.partySoftware;
38
43
  this.socket = socket;
39
44
  socket.on(channel, async (message, callback) => {
40
- Log.coreLogger.info('[ee-core] [socket/socketServer] socket id:' + socket.id + ' message cmd: ' + message.cmd);
45
+ coreLogger.info('[ee-core] [socket/socketServer] socket id:' + socket.id + ' message cmd: ' + message.cmd);
41
46
 
42
47
  try {
43
- // 找函数
48
+ // find function
44
49
  const cmd = message.cmd;
45
- const args = message.args || message.params;
50
+ const args = message.args;
46
51
  let fn = null;
47
52
  if (is.string(cmd)) {
48
53
  const actions = cmd.split('.');
49
- let obj = app;
54
+ let obj = { controller };
50
55
  actions.forEach(key => {
51
56
  obj = obj[key];
52
57
  if (!obj) throw new Error(`class or function '${key}' not exists`);
@@ -55,16 +60,18 @@ class SocketServer {
55
60
  }
56
61
  if (!fn) throw new Error('function not exists');
57
62
 
58
- const result = await fn.call(app, args);
63
+ const result = await fn.call(controller, args);
59
64
  if (callback) {
60
65
  callback(result);
61
66
  }
62
67
  } catch (err) {
63
- Log.coreLogger.error('[ee-core] [socket/socketServer] throw error:', err);
68
+ coreLogger.error('[ee-core] [socket/socketServer] throw error:', err);
64
69
  }
65
70
  });
66
71
  });
67
72
  }
68
73
  }
69
74
 
70
- module.exports = SocketServer;
75
+ module.exports = {
76
+ SocketServer,
77
+ };
package/storage/index.js CHANGED
@@ -1,39 +1,7 @@
1
- const assert = require('assert');
2
- const _ = require('lodash');
3
- const DB = {};
1
+ 'use strict';
4
2
 
5
- // jsondb 要么每次new对象,要么所有地方都用同一个实例,否则会出现数据无法刷新的情况
3
+ const { SqliteStorage } = require('./sqliteStorage');
6
4
 
7
- DB.connection = function (database, options = {}) {
8
- let driver = options.driver || 'jsondb';
9
-
10
- // 兼容之前api
11
- driver = driver == 'lowdb' ? 'jsondb' : driver;
12
-
13
- let opt = options.default || {};
14
- if (!_.includes(['jsondb', 'sqlite'], driver)) {
15
- assert(database, `db driver ${driver} is not supported`);
16
- }
17
- if (_.isEmpty(database)) {
18
- assert(database, `db name ${database} Cannot be empty`);
19
- }
20
- let storage;
21
- switch (driver) {
22
- case 'jsondb':
23
- const JsondbStorage = require('./jsondbStorage');
24
- storage = new JsondbStorage(database);
25
- break;
26
- case 'sqlite':
27
- const SqliteStorage = require('./sqliteStorage');
28
- storage = new SqliteStorage(database, opt);
29
- break;
30
- default:
31
- }
32
-
33
- return storage;
34
- }
35
-
36
- // 兼容之前的api
37
- DB.JsonDB = DB;
38
-
39
- module.exports = DB;
5
+ module.exports = {
6
+ SqliteStorage
7
+ };
@@ -4,8 +4,8 @@ const assert = require('assert');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const Database = require('better-sqlite3');
7
- const Helper = require('../utils/helper');
8
- const Ps = require('../ps');
7
+ const { mkdir } = require('../utils/helper');
8
+ const { getDataDir } = require('../ps');
9
9
 
10
10
  class SqliteStorage {
11
11
  constructor (name, opt = {}) {
@@ -13,7 +13,7 @@ class SqliteStorage {
13
13
 
14
14
  this.name = name;
15
15
  this.mode = this.getMode(name);
16
- this.storageDir = this._createStorageDir();
16
+ this.dbDir = this._createDatabaseDir();
17
17
  this.fileName = this._formatFileName(name);
18
18
  this.db = this._initDB(opt);
19
19
  }
@@ -36,7 +36,7 @@ class SqliteStorage {
36
36
 
37
37
  // 如果是文件类型,判断文件是否创建成功
38
38
  if (this.mode != 'memory') {
39
- assert(fs.existsSync(dbPath), `error: storage ${dbPath} not exists`);
39
+ assert(fs.existsSync(dbPath), `error: db ${dbPath} not exists`);
40
40
  }
41
41
 
42
42
  return db;
@@ -57,19 +57,17 @@ class SqliteStorage {
57
57
  /**
58
58
  * 创建storage目录
59
59
  */
60
- _createStorageDir () {
61
- let storageDir = Ps.getStorageDir();
62
-
60
+ _createDatabaseDir () {
61
+ let dbDir = path.join(getDataDir(), 'db');
63
62
  if (this.mode == 'absolute') {
64
- storageDir = path.dirname(this.name);
63
+ dbDir = path.dirname(this.name);
65
64
  }
66
65
 
67
- if (!fs.existsSync(storageDir)) {
68
- Helper.mkdir(storageDir);
69
- Helper.chmodPath(storageDir, '777');
66
+ if (!fs.existsSync(dbDir)) {
67
+ mkdir(dbDir, { mode: 0o755 });
70
68
  }
71
69
 
72
- return storageDir;
70
+ return dbDir;
73
71
  }
74
72
 
75
73
  /**
@@ -84,7 +82,7 @@ class SqliteStorage {
84
82
  return mode;
85
83
  }
86
84
 
87
- assert(path.extname(name) == '.db', `error: storage ${name} file ext name must be .db`);
85
+ assert(path.extname(name) == '.db', `error: db ${name} file ext name must be .db`);
88
86
 
89
87
  // 路径模式
90
88
  name = name.replace(/[/\\]/g, '/');
@@ -105,20 +103,22 @@ class SqliteStorage {
105
103
  }
106
104
 
107
105
  /**
108
- * 获取storage目录
106
+ * 获取 db 文件目录
109
107
  */
110
- getStorageDir () {
111
- return this.storageDir;
108
+ getDbDir () {
109
+ return this.dbDir;
112
110
  }
113
111
 
114
112
  /**
115
113
  * 获取文件绝对路径
116
114
  */
117
115
  getFilePath () {
118
- const dbFile = path.join(this.storageDir, this.fileName);
116
+ const dbFile = path.join(this.dbDir, this.fileName);
119
117
 
120
118
  return dbFile;
121
119
  }
122
120
  }
123
121
 
124
- module.exports = SqliteStorage;
122
+ module.exports = {
123
+ SqliteStorage
124
+ };
package/utils/extend.js CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var hasOwn = Object.prototype.hasOwnProperty;
4
- var toStr = Object.prototype.toString;
3
+ const hasOwn = Object.prototype.hasOwnProperty;
4
+ const toStr = Object.prototype.toString;
5
5
 
6
- var isPlainObject = function isPlainObject(obj) {
6
+ function isPlainObject(obj) {
7
7
  if (!obj || toStr.call(obj) !== '[object Object]') {
8
8
  return false;
9
9
  }
@@ -23,8 +23,8 @@ var isPlainObject = function isPlainObject(obj) {
23
23
  return typeof key === 'undefined' || hasOwn.call(obj, key);
24
24
  };
25
25
 
26
- module.exports = function extend() {
27
- var options, name, src, copy, copyIsArray, clone;
26
+ function extend() {
27
+ var options, name, src, copy, clone;
28
28
  var target = arguments[0];
29
29
  var i = 1;
30
30
  var length = arguments.length;
@@ -71,3 +71,8 @@ module.exports = function extend() {
71
71
  // Return the modified object
72
72
  return target;
73
73
  };
74
+
75
+ module.exports = {
76
+ extend,
77
+ isPlainObject,
78
+ };