jsir 2.1.4 → 2.1.6

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/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # jsir: JavaScript Script Management Tool
2
+
3
+ **jsir** is a command line tool designed to help manage and organize your JavaScript files. With **jsir**, you can edit, run, and compare JavaScript files, view file dependencies, and switch between different workspaces.
4
+
5
+ ## Installation
6
+
7
+ You can install **jsir** globally using npm:
8
+
9
+ ```
10
+ npm install -g jsir
11
+ ```
12
+
13
+ ## Getting Started
14
+
15
+ To start using **jsir**, simply run the command:
16
+
17
+ ```
18
+ jsir
19
+ ```
20
+
21
+ This will open the **jsir** REPL interface where you can start managing your files.
22
+
23
+ ## Commands
24
+
25
+ Here is a list of available commands in **jsir**:
26
+
27
+ | Keyword | Short | Comment |
28
+ | --- | --- | --- |
29
+ | .add | .a | Add file |
30
+ | .clear | .C | Clear task |
31
+ | .compare | .c | Compare files |
32
+ | .deps | .d | View file dependencies |
33
+ | .edit | .e | Edit file |
34
+ | .file | .f | Working file mode |
35
+ | .get | .g | Get file |
36
+ | .help | .h | Help documentation |
37
+ | .list | .l | View file list |
38
+ | .quit | .q | Exit |
39
+ | .rename | .n | Rename file |
40
+ | .repl | .p | Interactive interface |
41
+ | .rm | .R | Remove file |
42
+ | .run | .r | Quick execution |
43
+ | .see | .s | View file |
44
+ | .switch | .S | Switch workspace |
45
+ | .uninstall | .u | Uninstall workspace |
46
+ | .version | .v | View version |
47
+ | .workspace | .w | Workspace Management |
48
+
49
+ For detailed information on how to use each command, use the `.help` command followed by the short keyword of the command.
package/cmd/oaa.js CHANGED
@@ -3,10 +3,10 @@ const $lib = require('../deps/util');
3
3
  const {
4
4
  getLibDataDir, trim, regEach, getConfig, mkdir, reget,
5
5
  getCbText, e, sleep, objDataFile, vl, md5, BigNumber,
6
- info, warn, error, arrayDataFile, infoStr, warnStr, errorStack,
6
+ arrayDataFile, infoStr, warnStr, errorStack,
7
7
  getInfo, ei, pad, msgStr, getType,
8
8
  errorTag, isArgsMatch, draftQuery, setConfig,
9
- $log, $draft, getTextComments, getOr, importG
9
+ $log, $draft, getTextComments, getOr, importG, requireG
10
10
  } = $lib;
11
11
  const _args = process.argv.slice(2).map(trim);
12
12
  const evalCode = require('../deps/evalCode')
@@ -15,8 +15,8 @@ const _chokidar = require('chokidar');
15
15
  const setting = require('../deps/setting')
16
16
  const _fs = require('fs')
17
17
  const readline = require("readline");
18
- const {requireG} = require("../deps/util");
19
-
18
+ const packageJson = require("../package.json");
19
+ const example = require("../deps/example");
20
20
  const _workspaceConfigFile = 'workspace.json';
21
21
  const _libDataDir = getLibDataDir()
22
22
  const _tipsOnRm = {}
@@ -30,43 +30,55 @@ const $config = {
30
30
  get: getConfig,
31
31
  set: setConfig
32
32
  }
33
+ const CONSOLE = Object.assign({}, console);
34
+ const info = (msg) => $lib.info(msg, CONSOLE);
35
+ const warn = (msg) => $lib.warn(msg, CONSOLE);
36
+ const error = (msg, tag) => $lib.error(msg, tag, CONSOLE);
33
37
 
34
38
  let _cmdMapFile = setting.name + 'CmdMap.json'
35
39
  let _cmdMap = {}
36
40
  let _rl
37
41
  let _rlHistory = []
38
42
  let _haveWrapperInput = true
39
- let _exit = false
40
43
  let _noAppendNextLine = true
41
44
 
42
- const _onGetMap = {}
45
+ const _onLazyGetMap = {}
43
46
  const _data = {}
