jsir 1.2.8 → 1.3.0

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/cmd/ooa.js CHANGED
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  const {
3
- run, getLibDataDir, trim, regEach, getConfig, mkdir, requireG, reget,
4
- getCbText, e, sleep, objDataFile, setConfig, wrapRows, vl, md5, BigNumber,
5
- info, warn, error, arrayDataFile, infoStr, warnStr, errorStr, errorStack,
6
- getInfo, ei, pad, msg, msgStr
3
+ run, getLibDataDir, trim, regEach, getConfig, mkdir, reget,
4
+ getCbText, e, sleep, objDataFile, setConfig, vl, md5, BigNumber,
5
+ info, warn, error, arrayDataFile, infoStr, warnStr, errorStack,
6
+ getInfo, ei, pad, msgStr, getType, objProfileRows,
7
+ errorTag, isArgsMatch, draftQuery
7
8
  } = require('../util')
9
+ const evalCode = require('../evalCode')
8
10
 
9
11
  const _types = {
10
12
  'e': "exe",
11
13
  'i': "init",
12
14
  'f': "file"
13
15
  }
14
- const _Chokidar = require('chokidar');
16
+ const _chokidar = require('chokidar');
15
17
  const _fs = require('fs')
16
18
  const _libDataDir = getLibDataDir()
17
19
  const _home = _libDataDir + '/ooa'
@@ -19,12 +21,15 @@ const _args = process.argv.slice(2).map(trim)
19
21
  const _history9 = []
20
22
  const _tipsOnRm = {}
21
23
  const _setting = require('../setting')
24
+ const readline = require("readline");
22
25
  const _fileWatcherMap = {}
23
26
 
24
27
  let _cmdMap = {}
25
28
  let _rl
29
+ let _rlHistory = []
26
30
  let _haveWrapperInput = true
27
31
  let _repos = arrayDataFile('repos.json')
32
+ let _exit = false
28
33
 
29
34
  const $data = {}
30
35
 
@@ -38,28 +43,12 @@ try {
38
43
  error(e)
39
44
  }
40
45
 
41
- const _table = require('console.table')
42
- console.table = (...args) => {
43
- console.log(trim(_table.getTable(...args)))
44
- }
45
- console.nable = (rows) => {
46
- console.table(wrapRows(rows))
47
- }
48
-
49
46
  let _noAppendNextLine = true
50
47
 
