ee-core 2.6.0-beta.2 → 2.7.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.
- package/config/config.default.js +14 -5
- package/cross/index.js +134 -0
- package/ee/application.js +3 -1
- package/ee/eeApp.js +80 -2
- package/html/cross-failure.html +28 -0
- package/html/failure.html +1 -1
- package/package.json +1 -1
- package/ps/index.js +33 -1
- package/utils/pargv.js +263 -0
package/config/config.default.js
CHANGED
|
@@ -294,11 +294,6 @@ module.exports = appInfo => {
|
|
|
294
294
|
dir: path.join(appInfo.root, 'data'),
|
|
295
295
|
};
|
|
296
296
|
|
|
297
|
-
/**
|
|
298
|
-
* loading页(废弃)
|
|
299
|
-
*/
|
|
300
|
-
config.loadingPage = false;
|
|
301
|
-
|
|
302
297
|
/**
|
|
303
298
|
* addons
|
|
304
299
|
*/
|
|
@@ -317,5 +312,19 @@ module.exports = appInfo => {
|
|
|
317
312
|
rendererExit: true,
|
|
318
313
|
};
|
|
319
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Cross-language service
|
|
317
|
+
* 跨语言服务
|
|
318
|
+
* 例如:执行go的二进制程序
|
|
319
|
+
*/
|
|
320
|
+
config.cross = {};
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* jobs
|
|
324
|
+
*/
|
|
325
|
+
config.jobs = {
|
|
326
|
+
messageLog: true
|
|
327
|
+
};
|
|
328
|
+
|
|
320
329
|
return config;
|
|
321
330
|
};
|
package/cross/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const crossSpawn = require('cross-spawn');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const is = require('is-type-of');
|
|
5
|
+
const Conf = require('../config');
|
|
6
|
+
const UtilsHelper = require('../utils/helper');
|
|
7
|
+
const UtilsIs = require('../utils/is');
|
|
8
|
+
const UtilsPargv = require('../utils/pargv');
|
|
9
|
+
const Ps = require('../ps');
|
|
10
|
+
const Log = require('../log');
|
|
11
|
+
const GetPort = require('../utils/get-port');
|
|
12
|
+
const CoreElectronApp = require('../electron/app');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Cross-language service
|
|
16
|
+
* 跨语言服务
|
|
17
|
+
*/
|
|
18
|
+
const CrossLanguageService = {
|
|
19
|
+
|
|
20
|
+
execProcess: {},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* create
|
|
24
|
+
*/
|
|
25
|
+
async create() {
|
|
26
|
+
if (!Ps.isProd()) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// init dir
|
|
31
|
+
this._initPath();
|
|
32
|
+
|
|
33
|
+
// boot services
|
|
34
|
+
const servicesCfg = Conf.getValue('cross');
|
|
35
|
+
//await UtilsHelper.sleep(5 * 1000);
|
|
36
|
+
|
|
37
|
+
for (let key of Object.keys(servicesCfg)) {
|
|
38
|
+
let cfg = servicesCfg[key];
|
|
39
|
+
if (cfg.enable == true) {
|
|
40
|
+
this.run(cfg)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* run
|
|
47
|
+
*/
|
|
48
|
+
async run(conf = {}) {
|
|
49
|
+
const cmdName = conf.name;
|
|
50
|
+
const cmdPath = this._getCmdPath(cmdName);
|
|
51
|
+
let cmdArgs = is.string(conf.args) ? [conf.args] : conf.args;
|
|
52
|
+
|
|
53
|
+
// 动态生成port
|
|
54
|
+
// if (Ps.isProd() || this.workspaces.length > 0) {
|
|
55
|
+
let confPort = this.getArgs(cmdArgs, 'port');
|
|
56
|
+
if (!confPort) {
|
|
57
|
+
throw new Error(`[ee-core] [cross/run] --port parameter does not exist!`);
|
|
58
|
+
}
|
|
59
|
+
confPort = await GetPort({ port: confPort });
|
|
60
|
+
// 替换port
|
|
61
|
+
cmdArgs = this.replaceValue(cmdArgs, "--port=", confPort)
|
|
62
|
+
|
|
63
|
+
Log.coreLogger.info(`[ee-core] [cross/run] cmd: ${cmdPath}, args: ${cmdArgs}`);
|
|
64
|
+
|
|
65
|
+
// Launch executable program
|
|
66
|
+
const coreProcess = crossSpawn(cmdPath, cmdArgs, { stdio: 'inherit', detached: false });
|
|
67
|
+
coreProcess.on('close', (code, signal) => {
|
|
68
|
+
Log.coreLogger.info(`[ee-core] [cross/run] [pid=${coreProcess.pid}, port=${port}] exited with code: ${code}, signal: ${signal}`);
|
|
69
|
+
if (0 !== code) {
|
|
70
|
+
// 弹错误窗口
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
CoreElectronApp.quit();
|
|
74
|
+
});
|
|
75
|
+
this.execProcess[cmdName] = coreProcess;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
getArgs(argv, key) {
|
|
79
|
+
// parse args
|
|
80
|
+
let value = UtilsPargv(argv);
|
|
81
|
+
if (key) {
|
|
82
|
+
value = value[key];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return value;
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
replaceValue(arr, key, value) {
|
|
89
|
+
arr = arr.map(item => {
|
|
90
|
+
if (item.startsWith(key)) {
|
|
91
|
+
let newItem = key + value;
|
|
92
|
+
return newItem;
|
|
93
|
+
} else {
|
|
94
|
+
return item;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return arr;
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
getUrl(argv) {
|
|
101
|
+
const args = this.getArgs(argv);
|
|
102
|
+
let protocol = 'http://';
|
|
103
|
+
if (args.hasOwnProperty('ssl') && (args.ssl == 'true' || args.ssl == '1')) {
|
|
104
|
+
protocol = 'https://';
|
|
105
|
+
}
|
|
106
|
+
const hostname = args.hostname ? args.hostname : '127.0.0.1';
|
|
107
|
+
const url = protocol + hostname + ":" + args.port;
|
|
108
|
+
|
|
109
|
+
return url;
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
_getCmdPath(name) {
|
|
113
|
+
const coreName = UtilsIs.windows() ? name + ".exe" : name;
|
|
114
|
+
const p = path.join(Ps.getExtraResourcesDir(), coreName);
|
|
115
|
+
return p;
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* init path
|
|
120
|
+
*/
|
|
121
|
+
_initPath() {
|
|
122
|
+
try {
|
|
123
|
+
const pathname = Ps.getUserHomeConfigDir();
|
|
124
|
+
if (!fs.existsSync(pathname)) {
|
|
125
|
+
UtilsHelper.mkdir(pathname, {mode: 0o755});
|
|
126
|
+
}
|
|
127
|
+
} catch (e) {
|
|
128
|
+
Log.coreLogger.error(e);
|
|
129
|
+
throw new Error(`[ee-core] [cross] mkdir ${pathname} failed !`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
module.exports = CrossLanguageService;
|
package/ee/application.js
CHANGED
|
@@ -57,7 +57,7 @@ class Appliaction extends EeApp {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// normalize env
|
|
60
|
-
|
|
60
|
+
env.EE_APP_NAME = options.appName;
|
|
61
61
|
env.EE_HOME = options.homeDir;
|
|
62
62
|
env.EE_BASE_DIR = options.baseDir;
|
|
63
63
|
env.EE_SERVER_ENV = options.env;
|
|
@@ -89,6 +89,8 @@ class Appliaction extends EeApp {
|
|
|
89
89
|
|
|
90
90
|
await this.startSocket();
|
|
91
91
|
|
|
92
|
+
await this.crossService();
|
|
93
|
+
|
|
92
94
|
await this.ready();
|
|
93
95
|
|
|
94
96
|
await this.createElectronApp();
|
package/ee/eeApp.js
CHANGED
|
@@ -16,6 +16,7 @@ const Socket = require('../socket');
|
|
|
16
16
|
const GetPort = require('../utils/get-port');
|
|
17
17
|
const UtilsHelper = require('../utils/helper');
|
|
18
18
|
const HttpClient = require('../httpclient');
|
|
19
|
+
const Cross = require('../cross');
|
|
19
20
|
|
|
20
21
|
class EeApp extends BaseApp {
|
|
21
22
|
constructor(options = {}) {
|
|
@@ -59,6 +60,13 @@ class EeApp extends BaseApp {
|
|
|
59
60
|
Socket.startAll(this);
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
/**
|
|
64
|
+
* 启动跨语言服务
|
|
65
|
+
*/
|
|
66
|
+
async crossService() {
|
|
67
|
+
Cross.create();
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
/**
|
|
63
71
|
* 创建electron应用
|
|
64
72
|
*/
|
|
@@ -105,6 +113,8 @@ class EeApp extends BaseApp {
|
|
|
105
113
|
return;
|
|
106
114
|
}
|
|
107
115
|
|
|
116
|
+
const mainServer = this.config.mainServer;
|
|
117
|
+
|
|
108
118
|
// 开发环境
|
|
109
119
|
if (Ps.isDev()) {
|
|
110
120
|
let modeInfo;
|
|
@@ -137,7 +147,7 @@ class EeApp extends BaseApp {
|
|
|
137
147
|
let count = 0;
|
|
138
148
|
let frontendReady = false;
|
|
139
149
|
const hc = new HttpClient();
|
|
140
|
-
while(!frontendReady && count <
|
|
150
|
+
while(!frontendReady && count < 60){
|
|
141
151
|
await UtilsHelper.sleep(1 * 1000);
|
|
142
152
|
try {
|
|
143
153
|
await hc.request(url, {
|
|
@@ -165,7 +175,13 @@ class EeApp extends BaseApp {
|
|
|
165
175
|
}
|
|
166
176
|
|
|
167
177
|
// 生产环境
|
|
168
|
-
|
|
178
|
+
// cross service takeover web
|
|
179
|
+
if (mainServer.hasOwnProperty('takeover')) {
|
|
180
|
+
await this._crossTakeover(mainServer)
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 主进程
|
|
169
185
|
if (Conf.isFileProtocol(mainServer)) {
|
|
170
186
|
url = path.join(this.config.homeDir, mainServer.indexPath);
|
|
171
187
|
this.loadMainUrl('spa', url, 'file');
|
|
@@ -174,6 +190,55 @@ class EeApp extends BaseApp {
|
|
|
174
190
|
}
|
|
175
191
|
}
|
|
176
192
|
|
|
193
|
+
/**
|
|
194
|
+
* cross service takeover web
|
|
195
|
+
*/
|
|
196
|
+
async _crossTakeover(mainCfg = {}) {
|
|
197
|
+
const crossConfig = this.config.cross;
|
|
198
|
+
|
|
199
|
+
// loading page
|
|
200
|
+
this._loadingPage(mainCfg);
|
|
201
|
+
|
|
202
|
+
// cross service url
|
|
203
|
+
if (!crossConfig.hasOwnProperty(mainCfg.takeover)) {
|
|
204
|
+
Log.coreLogger.error(`[ee-core] Please check cross config !`);
|
|
205
|
+
throw new Error(`[ee-core] Please Check the value of mainServer.takeover in the config file !`);
|
|
206
|
+
}
|
|
207
|
+
const servicesCfg = crossConfig[mainCfg.takeover];
|
|
208
|
+
const url = Cross.getUrl(servicesCfg.args);
|
|
209
|
+
|
|
210
|
+
let count = 0;
|
|
211
|
+
let serviceReady = false;
|
|
212
|
+
const hc = new HttpClient();
|
|
213
|
+
|
|
214
|
+
// 循环检查
|
|
215
|
+
const times = Ps.isDev() ? 20 : 100;
|
|
216
|
+
const sleeptime = Ps.isDev() ? 1000 : 100;
|
|
217
|
+
while(!serviceReady && count < times){
|
|
218
|
+
await UtilsHelper.sleep(sleeptime);
|
|
219
|
+
try {
|
|
220
|
+
await hc.request(url, {
|
|
221
|
+
method: 'GET',
|
|
222
|
+
timeout: 100,
|
|
223
|
+
});
|
|
224
|
+
serviceReady = true;
|
|
225
|
+
} catch(err) {
|
|
226
|
+
//console.log('The cross service is starting');
|
|
227
|
+
}
|
|
228
|
+
count++;
|
|
229
|
+
}
|
|
230
|
+
//console.log('count:', count)
|
|
231
|
+
if (serviceReady == false) {
|
|
232
|
+
const bootFailurePage = path.join(__dirname, '..', 'html', 'cross-failure.html');
|
|
233
|
+
this.mainWindow.loadFile(bootFailurePage);
|
|
234
|
+
Log.coreLogger.error(`[ee-core] Please check cross service [${mainCfg.takeover}] ${url} !`);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
Log.coreLogger.info(`[ee-core] cross service [${mainCfg.takeover}] is started successfully`);
|
|
239
|
+
this.loadMainUrl('spa', url);
|
|
240
|
+
}
|
|
241
|
+
|
|
177
242
|
/**
|
|
178
243
|
* 加载本地前端资源
|
|
179
244
|
*/
|
|
@@ -241,6 +306,19 @@ class EeApp extends BaseApp {
|
|
|
241
306
|
}
|
|
242
307
|
}
|
|
243
308
|
|
|
309
|
+
/**
|
|
310
|
+
* loading page
|
|
311
|
+
*/
|
|
312
|
+
_loadingPage(mainCfg = {}) {
|
|
313
|
+
const p = mainCfg.hasOwnProperty('loadingPage') ? mainCfg.loadingPage : 'unknown';
|
|
314
|
+
const lp = path.join(this.config.homeDir, p);
|
|
315
|
+
if (!fs.existsSync(lp)) {
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
this.mainWindow.loadFile(lp);
|
|
320
|
+
}
|
|
321
|
+
|
|
244
322
|
/**
|
|
245
323
|
* electron app退出
|
|
246
324
|
*/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0" />
|
|
7
|
+
<title>Booting failure</title>
|
|
8
|
+
<style>
|
|
9
|
+
#failure {
|
|
10
|
+
background-color: #dedede;
|
|
11
|
+
font-size: 14px;
|
|
12
|
+
}
|
|
13
|
+
.base {
|
|
14
|
+
position: absolute;
|
|
15
|
+
top: 50%;
|
|
16
|
+
left: 50%;
|
|
17
|
+
transform: translate(-50%, -50%);
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="failure">
|
|
23
|
+
<div class='base'>
|
|
24
|
+
Booting failure, please check cross service is runing !
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
package/html/failure.html
CHANGED
package/package.json
CHANGED
package/ps/index.js
CHANGED
|
@@ -127,6 +127,13 @@ exports.processType = function() {
|
|
|
127
127
|
return type;
|
|
128
128
|
};
|
|
129
129
|
|
|
130
|
+
/**
|
|
131
|
+
* app name
|
|
132
|
+
*/
|
|
133
|
+
exports.appName = function() {
|
|
134
|
+
return process.env.EE_APP_NAME;
|
|
135
|
+
}
|
|
136
|
+
|
|
130
137
|
/**
|
|
131
138
|
* 获取home路径
|
|
132
139
|
*/
|
|
@@ -230,10 +237,35 @@ exports.getExecDir = function() {
|
|
|
230
237
|
/**
|
|
231
238
|
* 获取操作系统用户目录
|
|
232
239
|
*/
|
|
233
|
-
exports.getUserHomeDir = function
|
|
240
|
+
exports.getUserHomeDir = function() {
|
|
234
241
|
return process.env.EE_USER_HOME;
|
|
235
242
|
}
|
|
236
243
|
|
|
244
|
+
/**
|
|
245
|
+
* 获取用户目录配置数据目录
|
|
246
|
+
*/
|
|
247
|
+
exports.getUserHomeConfigDir = function() {
|
|
248
|
+
// const filePath = path.join(this.getHomeDir(), 'package.json');
|
|
249
|
+
// if (!fs.existsSync(filePath)) {
|
|
250
|
+
// throw new Error(filePath + ' is not found');
|
|
251
|
+
// }
|
|
252
|
+
// const pkg = JSON.parse(fs.readFileSync(filePath));
|
|
253
|
+
// if (!pkg.name || pkg.name == "") {
|
|
254
|
+
// throw new Error(`name is required from ${filePath}`);
|
|
255
|
+
// }
|
|
256
|
+
const appname = this.appName();
|
|
257
|
+
const cfgDir = path.join(this.getUserHomeDir(), ".config", appname);
|
|
258
|
+
return cfgDir;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 获取基础数据路径
|
|
263
|
+
*/
|
|
264
|
+
exports.getUserHomeAppFilePath = function() {
|
|
265
|
+
const p = path.join(this.getUserHomeConfigDir(), "app.json");
|
|
266
|
+
return p;
|
|
267
|
+
}
|
|
268
|
+
|
|
237
269
|
/**
|
|
238
270
|
* 获取主进程端口
|
|
239
271
|
*/
|
package/utils/pargv.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function hasKey(obj, keys) {
|
|
4
|
+
var o = obj;
|
|
5
|
+
keys.slice(0, -1).forEach(function (key) {
|
|
6
|
+
o = o[key] || {};
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
var key = keys[keys.length - 1];
|
|
10
|
+
return key in o;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function isNumber(x) {
|
|
14
|
+
if (typeof x === 'number') { return true; }
|
|
15
|
+
if ((/^0x[0-9a-f]+$/i).test(x)) { return true; }
|
|
16
|
+
return (/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/).test(x);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isConstructorOrProto(obj, key) {
|
|
20
|
+
return (key === 'constructor' && typeof obj[key] === 'function') || key === '__proto__';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = function (args, opts) {
|
|
24
|
+
if (!opts) { opts = {}; }
|
|
25
|
+
|
|
26
|
+
var flags = {
|
|
27
|
+
bools: {},
|
|
28
|
+
strings: {},
|
|
29
|
+
unknownFn: null,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
if (typeof opts.unknown === 'function') {
|
|
33
|
+
flags.unknownFn = opts.unknown;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (typeof opts.boolean === 'boolean' && opts.boolean) {
|
|
37
|
+
flags.allBools = true;
|
|
38
|
+
} else {
|
|
39
|
+
[].concat(opts.boolean).filter(Boolean).forEach(function (key) {
|
|
40
|
+
flags.bools[key] = true;
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var aliases = {};
|
|
45
|
+
|
|
46
|
+
function aliasIsBoolean(key) {
|
|
47
|
+
return aliases[key].some(function (x) {
|
|
48
|
+
return flags.bools[x];
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Object.keys(opts.alias || {}).forEach(function (key) {
|
|
53
|
+
aliases[key] = [].concat(opts.alias[key]);
|
|
54
|
+
aliases[key].forEach(function (x) {
|
|
55
|
+
aliases[x] = [key].concat(aliases[key].filter(function (y) {
|
|
56
|
+
return x !== y;
|
|
57
|
+
}));
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
[].concat(opts.string).filter(Boolean).forEach(function (key) {
|
|
62
|
+
flags.strings[key] = true;
|
|
63
|
+
if (aliases[key]) {
|
|
64
|
+
[].concat(aliases[key]).forEach(function (k) {
|
|
65
|
+
flags.strings[k] = true;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
var defaults = opts.default || {};
|
|
71
|
+
|
|
72
|
+
var argv = { _: [] };
|
|
73
|
+
|
|
74
|
+
function argDefined(key, arg) {
|
|
75
|
+
return (flags.allBools && (/^--[^=]+$/).test(arg))
|
|
76
|
+
|| flags.strings[key]
|
|
77
|
+
|| flags.bools[key]
|
|
78
|
+
|| aliases[key];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function setKey(obj, keys, value) {
|
|
82
|
+
var o = obj;
|
|
83
|
+
for (var i = 0; i < keys.length - 1; i++) {
|
|
84
|
+
var key = keys[i];
|
|
85
|
+
if (isConstructorOrProto(o, key)) { return; }
|
|
86
|
+
if (o[key] === undefined) { o[key] = {}; }
|
|
87
|
+
if (
|
|
88
|
+
o[key] === Object.prototype
|
|
89
|
+
|| o[key] === Number.prototype
|
|
90
|
+
|| o[key] === String.prototype
|
|
91
|
+
) {
|
|
92
|
+
o[key] = {};
|
|
93
|
+
}
|
|
94
|
+
if (o[key] === Array.prototype) { o[key] = []; }
|
|
95
|
+
o = o[key];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
var lastKey = keys[keys.length - 1];
|
|
99
|
+
if (isConstructorOrProto(o, lastKey)) { return; }
|
|
100
|
+
if (
|
|
101
|
+
o === Object.prototype
|
|
102
|
+
|| o === Number.prototype
|
|
103
|
+
|| o === String.prototype
|
|
104
|
+
) {
|
|
105
|
+
o = {};
|
|
106
|
+
}
|
|
107
|
+
if (o === Array.prototype) { o = []; }
|
|
108
|
+
if (o[lastKey] === undefined || flags.bools[lastKey] || typeof o[lastKey] === 'boolean') {
|
|
109
|
+
o[lastKey] = value;
|
|
110
|
+
} else if (Array.isArray(o[lastKey])) {
|
|
111
|
+
o[lastKey].push(value);
|
|
112
|
+
} else {
|
|
113
|
+
o[lastKey] = [o[lastKey], value];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setArg(key, val, arg) {
|
|
118
|
+
if (arg && flags.unknownFn && !argDefined(key, arg)) {
|
|
119
|
+
if (flags.unknownFn(arg) === false) { return; }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
var value = !flags.strings[key] && isNumber(val)
|
|
123
|
+
? Number(val)
|
|
124
|
+
: val;
|
|
125
|
+
setKey(argv, key.split('.'), value);
|
|
126
|
+
|
|
127
|
+
(aliases[key] || []).forEach(function (x) {
|
|
128
|
+
setKey(argv, x.split('.'), value);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Object.keys(flags.bools).forEach(function (key) {
|
|
133
|
+
setArg(key, defaults[key] === undefined ? false : defaults[key]);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
var notFlags = [];
|
|
137
|
+
|
|
138
|
+
if (args.indexOf('--') !== -1) {
|
|
139
|
+
notFlags = args.slice(args.indexOf('--') + 1);
|
|
140
|
+
args = args.slice(0, args.indexOf('--'));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for (var i = 0; i < args.length; i++) {
|
|
144
|
+
var arg = args[i];
|
|
145
|
+
var key;
|
|
146
|
+
var next;
|
|
147
|
+
|
|
148
|
+
if ((/^--.+=/).test(arg)) {
|
|
149
|
+
// Using [\s\S] instead of . because js doesn't support the
|
|
150
|
+
// 'dotall' regex modifier. See:
|
|
151
|
+
// http://stackoverflow.com/a/1068308/13216
|
|
152
|
+
var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
|
|
153
|
+
key = m[1];
|
|
154
|
+
var value = m[2];
|
|
155
|
+
if (flags.bools[key]) {
|
|
156
|
+
value = value !== 'false';
|
|
157
|
+
}
|
|
158
|
+
setArg(key, value, arg);
|
|
159
|
+
} else if ((/^--no-.+/).test(arg)) {
|
|
160
|
+
key = arg.match(/^--no-(.+)/)[1];
|
|
161
|
+
setArg(key, false, arg);
|
|
162
|
+
} else if ((/^--.+/).test(arg)) {
|
|
163
|
+
key = arg.match(/^--(.+)/)[1];
|
|
164
|
+
next = args[i + 1];
|
|
165
|
+
if (
|
|
166
|
+
next !== undefined
|
|
167
|
+
&& !(/^(-|--)[^-]/).test(next)
|
|
168
|
+
&& !flags.bools[key]
|
|
169
|
+
&& !flags.allBools
|
|
170
|
+
&& (aliases[key] ? !aliasIsBoolean(key) : true)
|
|
171
|
+
) {
|
|
172
|
+
setArg(key, next, arg);
|
|
173
|
+
i += 1;
|
|
174
|
+
} else if ((/^(true|false)$/).test(next)) {
|
|
175
|
+
setArg(key, next === 'true', arg);
|
|
176
|
+
i += 1;
|
|
177
|
+
} else {
|
|
178
|
+
setArg(key, flags.strings[key] ? '' : true, arg);
|
|
179
|
+
}
|
|
180
|
+
} else if ((/^-[^-]+/).test(arg)) {
|
|
181
|
+
var letters = arg.slice(1, -1).split('');
|
|
182
|
+
|
|
183
|
+
var broken = false;
|
|
184
|
+
for (var j = 0; j < letters.length; j++) {
|
|
185
|
+
next = arg.slice(j + 2);
|
|
186
|
+
|
|
187
|
+
if (next === '-') {
|
|
188
|
+
setArg(letters[j], next, arg);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if ((/[A-Za-z]/).test(letters[j]) && next[0] === '=') {
|
|
193
|
+
setArg(letters[j], next.slice(1), arg);
|
|
194
|
+
broken = true;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (
|
|
199
|
+
(/[A-Za-z]/).test(letters[j])
|
|
200
|
+
&& (/-?\d+(\.\d*)?(e-?\d+)?$/).test(next)
|
|
201
|
+
) {
|
|
202
|
+
setArg(letters[j], next, arg);
|
|
203
|
+
broken = true;
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (letters[j + 1] && letters[j + 1].match(/\W/)) {
|
|
208
|
+
setArg(letters[j], arg.slice(j + 2), arg);
|
|
209
|
+
broken = true;
|
|
210
|
+
break;
|
|
211
|
+
} else {
|
|
212
|
+
setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
key = arg.slice(-1)[0];
|
|
217
|
+
if (!broken && key !== '-') {
|
|
218
|
+
if (
|
|
219
|
+
args[i + 1]
|
|
220
|
+
&& !(/^(-|--)[^-]/).test(args[i + 1])
|
|
221
|
+
&& !flags.bools[key]
|
|
222
|
+
&& (aliases[key] ? !aliasIsBoolean(key) : true)
|
|
223
|
+
) {
|
|
224
|
+
setArg(key, args[i + 1], arg);
|
|
225
|
+
i += 1;
|
|
226
|
+
} else if (args[i + 1] && (/^(true|false)$/).test(args[i + 1])) {
|
|
227
|
+
setArg(key, args[i + 1] === 'true', arg);
|
|
228
|
+
i += 1;
|
|
229
|
+
} else {
|
|
230
|
+
setArg(key, flags.strings[key] ? '' : true, arg);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
|
|
235
|
+
argv._.push(flags.strings._ || !isNumber(arg) ? arg : Number(arg));
|
|
236
|
+
}
|
|
237
|
+
if (opts.stopEarly) {
|
|
238
|
+
argv._.push.apply(argv._, args.slice(i + 1));
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
Object.keys(defaults).forEach(function (k) {
|
|
245
|
+
if (!hasKey(argv, k.split('.'))) {
|
|
246
|
+
setKey(argv, k.split('.'), defaults[k]);
|
|
247
|
+
|
|
248
|
+
(aliases[k] || []).forEach(function (x) {
|
|
249
|
+
setKey(argv, x.split('.'), defaults[k]);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
if (opts['--']) {
|
|
255
|
+
argv['--'] = notFlags.slice();
|
|
256
|
+
} else {
|
|
257
|
+
notFlags.forEach(function (k) {
|
|
258
|
+
argv._.push(k);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return argv;
|
|
263
|
+
};
|