44
- const _tempTime = 60 * 1000
45
- const _dealOnGet = (key) => {
46
- if (_noAppendNextLine || !_onGetMap[key]) {
47
+ const _lazyTime = 5 * 60 * 1000
48
+ const _dealOnLazyGet = (key) => {
49
+ if (_noAppendNextLine || !_onLazyGetMap[key]) {
47
50
  return _data[key]
48
51
  }
49
- let item = _onGetMap[key]
52
+ let item = _onLazyGetMap[key]
50
53
  if (Date.now() <= item.startTime) {
51
- item.startTime = Date.now() + _tempTime
54
+ item.startTime = Date.now() + _lazyTime
52
55
  return _data[key]
53
56
  }
54
- let flag = _onGetMap[key].fn()
57
+ let flag = _onLazyGetMap[key].fn()
55
58
  if (getType(flag)=== 'Promise') {
56
59
  return new Promise(async (resolve, reject) => {
57
60
  try {
58
61
  await flag
59
- item.startTime = Date.now() + _tempTime
62
+ item.startTime = Date.now() + _lazyTime
60
63
  resolve(_data[key])
61
64
  } catch (e) {
62
65
  reject(e)
63
66
  }
64
67
  })
65
68
  } else {
66
- item.startTime = Date.now() + _tempTime
69
+ item.startTime = Date.now() + _lazyTime
67
70
  return _data[key]
68
71
  }
69
72
  }
73
+ const _dataSet = (key, val, onLazyGet) => {
74
+ if (onLazyGet) {
75
+ _onLazyGetMap[key] = {
76
+ fn: onLazyGet,
77
+ startTime: Date.now() + _lazyTime
78
+ }
79
+ }
80
+ return _data[key] = val
81
+ }
70
82
  const $data = {
71
83
  get: (key, defaultVal) => {
72
84
  if (!vl(_data[key])) {
@@ -76,34 +88,26 @@ const $data = {
76
88
  return _data[key]
77
89
  }
78
90
  }
79
- return _dealOnGet(key)
91
+ return _dealOnLazyGet(key)
80
92
  },
81
- gos: (key, defaultVal) => {
93
+ gos: (key, defaultVal, onLazyGet) => {
82
94
  if (!vl(_data[key])) {
83
95
  if (defaultVal !== undefined) {
84
- _data[key] = defaultVal
85
- return defaultVal
96
+ return _dataSet(key, defaultVal, onLazyGet)
86
97
  } else {
87
98
  return _data[key]
88
99
  }
89
100
  }
90
- return _dealOnGet(key)
91
- },
92
- set: (key, val, onGet) => {
93
- if (onGet) {
94
- _onGetMap[key] = {
95
- fn: onGet,
96
- startTime: Date.now() + _tempTime
97
- }
98
- }
99
- return _data[key] = val
101
+ return _dealOnLazyGet(key)
100
102
  },
103
+ set: _dataSet,
101
104
  del: (key) => {
102
105
  let val = _data[key]
103
106
  delete _data[key]
104
107
  return val
105
108
  },
106
- keys: () => Object.keys(_data)
109
+ keys: () => Object.keys(_data),
110
+ have: (key) => vl(_data[key])
107
111
  }
108
112
  const $homeDir = getLibDataDir()
109
113
 
@@ -171,7 +175,7 @@ async function getFileWatcher(workFilePath, text) {
171
175
  _fs.writeFileSync(workFilePath, text)
172
176
  let watcher = _chokidar.watch([workFilePath]);
173
177
  _fileWatcherMap[workFilePath] = watcher;
174
- setTips("FILE", "FILE", () => {
178
+ setTips("FILE", null, () => {
175
179
  Object.keys(_fileWatcherMap).forEach(closeFileWatcher);
176
180
  })
177
181
  return watcher
@@ -209,7 +213,7 @@ async function watchFile(uniqueName) {
209
213
  text = newText;
210
214
  if (trim(exeStr)) {
211
215
  try {
212
- console.log("\n" + infoStr("------ workFile run ------"))
216
+ CONSOLE.log("\n" + infoStr("------ workFile run ------"))
213
217
  await wrapperInput("# " + exeStr)
214
218
  } catch (e) {
215
219
  error(e)
@@ -270,13 +274,18 @@ function getExeStr(oldText, newText) {
270
274
  }
271
275
  }
272
276
 
273
- async function nextLine(callback, preStr, hidden) {
277
+ async function nextLine(callback, promptStr, hidden) {
274
278
  return new Promise(resolve => {
275
- _nextLine(callback, preStr, hidden, resolve)
279
+ _nextLine(callback, promptStr, hidden, resolve)
276
280
  })
277
281
  }
278
282
 
279
- function initRl(callback, preStr, hidden) {
283
+ function defaultPromptStr(showKey = false) {
284
+ return [getTipStr(showKey), $defaultSpace].filter(i => i).join(':') + `> `;
285
+ }
286
+
287
+ function initRl(callback, promptStr, hidden) {
288
+ let origin_writeToOutput;
280
289
  if (!_rl) {
281
290
  _rl = readline.createInterface({
282
291
  input: process.stdin,
@@ -284,8 +293,10 @@ function initRl(callback, preStr, hidden) {
284
293
  })
285
294
  _rl.on("SIGINT", async () => {
286
295
  if (_noAppendNextLine) {
296
+ delTips();
287
297
  process.exit(0);
288
298
  } else {
299
+ _rl._writeToOutput = origin_writeToOutput;
289
300
  _haveWrapperInput = true;
290
301
  _rl.clearLine(0)
291
302
  nextLine();
@@ -293,12 +304,11 @@ function initRl(callback, preStr, hidden) {
293
304
  });
294
305
  _rl.history = _rlHistory
295
306
  }
296
-
297
- let promptStr = preStr
307
+ origin_writeToOutput = _rl._writeToOutput
298
308
  if (promptStr !== '') {
299
- promptStr = (preStr
309
+ promptStr = (promptStr
300
310
  || ((callback && callback !== wrapperInput) ? "-> ":"")
301
- || [Object.values(global.$tips).map(trim).filter(i => i).map(i => i.replace(/,/g, '-')).join(','), $defaultSpace].filter(i => i).join(':') + `> `)
311
+ || defaultPromptStr())
302
312
  promptStr = infoStr(promptStr)
303
313
  }
304
314
  if (hidden) {
@@ -318,69 +328,88 @@ function initRl(callback, preStr, hidden) {
318
328
  _rl.setPrompt(promptStr);
319
329
  }
320
330
 
331
+ function getTipStr(showKey = false) {
332
+ let items = [];
333
+ for (let key of Object.keys(global.$tips)) {
334
+ let val = global.$tips[key].map(i => trim(i).replace(/,/g, '-')).join("|");
335
+ key = trim(key)
336
+
337
+ let item
338
+ if (!showKey && vl(val)) {
339
+ item = val;
340
+ } else if (vl(key)) {
341
+ item = key
342
+ }
343
+ if (item) {
344
+ items.push(item)
345
+ }
346
+ }
347
+ return items.join(',');
348
+ }
349
+
321
350
  function closeRl() {
322
351
  _rlHistory = _rl.history;
323
352
  _rl.close();
324
353
  _rl = null;
325
354
  }
326
355
 
327
- function _nextLine(callback, preStr, hidden, resolve, end) {
356
+ function _nextLine(callback, promptStr, hidden, resolve, end, isText) {
328
357
  end = trim(end)
329
358
  if (!_haveWrapperInput) {
330
359
  return
331
360
  }
332
- initRl(callback, preStr, hidden);
361
+ initRl(callback, promptStr, hidden);
333
362
  _haveWrapperInput = false
334
363
  let inputStr = ''
335
- let lineHander = async line => {
364
+ let lineHandler = async line => {
336
365
  let textLine = line
337
366
  line = trim(line)
338
- if (end) {
339
- if (line !== end) {
367
+ if (isText) {
368
+ if (!end) {
369
+ end = line
370
+ line = ''
371
+ } else if (line !== end) {
340
372
  inputStr += textLine + '\n'
341
373
  }
342
374
  } else {
343
375
  inputStr = line
344
- if (/^\s+$/.test(textLine) && (!callback || wrapperInput === callback)) {
345
- process.stdout.write('\033[2J\033[H');
346
- listCmd();
347
- }
348
376
  }
349
- if (line && (hidden || (callback && callback !== wrapperInput))) {
377
+ if (trim(textLine) && (hidden || (callback && callback !== wrapperInput))) {
350
378
  _rl.history = _rl.history.slice(1)
351
379
  }
352
- if (!end || line === end) {
380
+ if (!isText || line === end) {
353
381
  _haveWrapperInput = true;
354
382
  closeRl()
355
383
  inputStr = inputStr.replace(/\s+$/, '');
356
384
 
357
385
  let pro = (callback || wrapperInput)(inputStr);
358
-
359
386
  resolve && resolve(inputStr);
360
- let currCallback = callback;
361
- callback = null;
362
- hidden = false;
363
- end = null;
364
- inputStr = '';
365
-
366
387
  try {
367
388
  await pro;
368
389
  } finally {
369
- if ((currCallback || wrapperInput) === wrapperInput) {
370
- _noAppendNextLine || nextLine()
390
+ if ((callback || wrapperInput) === wrapperInput) {
391
+ if (!_noAppendNextLine) {
392
+ if (/^\s+$/.test(textLine)) {
393
+ process.stdout.write('\033[2J\033[H');
394
+ listCmd();
395
+ nextLine(null, defaultPromptStr(true))
396
+ } else {
397
+ nextLine()
398
+ }
399
+ }
371
400
  }
372
401
  }
373
402
  }
374
403
  }
375
404
 
376
405
  _rl.removeAllListeners('line')
377
- _rl.on('line', lineHander)
406
+ _rl.on('line', lineHandler)
378
407
  _rl.prompt()
379
408
  }
380
409
 
381
410
  async function nextText(callback, end, hidden) {
382
411
  return new Promise(resolve => {
383
- _nextLine(callback, '', hidden, resolve, end)
412
+ _nextLine(callback, '', hidden, resolve, end, true)
384
413
  })
385
414
  }
386
415
 
@@ -397,30 +426,9 @@ async function save(args) {
397
426
  }
398
427
  let resp;
399
428
  if (args[0] === 'e') {
400
- resp = `/*
401
- A test exe script
402
- */
403
-
404
- $defArgs({
405
- arg: '必填参数',
406
- _arg: '非必填参数'
407
- })
408
-
409
- let {} = $lib // 引用内置资源
410
-
411
- console.log($args)
412
-
413
- return {}
414
- `;
429
+ resp = example.exeFile;
415
430
  } else if (args[0] === 'i') {
416
- resp = `/*
417
- A test init script
418
- */
419
-
420
- let {} = $lib // 引用内置资源
421
-
422
- return {}
423
- `;
431
+ resp = example.initFile;
424
432
  } else {
425
433
  resp = await getCbText();
426
434
  }
@@ -447,8 +455,15 @@ function rename(dir, oldName, newName) {
447
455
  listCmd()
448
456
  }
449
457
 
450
- function listCmd() {
451
- let items = Object.values(_cmdMap)
458
+ function listCmd(tmpMap) {
459
+ let tmpList = false;
460
+ if (tmpMap) {
461
+ tmpList = true;
462
+ } else {
463
+ tmpMap = _cmdMap;
464
+ }
465
+
466
+ tmpMap = arrayToCmdMap(Object.values(tmpMap)
452
467
  .filter(item => _fs.existsSync(getFullPath(item)))
453
468
  .sort((a,b) => {
454
469
  a = parseUniqueName(a)[1];
@@ -459,17 +474,19 @@ function listCmd() {
459
474
  orderA = orderA === -1 ? 999999:orderA;
460
475
  orderB = orderB === -1 ? 999999:orderB;
461
476
  return orderA - orderB
462
- })
477
+ }))
463
478
 
464
- _cmdMap = arrayToCmdMap(items)
465
- if (_noAppendNextLine) {
466
- objDataFile(_cmdMapFile, () => _cmdMap)
479
+ if (!tmpList) {
480
+ _cmdMap = tmpMap;
481
+ if (_noAppendNextLine) {
482
+ objDataFile(_cmdMapFile, () => _cmdMap)
483
+ }
467
484
  }
468
485
 
469
- items = []
470
- for (let i of Object.keys(_cmdMap)) {
471
- let text = String(_fs.readFileSync(getFullPath(_cmdMap[i])))
472
- let pair = parseUniqueName(_cmdMap[i])
486
+ let items = []
487
+ for (let i of Object.keys(tmpMap)) {
488
+ let text = String(_fs.readFileSync(getFullPath(tmpMap[i])))
489
+ let pair = parseUniqueName(tmpMap[i])
473
490
  let name = trimJsirFileName(pair[1])
474
491
  let suffix = getJsirFileSuffix(pair[1])
475
492
  let item = {
@@ -480,9 +497,9 @@ function listCmd() {
480
497
  items.push(item)
481
498
 
482
499
  if (!text) {
483
- text = String(_fs.readFileSync(getFullPath(_cmdMap[i])))
500
+ text = String(_fs.readFileSync(getFullPath(tmpMap[i])))
484
501
  }
485
- getComments(i, _cmdMap[i], text, items, item)
502
+ getComments(i, tmpMap[i], text, items, item)
486
503
  }
487
504
  if (Object.keys(items).length === 0) {
488
505
  warn("no items")
@@ -500,7 +517,7 @@ function listCmd() {
500
517
  item.name = pair[0] + '/' + item.name
501
518
  }
502
519
  })
503
- console.table(items)
520
+ CONSOLE.table(items)
504
521
  }
505
522
  }
506
523
 
@@ -542,7 +559,7 @@ async function _wrapperInput(str) {
542
559
  } else {
543
560
  let fLine = trim(str.substr(1))
544
561
  if (fLine) {
545
- console.log(draftQuery(fLine).join("\n"))
562
+ CONSOLE.log(draftQuery(fLine).join("\n"))
546
563
  } else {
547
564
  let text = str.substr(1) + "\n" + await nextText(line => line, fstr)
548
565
  $draft(text)
@@ -553,14 +570,14 @@ async function _wrapperInput(str) {
553
570
  let isStar = str.startsWith('*')
554
571
  let text = trim(str.replace(/^[$#*]/, ''))
555
572
  if (is$) {
556
- console.log(await evalText('return ' + text))
573
+ CONSOLE.log(await evalText('return ' + text))
557
574
  } else if (isStar) {
558
575
  if (!text) {
559
576
  text = '$context';
560
577
  }
561
578
  let result = await evalText('return ' + text)
562
579
  if (!result || typeof result === 'string' || Object.keys(result).length === 0) {
563
- console.nable([getInfo(result)])
580
+ CONSOLE.nable([getInfo(result)])
564
581
  return
565
582
  }
566
583
  let rows = []
@@ -570,7 +587,7 @@ async function _wrapperInput(str) {
570
587
  if (rows.length === 0) {
571
588
  warn("no items")
572
589
  } else {
573
- console.nable(rows)
590
+ CONSOLE.nable(rows)
574
591
  }
575
592
  } else {
576
593
  await evalText(text)
@@ -590,7 +607,7 @@ async function _wrapperInput(str) {
590
607
  if (firstName === 'f') {
591
608
  await workFile(uniqueName)
592
609
  } else if (firstName !== 'e') {
593
- console.log(String(_fs.readFileSync(path)));
610
+ CONSOLE.log(String(_fs.readFileSync(path)));
594
611
  } else {
595
612
  await runCmd(str)
596
613
  }
@@ -609,12 +626,12 @@ function arrayToCmdMap(cmds) {
609
626
  }
610
627
 
611
628
  function help() {
612
- console.nable(Object.keys(keywordDef).map(key => {
629
+ CONSOLE.nable(Object.keys(keywordDef).map(key => {
613
630
  let item = keywordDef[key];
614
631
  return {
615
632
  keyword: ' ' + warnStr(`.${key}`),
616
633
  short: ' ' + warnStr(`.${item.short}`),
617
- comment: [item.comment, item.args ? getArgComments(item.args).join('\n'):''].filter(i => i).join("\n"),
634
+ comment: [infoStr(item.comment), item.args ? getArgComments(item.args).join('\n'):''].filter(i => i).join("\n"),
618
635
  }
619
636
  }))
620
637
  }
@@ -716,21 +733,21 @@ let compareMode = {
716
733
 
717
734
  const keywordDef = {
718
735
  help: {
719
- comment: '帮助文档',
736
+ comment: 'Help documentation',
720
737
  exeFn: (args) => {
721
738
  help()
722
739
  },
723
740
  short: 'h'
724
741
  },
725
742
  version: {
726
- comment: '查看版本',
743
+ comment: 'View version',
727
744
  exeFn: (args) => {
728
- console.log(require("../package.json").version)
745
+ CONSOLE.log(packageJson.version)
729
746
  },
730
747
  short: 'v'
731
748
  },
732
749
  list: {
733
- comment: '查看文件列表',
750
+ comment: 'View file list',
734
751
  exeFn: (args) => {
735
752
  if (args.length > 0) {
736
753
  _cmdMap = arrayToCmdMap(filterCmd(args.length > 0 ? args.join(' '):[',']))
@@ -738,22 +755,22 @@ const keywordDef = {
738
755
  listCmd()
739
756
  },
740
757
  args: {
741
- queryParams: '字符串匹配,[,]代表全部,关键字可以省略'
758
+ queryParams: 'string matching, [,] represents all, keywords can be omitted'
742
759
  },
743
760
  short: 'l'
744
761
  },
745
762
  clear: {
746
- comment: '清除任务',
763
+ comment: 'Clear task',
747
764
  exeFn: (args) => {
748
765
  delTipsByIndex(args.filter(i => i))
749
766
  },
750
767
  args: {
751
- tipIndex: '左侧提示符下标,可以多个用空格隔开'
768
+ tipIndex: 'left prompt index, can be separated by spaces for multiple'
752
769
  },
753
770
  short: 'C'
754
771
  },
755
772
  see: {
756
- comment: '查看文件',
773
+ comment: 'View file',
757
774
  exeFn: (args) => {
758
775
  let uniqueName = _cmdMap[args[0]]
759
776
  if (!uniqueName) {
@@ -761,16 +778,16 @@ const keywordDef = {
761
778
  } else {
762
779
  let path = getFullPath(uniqueName)
763
780
  let sourceStr = String(_fs.readFileSync(path))
764
- console.log(sourceStr)
781
+ CONSOLE.log(sourceStr)
765
782
  }
766
783
  },
767
784
  args: {
768
- fileIndex: '文件下标'
785
+ fileIndex: 'File index'
769
786
  },
770
787
  short: 's'
771
788
  },
772
789
  rm: {
773
- comment: '删除文件',
790
+ comment: 'Remove file',
774
791
  exeFn: (args) => {
775
792
  let uniqueName = _cmdMap[args[0]]
776
793
  if (args[0] === 'ALL') {
@@ -788,12 +805,12 @@ const keywordDef = {
788
805
  }
789
806
  },
790
807
  args: {
791
- fileIndex: '文件下标, ALL代表全部'
808
+ fileIndex: 'File index, [ALL] for all files'
792
809
  },
793
810
  short: 'R'
794
811
  },
795
812
  get: {
796
- comment: '获取文件',
813
+ comment: 'Get file',
797
814
  exeFn: (args) => {
798
815
  let uniqueName = _cmdMap[args[0]]
799
816
  if (args[0] === 'ALL') {
@@ -807,12 +824,12 @@ const keywordDef = {
807
824
  }
808
825
  },
809
826
  args: {
810
- fileIndex: '文件下标, ALL代表全部'
827
+ fileIndex: 'File index, [ALL] for all files'
811
828
  },
812
829
  short: 'g'
813
830
  },
814
831
  rename: {
815
- comment: '重命名文件',
832
+ comment: 'Rename file',
816
833
  exeFn: (args) => {
817
834
  let uniqueName = _cmdMap[args[0]]
818
835
  if (!uniqueName) {
@@ -824,13 +841,13 @@ const keywordDef = {
824
841
  }
825
842
  },
826
843
  args: {
827
- fileIndex: '文件下标',
828
- newName: '新名字'
844
+ fileIndex: 'File index',
845
+ newName: 'New name'
829
846
  },
830
847
  short: 'n'
831
848
  },
832
849
  edit: {
833
- comment: '编辑文件',
850
+ comment: 'Edit file',
834
851
  exeFn: async (args) => {
835
852
  let uniqueName = _cmdMap[args[0]]
836
853
  if (!uniqueName) {
@@ -841,12 +858,12 @@ const keywordDef = {
841
858
  }
842
859
  },
843
860
  args: {
844
- fileIndex: '文件下标'
861
+ fileIndex: 'File index'
845
862
  },
846
863
  short: 'e'
847
864
  },
848
865
  compare: {
849
- comment: '比较文件',
866
+ comment: 'Compare files',
850
867
  exeFn: async (args) => {
851
868
  let aUniqueName = _cmdMap[args[0]]
852
869
  let bUniqueName = _cmdMap[args[1]]
@@ -854,7 +871,7 @@ const keywordDef = {
854
871
  let bSpace = args[1]
855
872
 
856
873
  if (aUniqueName && bUniqueName) {
857
- await e(`idea diff "${getFullPath(aUniqueName)}" "${getFullPath(bUniqueName)}"`)
874
+ await e(`${getConfig("compareExe", "idea diff")} "${getFullPath(aUniqueName)}" "${getFullPath(bUniqueName)}"`)
858
875
  } else if (aSpace && bSpace) {
859
876
  if (!args[2]) {
860
877
  warn('require mode')
@@ -878,14 +895,14 @@ const keywordDef = {
878
895
  }
879
896
  },
880
897
  args: {
881
- a: '文件/工作空间',
882
- b: '文件/工作空间',
898
+ a: 'File/workspace',
899
+ b: 'File/workspace',
883
900
  mode: 'a=, b=, ab=, a+, b+, ab+'
884
901
  },
885
902
  short: 'c'
886
903
  },
887
904
  deps: {
888
- comment: '查看文件依赖',
905
+ comment: 'View file dependencies',
889
906
  exeFn: (args) => {
890
907
  let uniqueName = _cmdMap[args[0]]
891
908
  if (!uniqueName) {
@@ -909,12 +926,12 @@ const keywordDef = {
909
926
  }
910
927
  },
911
928
  args: {
912
- fileIndex: '文件下标'
929
+ fileIndex: 'File index'
913
930
  },
914
931
  short: 'd'
915
932
  },
916
933
  file: {
917
- comment: '工作文件模式',
934
+ comment: 'Working file mode',
918
935
  exeFn: async (args) => {
919
936
  if (args.length === 0) {
920
937
  await workFile('')
@@ -928,12 +945,12 @@ const keywordDef = {
928
945
  }
929
946
  },
930
947
  args: {
931
- fileIndex: '文件下标'
948
+ fileIndex: 'File index'
932
949
  },
933
950
  short: 'f'
934
951
  },
935
952
  workspace: {
936
- comment: '工作空间管理',
953
+ comment: 'Workspace Management',
937
954
  exeFn: async (args) => {
938
955
  let newWorkspace = args.join(' ')
939
956
  if (newWorkspace) {
@@ -950,15 +967,15 @@ const keywordDef = {
950
967
  path
951
968
  }
952
969
  })
953
- console.table(items)
970
+ CONSOLE.table(items)
954
971
  },
955
972
  args: {
956
- workspacePath: '新增工作空间路径'
973
+ workspacePath: 'New workspace path'
957
974
  },
958
975
  short: 'w'
959
976
  },
960
977
  uninstall: {
961
- comment: '卸载工作空间',
978
+ comment: 'Uninstall workspace',
962
979
  exeFn: async (args) => {
963
980
  let workspaces = Object.values($workspaceMap)
964
981
  let items = workspaces.map((path, index) => {
@@ -968,7 +985,7 @@ const keywordDef = {
968
985
  path
969
986
  }
970
987
  })
971
- console.table(items)
988
+ CONSOLE.table(items)
972
989
  let index = await nextLine(line => line, "index: ")
973
990
  let workspace = workspaces[index - 1]
974
991
  if (workspace) {
@@ -982,7 +999,7 @@ const keywordDef = {
982
999
  short: 'u'
983
1000
  },
984
1001
  switch: {
985
- comment: '切换工作空间',
1002
+ comment: 'Switch workspace',
986
1003
  exeFn: async (args) => {
987
1004
  checkWorkspaces()
988
1005
  let workspaces = Object.values($workspaceMap)
@@ -993,7 +1010,7 @@ const keywordDef = {
993
1010
  path
994
1011
  }
995
1012
  })
996
- console.table(items)
1013
+ CONSOLE.table(items)
997
1014
  let index = trim(await nextLine(line => line, "switch workspace: "));
998
1015
  if (index && workspaces[index - 1]) {
999
1016
  let workspace = workspaces[index - 1];
@@ -1005,54 +1022,76 @@ const keywordDef = {
1005
1022
  short: 'S'
1006
1023
  },
1007
1024
  add: {
1008
- comment: '新增文件',
1025
+ comment: 'Add file',
1009
1026
  exeFn: async (args) => {
1010
1027
  await save(args)
1011
1028
  },
1012
1029
  args: {
1013
- fileName: '文件名称(e可执行,i资源文件,f工作文件), 例:.add e test'
1030
+ fileName: 'File name (e for executable, i for resource file, f for working file), example: .add e test'
1014
1031
  },
1015
1032
  short: 'a'
1016
1033
  },
1017
1034
  run: {
1018
- comment: '快捷执行',
1035
+ comment: 'Quick execution',
1019
1036
  exeFn: async (args) => {
1020
1037
  if (!args[0]) {
1021
1038
  warn('invalid args')
1022
1039
  return
1023
1040
  }
1024
- let cmds = filterCmd('^e ' + toJsirFileName(args[0]).replace(/^[eif]\s+/, '') + '$')
1041
+ let pair = parseUniqueName(args[0])
1042
+ let cmds;
1043
+ if (/^0x[a-z\d]{8}$/.test(pair[1]) || pair[1].indexOf(",") !== -1) {
1044
+ cmds = getQuickRunCmds(args[0], args[0])
1045
+ } else {
1046
+ cmds = getQuickRunCmds(args[0], '^e ' + toJsirFileName(pair[1]) + '$')
1047
+ if (cmds.length === 0) {
1048
+ cmds = getQuickRunCmds(args[0], args[0])
1049
+ }
1050
+ }
1025
1051
  if (cmds.length === 1) {
1052
+ if (_noAppendNextLine) {
1053
+ listCmd(arrayToCmdMap(cmds))
1054
+ }
1026
1055
  await runCmd(args.slice(1).join(' '), cmds[0])
1056
+ } else {
1057
+ warn(cmds.length > 1 ? "multiple match" : "no match")
1027
1058
  }
1028
1059
  },
1029
1060
  args: {
1030
- fileNameReg: '文件名称匹配'
1061
+ fileNameReg: 'File name matching'
1031
1062
  },
1032
1063
  short: 'r'
1033
1064
  },
1034
1065
  quit: {
1035
- comment: '退出',
1066
+ comment: 'Exit',
1036
1067
  exeFn: (args) => {
1037
- console.log(infoStr("Bye!"))
1038
- _exit = true;
1068
+ delTips();
1069
+ CONSOLE.log(infoStr("Bye!"))
1039
1070
  process.exit(0)
1040
1071
  },
1041
1072
  short: 'q'
1042
1073
  },
1043
1074
  repl: {
1044
- comment: '交互式界面',
1075
+ comment: 'Interactive interface',
1045
1076
  exeFn: (args) => {
1046
1077
  _noAppendNextLine = false
1047
- console.log(warnStr("You can start with .help, use * to expand context"))
1048
- if (Object.keys(_cmdMap).length > 0) {
1049
- listCmd()
1050
- }
1078
+ _cmdMap = {}
1079
+ CONSOLE.log(warnStr("You can start with .help, use * to expand context"))
1051
1080
  },
1052
1081
  short: 'p'
1053
1082
  }
1054
1083
  }
1055
1084
 
1085
+ function getQuickRunCmds(input, matchStr) {
1086
+ let pair = parseUniqueName(input)
1087
+ if (pair[0]) {
1088
+ matchStr = pair[0] + '/' + matchStr;
1089
+ } else if (input.startsWith("/")) {
1090
+ matchStr = '/' + matchStr;
1091
+ }
1092
+ return filterCmd(matchStr).filter(i => parseUniqueName(i)[1].startsWith("e "))
1093
+ }
1094
+
1056
1095
  function preLoad(text, fnNameMatch, fn) {
1057
1096
  regEach(text, new RegExp(`${fnNameMatch}\\s*\\(([^()]+)\\)`, 'g'), r=> {
1058
1097
  let item = trim(r[1])
@@ -1104,7 +1143,7 @@ async function _dealKeyword(keyword, args) {
1104
1143
  }
1105
1144
  }
1106
1145
  if (unMatched) {
1107
- warn(`unknown keyword: ${keyword}`)
1146
+ await keywordDef.run.exeFn([keyword, ...args])
1108
1147
  }
1109
1148
  }
1110
1149
 
@@ -1180,7 +1219,7 @@ function getScriptRequires(uniqueName) {
1180
1219
  }
1181
1220
 
1182
1221
  function getComments(i, cmdName, text, cols = [], col) {
1183
- let docLines = [infoStr(getCmdMd5Key(parseUniqueName(cmdName)[1])) + " - " + infoStr(i)]
1222
+ let docLines = [getCmdMd5Key(parseUniqueName(cmdName)[1]) + " - " + i]
1184
1223
  text = trim(text)
1185
1224
  docLines.push(...getTextComments(text))
1186
1225
  let argDef = getArgDef(text)
@@ -1189,12 +1228,17 @@ function getComments(i, cmdName, text, cols = [], col) {
1189
1228
  docLines.push(...comments)
1190
1229
  }
1191
1230
  if (docLines.length > 0) {
1192
- col.doc = '- ' + infoStr(trim(docLines[0]))
1231
+ col.doc = '- ' + docLines[0]
1193
1232
  if (docLines.length > 1) {
1194
- for (let line of docLines.slice(1)) {
1195
- cols.push({
1196
- doc: ' ' + line
1197
- })
1233
+ cols.push({
1234
+ doc: ' ' + infoStr(docLines[1])
1235
+ })
1236
+ if (docLines.length > 2) {
1237
+ for (let line of docLines.slice(2)) {
1238
+ cols.push({
1239
+ doc: ' ' + line
1240
+ })
1241
+ }
1198
1242
  }
1199
1243
  }
1200
1244
  }
@@ -1327,7 +1371,7 @@ function getArgComments(argDef) {
1327
1371
  let aLine = []
1328
1372
  for (let k of keys) {
1329
1373
  let item = warnStr(k) + (argDef[k] ? ` <${argDef[k]}>`:'')
1330
- if ([...aLine, item].join(', ').length > 64) {
1374
+ if (aLine.length > 0 && [...aLine, item].join(', ').length > 64) {
1331
1375
  comments.push(aLine.join(", ") + ", ")
1332
1376
  aLine = []
1333
1377
  }
@@ -1392,7 +1436,8 @@ async function runCmd(str = '', uniqueName = '', text = '') {
1392
1436
  pair = [arg, oriArgs[i+1]]
1393
1437
  i++
1394
1438
  } else {
1395
- pair = [arg, null]
1439
+ // 只传参数名称,不传参数,使用翻译赋值为true
1440
+ pair = [arg, 'true ']
1396
1441
  }
1397
1442
  } else {
1398
1443
  pair = [null, arg]
@@ -1422,7 +1467,7 @@ async function runCmd(str = '', uniqueName = '', text = '') {
1422
1467
  for (let key of Object.keys(exactArgs)) {
1423
1468
  scriptArgs[key] = exactArgs[key]
1424
1469
  }
1425
- let exit = false
1470
+ let argAbsent = false
1426
1471
  let scriptArgKeys = Object.keys(scriptArgs);
1427
1472
  for(let name of argNames) {
1428
1473
  let defStr = argDef[name]
@@ -1436,15 +1481,15 @@ async function runCmd(str = '', uniqueName = '', text = '') {
1436
1481
  continue
1437
1482
  }
1438
1483
  if (scriptArgKeys.indexOf(name) === -1 || (reg && !reg.test(scriptArgs[name]))) {
1439
- exit = true
1484
+ argAbsent = true
1440
1485
  warn(`require ${warnStr(name)}` + (defStr ? ` <${defStr}>`:''))
1441
1486
  }
1442
1487
  }
1443
- if (exit) {
1488
+ if (argAbsent) {
1444
1489
  throw 'invalid args';
1445
1490
  }
1446
1491
 
1447
- process.argv = [process.argv[0], path, ...scriptArgs]
1492
+ process.argv = [process.argv[0], path, ...(scriptArgs.map(String))]
1448
1493
  return await evalText(text, uniqueName, scriptArgs)
1449
1494
  }
1450
1495
 
@@ -1514,9 +1559,7 @@ function getArgDef(text) {
1514
1559
  }
1515
1560
 
1516
1561
  function setTips(key, value, onRm) {
1517
- let vals = getOr(global.$tips, key, []);
1518
- vals.push(value)
1519
- global.$tips[key] = [...new Set(vals)]
1562
+ getOr(global.$tips, key, []).push(value);
1520
1563
  if (onRm) {
1521
1564
  getOr(_tipsOnRm, key, []).push(onRm)
1522
1565
  }
@@ -1656,7 +1699,6 @@ async function evalText($text = '', $cmdName = '', $args = []) {
1656
1699
  setTips, delTips,
1657
1700
  wrapperInput, filterCmd,
1658
1701
  currSpace,
1659
- $log, $draft,
1660
1702
  $homeDir, $lib)
1661
1703
  } catch(e) {
1662
1704
  throw errorTag(e, $cmdName);
@@ -1677,14 +1719,17 @@ process.on('rejectionHandled',function(err){
1677
1719
  })
1678
1720
  process.on('SIGINT', function () {
1679
1721
  if (_noAppendNextLine) {
1680
- process.exit();
1722
+ delTips();
1723
+ process.exit(0);
1681
1724
  } else {
1682
1725
  nextLine();
1683
1726
  }
1684
1727
  });
1685
1728
  process.on('beforeExit', function () {
1686
- if (!_exit) {
1687
- _noAppendNextLine || nextLine();
1729
+ if (_noAppendNextLine) {
1730
+ delTips();
1731
+ } else {
1732
+ nextLine();
1688
1733
  }
1689
1734
  });
1690
1735
 
package/deps/evalCode.js CHANGED
@@ -1,4 +1,4 @@
1
- const {info: $info, msg: $msg, warn: $warn, error: $error, importG: $import} = require("./util");
1
+ const {info: $info, msg: $msg, warn: $warn, error: $error, importG: $import, $log, $draft} = require("./util");
2
2
  require = require("./util").requireG
3
3
  module.exports = async ($text = '', $cmdName = '', $args = [],
4
4
  $data, $config,
@@ -7,7 +7,6 @@ module.exports = async ($text = '', $cmdName = '', $args = [],
7
7
  $setTips, $delTips,
8
8
  $enter, $filterCmd,
9
9
  $currentSpace,
10
- $log, $draft,
11
10
  $homeDir, $lib) => {
12
11
  const $defArgs = () => $args;
13
12
  const $context = {
@@ -0,0 +1,25 @@
1
+ module.exports = {
2
+ exeFile: `/*
3
+ A test exe script
4
+ */
5
+
6
+ $defArgs({
7
+ arg: 'required argument',
8
+ _arg: 'optional argument'
9
+ })
10
+
11
+ let {} = $lib // Reference to built-in resources
12
+
13
+ console.log($args)
14
+
15
+ return {}
16
+ `,
17
+ initFile: `/*
18
+ A test init script
19
+ */
20
+
21
+ let {} = $lib // Reference to built-in resources
22
+
23
+ return {}
24
+ `
25
+ }
package/deps/util.js CHANGED
@@ -13,6 +13,7 @@ const globalDirectories = require('global-dirs');
13
13
  const emptyFn = ()=>{}
14
14
  const dayJs = require('dayjs')
15
15
  const table = require('console.table')
16
+ const {log: _log} = console;
16
17
  const _fs = require("fs");
17
18
  if (module.paths.indexOf(globalDirectories.npm.packages) === -1) {
18
19
  module.paths.push(globalDirectories.npm.packages)
@@ -126,10 +127,10 @@ function nableStr(rows) {
126
127
  return tableStr(wrapRows(rows))
127
128
  }
128
129
  console.table = (...args) => {
129
- console.log(tableStr(...args))
130
+ _log(tableStr(...args))
130
131
  }
131
132
  console.nable = (rows) => {
132
- console.log(nableStr(rows))
133
+ _log(nableStr(rows))
133
134
  }
134
135
 
135
136
  function timeStr(fmt, date) {
@@ -344,7 +345,7 @@ function requireG(moduleName){
344
345
  } catch (e) {}
345
346
  let path = globalDirectories.npm.packages + '/' + moduleName;
346
347
  if (!fs.existsSync(path)) {
347
- console.log(warnStr(`npm install -g ${moduleName}`))
348
+ _log(warnStr(`npm install -g ${moduleName}`))
348
349
  throw `${moduleName} not found, use above cmd to install it`;
349
350
  }
350
351
  return require(path);
@@ -359,7 +360,7 @@ async function importG(moduleName) {
359
360
  } catch (e) {}
360
361
  let path = globalDirectories.npm.packages + '/' + moduleName;
361
362
  if (!fs.existsSync(path)) {
362
- console.log(warnStr(`npm install -g ${moduleName}`))
363
+ _log(warnStr(`npm install -g ${moduleName}`))
363
364
  throw `${moduleName} not found, use above cmd to install it`;
364
365
  }
365
366
  return await import(path);
@@ -888,50 +889,97 @@ function strEq(a, b) {
888
889
 
889
890
  function wrapRows(rows) {
890
891
  let newRows = []
892
+ // 构建新的数组
891
893
  for(let row of rows) {
892
894
  let temp = []
893
895
  for(let key of Object.keys(row)) {
894
896
  let val = row[key]
895
- if (getType(val) !== "String") {
897
+ if (typeof val === 'number') {
898
+ let r = getOr(temp, 0, {})
899
+ r[key] = val;
900
+ continue;
901
+ }
902
+ if (typeof val !== "string") {
896
903
  val = JSON.stringify(val, null, 2)
897
904
  }
905
+
906
+ let r = getOr(temp, 0, {})
907
+ r[key] = val;
908
+ }
909
+ newRows.push(...temp)
910
+ }
911
+
912
+ // 排序
913
+ if (newRows.length > 0) {
914
+ newRows.sort((a,b) => {
915
+ for (let key of Object.keys(newRows[0])) {
916
+ if (a[key] < b[key]) {
917
+ return -1;
918
+ } else if (a[key] > b[key]) {
919
+ return 1;
920
+ }
921
+ }
922
+ return 0;
923
+ })
924
+ let keyMap = {}
925
+ for (let newRow of newRows) {
926
+ let lastKey
927
+ for (let key of Object.keys(newRows[0])) {
928
+ if (keyMap[key] === newRow[key]) {
929
+ if (!lastKey || newRow[lastKey] === ' - ') {
930
+ newRow[key] = ' - '
931
+ }
932
+ } else {
933
+ keyMap[key] = newRow[key]
934
+ }
935
+ lastKey = key;
936
+ }
937
+ }
938
+ }
939
+
940
+ // 换行处理
941
+ let result = []
942
+ for(let row of newRows) {
943
+ let temp = []
944
+ for(let key of Object.keys(row)) {
945
+ let val = row[key]
898
946
  let items = String(val).split('\n')
899
947
  for(let i = 0; i<items.length; i++) {
900
948
  let r = getOr(temp, i, {})
901
949
  r[key] = items[i]
902
950
  }
903
951
  }
904
- newRows.push(...temp)
952
+ result.push(...temp)
905
953
  }
906
- return newRows
954
+ return result
907
955
  }
908
956
 
909
- function info(msg) {
957
+ function info(msg, _console = console) {
910
958
  if (typeof msg === 'string' && msg && msg.indexOf('\n') === -1) {
911
959
  msg = infoStr(msg)
912
960
  }
913
- console.log(infoStr('[info]'), msg)
961
+ _console.log(infoStr('[info]'), msg)
914
962
  }
915
963
 
916
- function msg(msg) {
964
+ function msg(msg, _console = console) {
917
965
  if (typeof msg === 'string' && msg && msg.indexOf('\n') === -1) {
918
966
  msg = msgStr(msg)
919
967
  }
920
- console.log(msgStr('[msg]'), msg)
968
+ _console.log(msgStr('[msg]'), msg)
921
969
  }
922
970
 
923
- function warn(msg) {
971
+ function warn(msg, _console = console) {
924
972
  if (typeof msg === 'string' && msg && msg.indexOf('\n') === -1) {
925
973
  msg = warnStr(msg)
926
974
  }
927
- console.warn(warnStr('[warn]'), msg)
975
+ _console.warn(warnStr('[warn]'), msg)
928
976
  }
929
977
 
930
- function error(msg, tag) {
978
+ function error(msg, tag, _console = console) {
931
979
  if (typeof msg === 'string' && msg && msg.indexOf('\n') === -1) {
932
980
  msg = errorStr(msg)
933
981
  }
934
- console.error(errorStr(`[${tag || 'error'}]`), msg)
982
+ _console.error(errorStr(`[${tag || 'error'}]`), msg)
935
983
  }
936
984
 
937
985
  function infoStr(str) {
@@ -1126,7 +1174,6 @@ function errorTag(e, tag) {
1126
1174
  function getTextComments(text) {
1127
1175
  let results = []
1128
1176
  text = text.replace(/\r/g, '\n')
1129
- text = text.replace(/\n+/g, '\n')
1130
1177
  let lines = text.split(/\n/);
1131
1178
 
1132
1179
  if (text.startsWith("/*")) {
@@ -1144,17 +1191,14 @@ function getTextComments(text) {
1144
1191
  results.push(line)
1145
1192
  }
1146
1193
  } else {
1147
- for (let key of ['#', '/', '-', ';']) {
1148
- if (!text.startsWith(key)) {
1149
- continue
1150
- }
1194
+ let firstReg = /^[#/\-;]+/;
1195
+ if (firstReg.test(text)) {
1151
1196
  for (let line of lines) {
1152
1197
  let trimLine = trim(line)
1153
1198
  if (!trimLine) {
1154
- continue
1199
+ break
1155
1200
  }
1156
- if (trimLine.startsWith(key)) {
1157
- let line = trimLine.replace(new RegExp(`^[${key}]+`), '');
1201
+ if (firstReg.test(trimLine)) {
1158
1202
  if (trim(line)) {
1159
1203
  results.push(line)
1160
1204
  }
package/index.js CHANGED
@@ -1,4 +0,0 @@
1
-
2
- module.exports = {
3
- ...require('deps/util')
4
- }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jsir",
3
- "version": "2.1.4",
4
- "description": "js script manager tool",
3
+ "version": "2.1.6",
4
+ "description": "JavaScript Script Management Tool",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "cmd/oaa.js"
@@ -9,7 +9,12 @@
9
9
  "bin": {
10
10
  "jsir": "cmd/oaa.js"
11
11
  },
12
- "keywords": [],
12
+ "keywords": [
13
+ "javascript",
14
+ "scripts",
15
+ "manager",
16
+ "executor"
17
+ ],
13
18
  "author": "",
14
19
  "license": "ISC",
15
20
  "dependencies": {