51
48
  const _mainCmdMap = {
52
49
  repl: {
53
50
  comment: "交互界面",
54
51
  },
55
- ls: {
56
- comment: "模糊搜索脚本",
57
- cmd: ['']
58
- },
59
- run: {
60
- comment: "执行脚本",
61
- cmd: ['']
62
- },
63
52
  add: {
64
53
  comment: "新增脚本",
65
54
  cmd: ['@e ']
@@ -107,6 +96,10 @@ const _mainCmdMap = {
107
96
  lib: {
108
97
  comment: "查看内置资源",
109
98
  cmd: ['*$lib ']
99
+ },
100
+ deps: {
101
+ comment: "查看依赖",
102
+ cmd: ['@^']
110
103
  }
111
104
  }
112
105
 
@@ -126,8 +119,11 @@ function isMainCmd(mainList) {
126
119
  }
127
120
 
128
121
  async function initRuntime() {
129
- global.$lib = {...require('../util'), ...require('../ethWeb'),
130
- evalText
122
+ global.$lib = {...require('../util'), evalText}
123
+ let runtimeScript = 'e RUNTIME.js'
124
+ let runtimePath = getLibDataDir() + '/ooa/' + runtimeScript
125
+ if (_fs.existsSync(runtimePath)) {
126
+ await runCmd('', runtimeScript)
131
127
  }
132
128
  }
133
129
 
@@ -151,7 +147,7 @@ run(async () => {
151
147
  if (isMainCmd(['config'])) {
152
148
  let fileName = 'config.json';
153
149
  let configFile = getLibDataDir() + '/' + fileName;
154
- await e(`"${getFileOpenExe(fileName)}" "${configFile}"`)
150
+ ei('vi', [configFile])
155
151
  return
156
152
  }
157
153
 
@@ -160,25 +156,12 @@ run(async () => {
160
156
  if (isMainCmd(['repl'])) {
161
157
  await initRuntime()
162
158
  _noAppendNextLine = false
163
- nextLine()
164
159
  } else if (isMainCmd()){
165
160
  if (_noAppendNextLine) {
166
161
  _cmdMap = objDataFile('ooaCmdMap.json')
167
162
  }
168
163
 
169
- if (isMainCmd(['run', 'edit', 'rm', 'diff', 'push', 'pull'])
170
- && _args[1] && !/^\d+$/.test(_args[1])) {
171
- let name = toJsirFileName(`e ${_args[1]}`)
172
- let path = _home + '/' + name
173
- if (_fs.existsSync(path)) {
174
- _cmdMap = {
175
- '1': name
176
- }
177
- _args[1] = '1'
178
- }
179
- }
180
-
181
- if (isMainCmd(['run', 'edit', 'rm', 'diff', 'push', 'pull'])
164
+ if (isMainCmd(['edit', 'rm', 'diff', 'push', 'pull', 'deps'])
182
165
  && _args[1] && !/^\d+$/.test(_args[1])) {
183
166
  warn('wrong args')
184
167
  return
@@ -192,23 +175,15 @@ run(async () => {
192
175
  return
193
176
  }
194
177
 
195
- if (isMainCmd(['ls']) && _args[1] && /^\d+$/.test(_args[1])) {
196
- warn('wrong args')
197
- return
198
- }
199
-
200
178
  let argStr = _args.slice(1).map(i => {
201
179
  if (/\s+/.test(i) || !i) {
202
180
  i = `"${i}"`
203
181
  }
204
182
  return i
205
183
  }).join(' ').replace(/^@/, '')
206
- if (isMainCmd(['run', 'edit', 'rm', 'diff', 'push', 'pull']) && !trim(argStr)) {
184
+ if (isMainCmd(['edit', 'rm', 'diff', 'push', 'pull', 'deps']) && !trim(argStr)) {
207
185
  _args[0] = '@'
208
186
  }
209
- if (isMainCmd(['ls']) && !trim(argStr)) {
210
- argStr = ','
211
- }
212
187
  if (isMainCmd(['file'])) {
213
188
  await initRuntime()
214
189
  }
@@ -220,7 +195,7 @@ run(async () => {
220
195
  } else {
221
196
  await wrapperInput(`${_args[0]}${argStr}`)
222
197
  }
223
- } else if (isMainCmd(['help'])) {
198
+ } else if (_args[0] && _args[0].startsWith('--')) {
224
199
  let cols = []
225
200
  for (let key of Object.keys(_mainCmdMap)) {
226
201
  cols.push({
@@ -253,97 +228,104 @@ run(async () => {
253
228
  }
254
229
  })
255
230
 
256
- async function getFileWatcher(fileName, workFile, text) {
257
- info("fileLine open " + workFile)
258
- if (!_fileWatcherMap[workFile]) {
259
- _fs.unlinkSync(workFile)
231
+ async function getFileWatcher(fileName, workFilePath, text) {
232
+ info("workFile open " + workFilePath)
233
+ if (!_fileWatcherMap[workFilePath]) {
234
+ _fs.unlinkSync(workFilePath)
260
235
  await sleep(1000)
261
- _fs.writeFileSync(workFile, text)
262
- let watcher = _Chokidar.watch([workFile]);
263
- _fileWatcherMap[workFile] = watcher;
236
+ _fs.writeFileSync(workFilePath, text)
237
+ let watcher = _chokidar.watch([workFilePath]);
238
+ _fileWatcherMap[workFilePath] = watcher;
239
+ setTips("FILE", "FILE", () => {
240
+ Object.keys(_fileWatcherMap).forEach(closeFileWatcher);
241
+ })
264
242
  return watcher
265
243
  }
266
244
  }
267
- async function fileLine(name) {
245
+
246
+ function closeFileWatcher(workFilePath) {
247
+ let watcher = _fileWatcherMap[workFilePath]
248
+ info("workFile close " + workFilePath)
249
+ watcher.unwatch([workFilePath])
250
+ watcher.close()
251
+ delete _fileWatcherMap[workFilePath]
252
+ }
253
+
254
+ async function workFile(name) {
268
255
  name = trim(name)
269
256
  if (!name) {
270
- name = 'lineWorkFile'
257
+ name = 'workFile'
271
258
  }
272
259
  let fileName = `f ${toJsirFileName(name)}`
273
- let workFile = `${_home}/${fileName}`;
274
- if (!_fs.existsSync(workFile)) {
275
- _fs.writeFileSync(workFile, '');
260
+ let workFilePath = `${_home}/${fileName}`;
261
+ if (!_fs.existsSync(workFilePath)) {
262
+ _fs.writeFileSync(workFilePath, '');
276
263
  }
277
- let text = String(_fs.readFileSync(workFile))
278
- let watcher = await getFileWatcher(fileName, workFile, text)
279
- text = trim(text)
280
- let line = trim(getExeLine(text))
264
+ let text = String(_fs.readFileSync(workFilePath))
265
+ let watcher = await getFileWatcher(fileName, workFilePath, text)
266
+
281
267
  if (watcher) {
282
268
  watcher.on('change', async () => {
283
- let newText = trim(String(_fs.readFileSync(workFile)))
284
- let newLine = trim(getExeLine(newText))
285
- let tmpLine = line
286
- line = newLine
287
- if (newLine && newLine !== tmpLine) {
288
- let exeStrs
289
- if (newLine.startsWith('/*')) {
290
- exeStrs = newLine.split('\n').slice(1, -1).map(trim).filter(i => i)
291
- } else {
292
- exeStrs = ["#" + newLine]
293
- }
294
- for(let exeStr of exeStrs) {
295
- await wrapperInput(trim(exeStr))
269
+ let newText = String(_fs.readFileSync(workFilePath));
270
+ let exeStr = getExeStr(text, newText);
271
+ text = newText;
272
+ if (trim(exeStr)) {
273
+ try {
274
+ console.log("\n" + infoStr("------ workFile run ------"))
275
+ await evalText(exeStr)
276
+ } catch (e) {
277
+ error(e)
296
278
  }
297
279
  }
298
280
  }).on("unlink", () => {
299
- info("fileLine close " + workFile)
300
- watcher.unwatch([workFile])
301
- watcher.close()
302
- delete _fileWatcherMap[workFile]
281
+ closeFileWatcher(workFilePath);
303
282
  });
304
283
  }
305
- await e(`"${getFileOpenExe(fileName)}" "${workFile}"`)
284
+ await e(`"${getFileOpenExe(fileName)}" "${workFilePath}"`)
306
285
  }
307
286
 
308
- function getExeLine(text) {
309
- let lines = []
310
- let nLine = []
311
- let cLine = []
312
- for (let line of text.split("\n")
313
- .map(i => trim(i))
314
- .filter(i => i)) {
315
- if (lines.length > 1) {
316
- break
317
- }
318
- if (nLine.length > 0) {
319
- nLine.push(line)
320
- if (line.endsWith('*/')) {
321
- lines.push(nLine.join('\n'))
322
- nLine = []
323
- }
324
- continue
325
- }
287
+ function getExeStr(oldText, newText) {
288
+ let olds = oldText.split(/\n/).filter(i => trim(i));
289
+ let news = newText.split(/\n/).filter(i => trim(i));
326
290
 
327
- if (line.startsWith('/*')) {
328
- if (cLine.length > 0) {
329
- lines.push(cLine.join('\n'))
330
- cLine = []
331
- }
291
+ if (olds.length !== news.length) {
292
+ return ;
293
+ }
332
294
 
333
- if (!line.endsWith('*/')) {
334
- nLine.push(line)
295
+ let reg = /^\/\/\s*jsir(\s+.+)?$/;
296
+
297
+ let lineChange = false
298
+ let flagChange = false
299
+ let currText = []
300
+ for (let i = 0; i < news.length; i++) {
301
+ if (!flagChange && lineChange) {
302
+ break;
303
+ }
304
+ let oldLine = olds[i];
305
+ let newLine = news[i];
306
+ if (reg.test(trim(newLine))) {
307
+ if (flagChange) {
308
+ break;
309
+ }
310
+ if (reg.test(trim(oldLine))) {
311
+ if (trim(oldLine).split(/jsir/)[0] !== trim(newLine).split(/jsir/)[0]) {
312
+ flagChange = true
313
+ }
335
314
  } else {
336
- lines.push("")
315
+ break;
337
316
  }
338
- continue
317
+ currText = []
318
+ } else {
319
+ currText.push(newLine)
339
320
  }
340
321
 
341
- cLine.push(line)
322
+ if (oldLine !== newLine) {
323
+ lineChange = true;
324
+ }
342
325
  }
343
- if (cLine.length > 0) {
344
- lines.push(cLine.join('\n'))
326
+ if (flagChange) {
327
+ return currText.join("\n")
345
328
  }
346
- return lines[1]
347
329
  }
348
330
 
349
331
  async function nextLine(callback, preStr, hidden) {
@@ -352,13 +334,8 @@ async function nextLine(callback, preStr, hidden) {
352
334
  })
353
335
  }
354
336
 
355
- function _nextLine(callback, preStr, hidden, resolve, end) {
356
- end = trim(end)
357
- if (!_haveWrapperInput) {
358
- return
359
- }
337
+ function initRl(callback, preStr, hidden) {
360
338
  if (!_rl) {
361
- let readline = require('readline')
362
339
  _rl = readline.createInterface({
363
340
  input: process.stdin,
364
341
  output: process.stdout
@@ -372,23 +349,49 @@ function _nextLine(callback, preStr, hidden, resolve, end) {
372
349
  nextLine();
373
350
  }
374
351
  });
352
+ _rl.history = _rlHistory
375
353
  }
376
- _haveWrapperInput = false
377
354
 
378
- _rl._writeToOutput = function _writeToOutput(stringToWrite){
379
- if(hidden && stringToWrite.indexOf("\n") === -1 && stringToWrite !== promitStr){
380
- if (stringToWrite.indexOf(promitStr) === -1) {
381
- _rl.output.write("*");
355
+ let repoTip = trim(trim(getConfig("jsLibSource")).split('/').map(trim).reverse().filter(i => i)[0])
356
+ let promptStr = preStr
357
+ if (promptStr !== '') {
358
+ promptStr = (preStr
359
+ || ((callback && callback !== wrapperInput) ? "-> ":"")
360
+ || [Object.values(global.$tips).filter(i => String(i)).join(','), repoTip].filter(i => i).join(':') + `> `)
361
+ promptStr = infoStr(promptStr)
362
+ }
363
+ if (hidden) {
364
+ _rl._writeToOutput = function _writeToOutput(stringToWrite){
365
+ if(hidden && stringToWrite.indexOf("\n") === -1 && stringToWrite !== promptStr){
366
+ if (stringToWrite.indexOf(promptStr) === -1) {
367
+ _rl.output.write("*");
368
+ } else {
369
+ _rl.output.write(promptStr + stringToWrite.replace(promptStr, '').replace(/[\s\S]/g, '*'));
370
+ }
382
371
  } else {
383
- _rl.output.write(promitStr + stringToWrite.replace(promitStr, '').replace(/[\s\S]/g, '*'));
372
+ _rl.output.write(stringToWrite);
384
373
  }
385
- } else {
386
- _rl.output.write(stringToWrite);
387
374
  }
388
375
  }
389
- _rl.removeAllListeners('line')
376
+
377
+ _rl.setPrompt(promptStr);
378
+ }
379
+
380
+ function closeRl() {
381
+ _rlHistory = _rl.history;
382
+ _rl.close();
383
+ _rl = null;
384
+ }
385
+
386
+ function _nextLine(callback, preStr, hidden, resolve, end) {
387
+ end = trim(end)
388
+ if (!_haveWrapperInput) {
389
+ return
390
+ }
391
+ initRl(callback, preStr, hidden);
392
+ _haveWrapperInput = false
390
393
  let inputStr = ''
391
- _rl.on('line', async line => {
394
+ let lineHander = async line => {
392
395
  let textLine = line
393
396
  line = trim(line)
394
397
  if (end) {
@@ -397,37 +400,40 @@ function _nextLine(callback, preStr, hidden, resolve, end) {
397
400
  }
398
401
  } else {
399
402
  inputStr = line
403
+ if (/^\s+$/.test(textLine) && (!callback || wrapperInput === callback)) {
404
+ console.clear();
405
+ listCmd();
406
+ }
400
407
  }
401
408
  if (line && (hidden || (callback && callback !== wrapperInput))) {
402
409
  _rl.history = _rl.history.slice(1)
403
410
  }
404
411
  if (!end || line === end) {
405
412
  _haveWrapperInput = true;
406
- if (_noAppendNextLine && _rl) {
407
- _rl.close()
408
- _rl = null
409
- }
413
+ closeRl()
410
414
  inputStr = inputStr.replace(/\s+$/, '');
411
415
 
412
416
  let pro = (callback || wrapperInput)(inputStr);
413
417
 
414
418
  resolve && resolve(inputStr);
419
+ let currCallback = callback;
415
420
  callback = null;
416
421
  hidden = false;
417
422
  end = null;
418
423
  inputStr = '';
419
- await pro;
424
+
425
+ try {
426
+ await pro;
427
+ } finally {
428
+ if ((currCallback || wrapperInput) === wrapperInput) {
429
+ _noAppendNextLine || nextLine()
430
+ }
431
+ }
420
432
  }
421
- })
422
- let repoTip = trim(trim(getConfig("jsLibSource")).split('/').map(trim).reverse().filter(i => i)[0])
423
- let promitStr = preStr
424
- if (promitStr !== '') {
425
- promitStr = (preStr
426
- || ((callback && callback !== wrapperInput) ? "-> ":"")
427
- || [Object.values(global.$tips).filter(i => String(i)).join(','), repoTip].filter(i => i).join(':') + `> `)
428
- promitStr = infoStr(promitStr)
429
433
  }
430
- _rl.setPrompt(promitStr);
434
+
435
+ _rl.removeAllListeners('line')
436
+ _rl.on('line', lineHander)
431
437
  _rl.prompt()
432
438
  }
433
439
 
@@ -543,7 +549,7 @@ function hisToCmdMap() {
543
549
  _cmdMap = cmdMap
544
550
  }
545
551
 
546
- function listCmd(prefix, inputCmdMap) {
552
+ function listCmd(prefixKey, inputCmdMap) {
547
553
  let currCmdMap = _cmdMap
548
554
  if (inputCmdMap) {
549
555
  currCmdMap =inputCmdMap;
@@ -565,7 +571,10 @@ function listCmd(prefix, inputCmdMap) {
565
571
  }
566
572
  }
567
573
  let items = Object.values(currCmdMap)
568
- .filter(item => _fs.existsSync(_home + "/" + item) && (!prefix || prefixMap[item].indexOf(prefix) !== -1))
574
+ .filter(item => _fs.existsSync(_home + "/" + item)
575
+ && ((prefixKey === '' && prefixMap[item].filter(i => trim(i)).length <= 0)
576
+ || (trim(prefixKey) && prefixMap[item].indexOf(trim(prefixKey)) !== -1)
577
+ || (!prefixKey && prefixKey !== '')))
569
578
  .sort((a,b) => {
570
579
  let typeKeys = Object.keys(_types);
571
580
  let orderA = typeKeys.indexOf(a.split(/\s+/)[0]);
@@ -607,7 +616,7 @@ function listCmd(prefix, inputCmdMap) {
607
616
  if (!text) {
608
617
  text = String(_fs.readFileSync(_home + "/" + currCmdMap[i]))
609
618
  }
610
- getComments(currCmdMap[i], text, items, item)
619
+ getComments(i, currCmdMap[i], text, items, item)
611
620
  }
612
621
  if (Object.keys(items).length === 0) {
613
622
  warn("no items")
@@ -625,71 +634,6 @@ function listCmd(prefix, inputCmdMap) {
625
634
  }
626
635
  }
627
636
 
628
- function printObjProfile(result) {
629
- result = Object.keys(result).map(key => {
630
- return {
631
- key,
632
- type: typeof result[key]
633
- }})
634
- .sort((a,b) => {
635
- return a.type >= b.type ? 1:-1
636
- })
637
-
638
- let temp = []
639
- for(let i = 0; i< Object.keys(result).length; i+=3) {
640
- let item = {}
641
- temp.push(item)
642
-
643
- item['type'] = result[i].type
644
- item['name']= result[i].key
645
- if (result[i+1]) {
646
- item['type '] = result[i+1].type
647
- item['name ']= result[i+1].key
648
- }
649
- if (result[i+2]) {
650
- item['type '] = result[i+2].type
651
- item['name ']= result[i+2].key
652
- }
653
- }
654
- console.table(temp)
655
- }
656
-
657
- function draftQuery(fLine) {
658
- let lines = []
659
- let text = String(_fs.readFileSync(getLibDataDir() + "/log/draft.log"))
660
- let temp = []
661
- for (let line of text.split("\n")) {
662
- if (!trim(line)) {
663
- continue
664
- }
665
- if (line.startsWith("---------")) {
666
- if (temp.length > 0) {
667
- lines.push(temp.join('\n'))
668
- }
669
- temp = []
670
- temp.push(warnStr(line))
671
- } else {
672
- temp.push(line)
673
- }
674
- }
675
- if (temp.length > 0) {
676
- lines.push(temp.join('\n'))
677
- }
678
-
679
- let results = []
680
- if (/^\d+$/.test(fLine)) {
681
- let index = Math.abs(parseInt(fLine));
682
- results.push(...lines.slice(- index))
683
- } else {
684
- for (let line of lines) {
685
- if (isArgsMatch(line, fLine.split(/\s+/))) {
686
- results.push(line)
687
- }
688
- }
689
- }
690
- console.log(results.join("\n"))
691
- }
692
-
693
637
  async function wrapperInput(str) {
694
638
  try {
695
639
  await _wrapperInput(str);
@@ -704,31 +648,23 @@ async function _wrapperInput(str) {
704
648
 
705
649
  str = trim(str)
706
650
  if (!str) {
707
- _noAppendNextLine || nextLine()
708
651
  return;
709
652
  }
710
- if (/^[&]/.test(str)) {
711
- _rl.removeAllListeners('line');
712
- try {
713
- let cmdStr = trim(str.substr(1));
714
- if (/^\d+$/.test(cmdStr) && _cmdMap[cmdStr]) {
715
- if (_cmdMap[cmdStr]) {
716
- ei('vi', [getLibDataDir() + '/ooa/' + _cmdMap[cmdStr]])
717
- } else {
718
- warn("no items")
719
- }
720
- } else if (cmdStr) {
721
- ei(cmdStr.split(/\s+/)[0],
722
- enrichArgs(trim(cmdStr.replace(/^\S+/, ''))).map(trim));
653
+ if (/^&/.test(str)) {
654
+ let cmdStr = trim(str.substr(1));
655
+ if (/^\d+$/.test(cmdStr) && _cmdMap[cmdStr]) {
656
+ if (_cmdMap[cmdStr]) {
657
+ ei('vi', [getLibDataDir() + '/ooa/' + _cmdMap[cmdStr]])
723
658
  } else {
724
- ei('vi', ['-n'])
659
+ warn("no items")
725
660
  }
726
- return;
727
- } finally {
728
- _noAppendNextLine || nextLine()
661
+ } else if (cmdStr) {
662
+ ei(cmdStr.split(/\s+/)[0],
663
+ enrichArgs(trim(cmdStr.replace(/^\S+/, ''))).map(trim));
664
+ } else {
665
+ ei('vi', ['-n'])
729
666
  }
730
- }
731
- if (/^[`'"]/.test(str)) {
667
+ } else if (/^[`'"]/.test(str)) {
732
668
  let fstr = str.substr(0, 1);
733
669
  if (fstr === '`') {
734
670
  let text = str.substr(1) + "\n" + await nextText(line => line, fstr)
@@ -736,24 +672,20 @@ async function _wrapperInput(str) {
736
672
  } else {
737
673
  let fLine = trim(str.substr(1))
738
674
  if (fLine) {
739
- draftQuery(fLine)
675
+ console.log(draftQuery(fLine).join("\n"))
740
676
  } else {
741
677
  let text = str.substr(1) + "\n" + await nextText(line => line, fstr)
742
678
  $draft(text)
743
679
  }
744
- _noAppendNextLine || nextLine()
745
680
  }
746
- return;
747
- }
748
-
749
- if (/^[$#*]/.test(str)) {
681
+ } else if (/^[$#*]/.test(str)) {
750
682
  let is$ = str.startsWith('$')
751
683
  let isStar = str.startsWith('*')
752
684
  let text = trim(str.replace(/^[$#*]/, ''))
753
685
  if (is$) {
754
686
  let result = await evalText('return ' + text)
755
687
  if (result === $lib) {
756
- printObjProfile(result)
688
+ console.table(objProfileRows(result))
757
689
  } else {
758
690
  console.log(result)
759
691
  }
@@ -788,11 +720,9 @@ async function _wrapperInput(str) {
788
720
  } else {
789
721
  listCmd()
790
722
  }
791
- _noAppendNextLine || nextLine()
792
723
  } else if (!str.split(/\s+/)[0].match(/^\d+$/)) {
793
724
  _cmdMap = filterCmd(str.split(/\s+/))
794
725
  listCmd()
795
- _noAppendNextLine || nextLine()
796
726
  } else {
797
727
  let strs = str.split(/\s+/)
798
728
  if (_cmdMap[strs[0]]) {
@@ -801,10 +731,9 @@ async function _wrapperInput(str) {
801
731
  let fileName = trim(_cmdMap[strs[0]]);
802
732
  let firstName = fileName.split(/\s+/)[0]
803
733
  if (firstName === 'f') {
804
- await fileLine(fileName.replace(/^\s*f\s*/, ''))
734
+ await workFile(fileName.replace(/^\s*f\s*/, ''))
805
735
  } else if (firstName !== 'e') {
806
736
  console.log(String(_fs.readFileSync(path)));
807
- _noAppendNextLine || nextLine()
808
737
  } else {
809
738
  await runCmd(str)
810
739
  }
@@ -814,15 +743,35 @@ async function _wrapperInput(str) {
814
743
  }
815
744
  }
816
745
 
746
+ function delTipsByIndex(idxs) {
747
+ let keys = Object.keys($tips)
748
+ let indexKeyMap = {}
749
+ for(let i = 1;i<=keys.length;i++) {
750
+ indexKeyMap[i] = keys[i - 1]
751
+ }
752
+ let params = []
753
+ for (const index of idxs) {
754
+ if ($tips.hasOwnProperty(index)) {
755
+ params.push(index)
756
+ } else if (indexKeyMap[Number(index)]) {
757
+ params.push(indexKeyMap[Number(index)])
758
+ } else if (indexKeyMap[keys.length + 1 + Number(index)]) {
759
+ params.push(indexKeyMap[keys.length + 1 + Number(index)])
760
+ }
761
+ }
762
+ delTips(...params)
763
+ }
764
+
817
765
  async function dealKeyword(str, strs, fstr, ostr) {
818
- if (/^\d+$/.test(fstr)) {
766
+ if (fstr.startsWith("<")) {
767
+ delTipsByIndex([fstr, ...ostr].join(" ").replace(/^</, '').split(/\s+/).filter(i => i))
768
+ } else if (/^\d+$/.test(fstr)) {
819
769
  if (!_cmdMap[fstr]) {
820
770
  warn("no items")
821
771
  } else {
822
772
  let path = _home + '/' + _cmdMap[fstr]
823
773
  let sourceStr = String(_fs.readFileSync(path))
824
774
  console.log(sourceStr)
825
- // await setCbText(sourceStr)
826
775
  }
827
776
  } else if (/^-\d*$/.test(fstr)) {
828
777
  let name = _cmdMap[String(Number(fstr) * -1)]
@@ -895,7 +844,6 @@ async function dealKeyword(str, strs, fstr, ostr) {
895
844
  if (_fs.existsSync(sFile)) {
896
845
  let sourceStr = String(_fs.readFileSync(sFile))
897
846
  console.log(sourceStr)
898
- // await setCbText(sourceStr)
899
847
  }
900
848
  } else {
901
849
  warn('require config.jsLibSource')
@@ -938,6 +886,8 @@ async function dealKeyword(str, strs, fstr, ostr) {
938
886
  warn('require config.jsLibSource')
939
887
  }
940
888
  }
889
+ }else if (fstr === '!') {
890
+ listCmd('')
941
891
  } else if (/^w\d*$/.test(fstr)) {
942
892
  let name = _cmdMap[trim(fstr.replace(/^w/, ''))]
943
893
  if (!name) {
@@ -960,13 +910,22 @@ async function dealKeyword(str, strs, fstr, ostr) {
960
910
  warn('require config.jsLibSource')
961
911
  }
962
912
  }
913
+ } else if (/^\^\d*$/.test(fstr)) {
914
+ let name = _cmdMap[trim(fstr.replace(/^\^/, ''))]
915
+ if (!name) {
916
+ warn("no items")
917
+ } else {
918
+ let md5Keys = getScriptRequires(name);
919
+ _cmdMap = filterCmd(md5Keys)
920
+ listCmd()
921
+ }
963
922
  } else if (/^e\d+$/.test(fstr)) {
964
923
  await runCmd(trim(str.substring(1)).replace(/^e/, ''))
965
924
  } else if (fstr === 'e' && ostr.length === 0) {
966
925
  hisToCmdMap()
967
926
  listCmd()
968
927
  } else if (fstr === 'f') {
969
- await fileLine(trim(ostr.join(' ')))
928
+ await workFile(trim(ostr.join(' ')))
970
929
  } else if (fstr === '%') {
971
930
  let newRepo = trim(ostr[0])
972
931
  let currRepo = getConfig('jsLibSource');
@@ -994,17 +953,56 @@ async function dealKeyword(str, strs, fstr, ostr) {
994
953
  warn(`repo ${newRepo} not exist`)
995
954
  }
996
955
  }
997
- _noAppendNextLine || nextLine()
998
956
  } else if (fstr === 'q') {
999
957
  console.log("Bye!")
958
+ _exit = true;
1000
959
  process.exit(0)
1001
960
  } else {
1002
961
  await save(strs)
1003
962
  }
1004
963
  }
1005
964
 
1006
- function getComments(cmdName, text, cols = [], col) {
1007
- let docLines = [infoStr('0x' + md5(cmdName).substr(0, 8))]
965
+ function getScriptMd5Map() {
966
+ let files = _fs.readdirSync(_home)
967
+ let md5Map = {}
968
+ for (let file of files) {
969
+ file = trim(file)
970
+ md5Map['0x' + md5(file).substr(0, 8)] = file;
971
+ }
972
+ return md5Map
973
+ }
974
+
975
+ function _getScriptRequires(md5Map, scriptName, md5Keys, links) {
976
+ let path = _home + '/' + scriptName;
977
+ let text = String(_fs.readFileSync(path))
978
+ let temp = []
979
+ regEach(text, /(0x[0-9a-f]{8})/g, r=> {
980
+ temp.push(r[1])
981
+ });
982
+ temp = [...new Set(temp)]
983
+ temp = temp.filter(i => {
984
+ let have = md5Map[i];
985
+ if (have && links.indexOf(i) !== -1) {
986
+ let items = [...links, i];
987
+ let errorStr = items.map(item => item === i ? warnStr(item):item).join("->")
988
+ throw `circle deps: ${errorStr}`
989
+ }
990
+ return have;
991
+ })
992
+ md5Keys.push(...temp)
993
+ for (let md5Key of temp) {
994
+ _getScriptRequires(md5Map, md5Map[md5Key], md5Keys, [...links, md5Key])
995
+ }
996
+ }
997
+
998
+ function getScriptRequires(scriptName) {
999
+ let md5Keys = [];
1000
+ _getScriptRequires(getScriptMd5Map(), scriptName, md5Keys, ['0x' + md5(scriptName).substr(0, 8)]);
1001
+ return md5Keys
1002
+ }
1003
+
1004
+ function getComments(i, cmdName, text, cols = [], col) {
1005
+ let docLines = [infoStr('0x' + md5(cmdName).substr(0, 8)) + " - " + infoStr(i)]
1008
1006
  text = trim(text)
1009
1007
  if (text.startsWith("/*")) {
1010
1008
  for (let line of text.split("\n")) {
@@ -1089,28 +1087,6 @@ function filterCmd(args){
1089
1087
  return cmdMap
1090
1088
  }
1091
1089
 
1092
- function isArgsMatch(text, args, callback, useMd5) {
1093
- let match = false
1094
- for (let arg of args) {
1095
- let r = true
1096
- for (let str of arg.split(',').filter(item => trim(item) !== '')) {
1097
- let reg = new RegExp(str, 'i')
1098
- if (!reg.test(text) && !(useMd5 && ('0x' + md5(text).substr(0, 8)) === str)) {
1099
- r = false
1100
- break
1101
- }
1102
- }
1103
- if (r) {
1104
- match = true
1105
- break
1106
- }
1107
- }
1108
- if (match && callback) {
1109
- callback()
1110
- }
1111
- return match
1112
- }
1113
-
1114
1090
  function getArgComments(argDef) {
1115
1091
  let comments = []
1116
1092
  let keys = Object.keys(argDef)
@@ -1146,7 +1122,6 @@ async function runCmd(str = '', scriptName = '', text = '') {
1146
1122
  if (!scriptName) {
1147
1123
  if (!_cmdMap[strs[0]] && strs[0] !== '0') {
1148
1124
  warn('no items')
1149
- _noAppendNextLine || nextLine()
1150
1125
  return
1151
1126
  }
1152
1127
  if (_cmdMap[strs[0]]) {
@@ -1177,9 +1152,9 @@ async function runCmd(str = '', scriptName = '', text = '') {
1177
1152
  let arg = oriArgs[i]
1178
1153
  let needTrans
1179
1154
  let pair
1180
- if (arg.endsWith(":")) {
1181
- arg = arg.replace(/:$/, '')
1182
- if (oriArgs[i+1] && !oriArgs[i+1].endsWith(":")) {
1155
+ if (arg.startsWith(":") || arg.startsWith("_")) {
1156
+ arg = arg.replace(/^:/, '')
1157
+ if (oriArgs[i+1] && !(oriArgs[i+1].startsWith(":") || oriArgs[i+1].startsWith("_"))) {
1183
1158
  pair = [arg, oriArgs[i+1]]
1184
1159
  i++
1185
1160
  } else {
@@ -1194,7 +1169,7 @@ async function runCmd(str = '', scriptName = '', text = '') {
1194
1169
  if (pair[1]) {
1195
1170
  pair[1] = trim(pair[1])
1196
1171
  }
1197
- if (pair[0] && !argDef.hasOwnProperty(pair[0])) {
1172
+ if (pair[0] && argNames.indexOf(pair[0]) === -1) {
1198
1173
  throw 'invalid argName ' + pair[0]
1199
1174
  }
1200
1175
  pair[1] = needTrans ? await evalText( 'return ' + pair[1]):pair[1]
@@ -1205,7 +1180,7 @@ async function runCmd(str = '', scriptName = '', text = '') {
1205
1180
  if (argNames[curIdx]) {
1206
1181
  scriptArgs[argNames[curIdx]] = pair[1]
1207
1182
  }
1208
- if (pair[0] && argDef.hasOwnProperty(pair[0])) {
1183
+ if (pair[0] && argNames.indexOf(pair[0]) !== -1) {
1209
1184
  delete scriptArgs[argNames[curIdx]]
1210
1185
  exactArgs[pair[0]] = pair[1]
1211
1186
  }
@@ -1214,6 +1189,7 @@ async function runCmd(str = '', scriptName = '', text = '') {
1214
1189
  scriptArgs[key] = exactArgs[key]
1215
1190
  }
1216
1191
  let exit = false
1192
+ let scriptArgKeys = Object.keys(scriptArgs);
1217
1193
  for(let name of argNames) {
1218
1194
  let defStr = argDef[name]
1219
1195
  let beginIdx = defStr.indexOf("^");
@@ -1222,10 +1198,10 @@ async function runCmd(str = '', scriptName = '', text = '') {
1222
1198
  if (beginIdx !== -1 && endIdx !== -1 && beginIdx < endIdx) {
1223
1199
  reg = new RegExp(defStr.substring(beginIdx, endIdx + 1));
1224
1200
  }
1225
- if (name.startsWith("_") && !scriptArgs.hasOwnProperty(name)) {
1201
+ if (name.startsWith("_") && scriptArgKeys.indexOf(name) === -1) {
1226
1202
  continue
1227
1203
  }
1228
- if (!scriptArgs.hasOwnProperty(name) || (reg && !reg.test(scriptArgs[name]))) {
1204
+ if (scriptArgKeys.indexOf(name) === -1 || (reg && !reg.test(scriptArgs[name]))) {
1229
1205
  exit = true
1230
1206
  warn(`require ${warnStr(name)}` + (defStr ? ` <${defStr}>`:''))
1231
1207
  }
@@ -1275,9 +1251,15 @@ function getArgDef(text) {
1275
1251
  let argDef = {}
1276
1252
  try {
1277
1253
  argDef = eval(`(${exeStr || '{}'})`) || {}
1254
+ let array = []
1255
+ for (let key of Object.keys(argDef)) {
1256
+ if (array.hasOwnProperty(key)) {
1257
+ throw `invalid argName ${key}`
1258
+ }
1259
+ }
1278
1260
  } catch (e) {
1279
1261
  $log(errorStack(e))
1280
- argDef['[ParseError]'] = String(e)
1262
+ argDef = {'[ParseError]': String(e)}
1281
1263
  }
1282
1264
  if (typeof argDef !== 'object') {
1283
1265
  argDef = {}
@@ -1376,6 +1358,24 @@ async function _requireSource(cmdMatchStr, ignoreLog = false) {
1376
1358
  }
1377
1359
  throw `invalid returned: ${cmdMatchStr}`
1378
1360
  }
1361
+ if (typeof result === 'function') {
1362
+ let tmp = result;
1363
+ result = (...args) => {
1364
+ let resp
1365
+ try {
1366
+ resp = tmp(...args)
1367
+ } catch (e) {
1368
+ throw errorTag(e, cmdName);
1369
+ }
1370
+ if (getType(resp) === 'Promise') {
1371
+ return resp.catch(e => {
1372
+ return Promise.reject(errorTag(e, cmdName))
1373
+ })
1374
+ } else {
1375
+ return resp;
1376
+ }
1377
+ }
1378
+ }
1379
1379
  return result
1380
1380
  }
1381
1381
 
@@ -1401,30 +1401,9 @@ async function _requireSources(...matchItem) {
1401
1401
  }
1402
1402
 
1403
1403
  function evalText($text = '', $cmdName = '', $args = []) {
1404
- const require = requireG;
1405
- const $nextLine = nextLine;
1406
- const $nextText = nextText;
1407
- const $setTips = setTips;
1408
- const $delTips = delTips;
1409
- const $info = info;
1410
- const $msg = msg;
1411
- const $warn = warn;
1412
- const $error = error;
1413
- const $infoStr = infoStr;
1414
- const $msgStr = msgStr;
1415
- const $warnStr = warnStr;
1416
- const $errorStr = errorStr;
1417
- const $cmdDir = _home;
1418
- const $cmdMap = _cmdMap;
1419
- const $defArgs = () => $args;
1420
- const $require = _requireSources;
1421
-
1422
- let code = `(async ()=>{try {${$text};
1423
- } catch(e) {
1424
- throw \`${$cmdName}${errorStr('->')}\` + (e ? (e.stack || e):e);
1425
- }
1426
- })()`
1427
- return eval(code)
1404
+ return evalCode($text, $cmdName, $args,
1405
+ _home, _cmdMap, _requireSources, $data,
1406
+ nextLine, nextText, setTips, delTips, wrapperInput)
1428
1407
  }
1429
1408
 
1430
1409
  process.on('uncaughtException',function(err){
@@ -1439,3 +1418,15 @@ process.on('rejectionHandled',function(err){
1439
1418
  error(err, 'rejectionHandled')
1440
1419
  _noAppendNextLine || nextLine()
1441
1420
  })
1421
+ process.on('SIGINT', function () {
1422
+ if (_noAppendNextLine) {
1423
+ process.exit();
1424
+ } else {
1425
+ nextLine();
1426
+ }
1427
+ });
1428
+ process.on('beforeExit', function () {
1429
+ if (!_exit) {
1430
+ _noAppendNextLine || nextLine();
1431
+ }
1432
+ });