spyne-cli 0.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.
Files changed (70) hide show
  1. package/README.md +3 -0
  2. package/index-cli.js +56 -0
  3. package/index.js +14 -0
  4. package/lib/ansi.js +116 -0
  5. package/lib/combos.js +75 -0
  6. package/lib/completer.js +52 -0
  7. package/lib/interpolate.js +266 -0
  8. package/lib/keypress.js +243 -0
  9. package/lib/placeholder.js +63 -0
  10. package/lib/prompt.js +485 -0
  11. package/lib/prompts/autocomplete.js +113 -0
  12. package/lib/prompts/basicauth.js +41 -0
  13. package/lib/prompts/confirm.js +13 -0
  14. package/lib/prompts/editable.js +136 -0
  15. package/lib/prompts/form.js +196 -0
  16. package/lib/prompts/index.js +28 -0
  17. package/lib/prompts/input.js +55 -0
  18. package/lib/prompts/invisible.js +11 -0
  19. package/lib/prompts/list.js +36 -0
  20. package/lib/prompts/multiselect.js +11 -0
  21. package/lib/prompts/numeral.js +1 -0
  22. package/lib/prompts/password.js +18 -0
  23. package/lib/prompts/quiz.js +37 -0
  24. package/lib/prompts/scale.js +237 -0
  25. package/lib/prompts/select.js +139 -0
  26. package/lib/prompts/snippet.js +185 -0
  27. package/lib/prompts/sort.js +37 -0
  28. package/lib/prompts/survey.js +163 -0
  29. package/lib/prompts/text.js +1 -0
  30. package/lib/prompts/toggle.js +109 -0
  31. package/lib/render.js +33 -0
  32. package/lib/roles.js +46 -0
  33. package/lib/state.js +69 -0
  34. package/lib/styles.js +144 -0
  35. package/lib/symbols.js +66 -0
  36. package/lib/theme.js +11 -0
  37. package/lib/timer.js +38 -0
  38. package/lib/types/array.js +658 -0
  39. package/lib/types/auth.js +29 -0
  40. package/lib/types/boolean.js +88 -0
  41. package/lib/types/index.js +7 -0
  42. package/lib/types/number.js +86 -0
  43. package/lib/types/string.js +185 -0
  44. package/lib/utils.js +268 -0
  45. package/package.json +45 -0
  46. package/src/app/channels/.gitkeep +0 -0
  47. package/src/app/components/.gitkeep +0 -0
  48. package/src/app/traits/.gitkeep +0 -0
  49. package/src/spyne-file-prompt.js +63 -0
  50. package/src/spyne-template-prompts.js +171 -0
  51. package/src/templates/generate-file-string.js +131 -0
  52. package/src/templates/generate-prompt-input-fields.js +256 -0
  53. package/src/templates/generate-prompt-input-object.js +46 -0
  54. package/src/templates/generate-prompt-output.js +109 -0
  55. package/src/ui.js +16 -0
  56. package/src/utils/color-utils.js +36 -0
  57. package/src/utils/error-logger.js +15 -0
  58. package/src/utils/file-utils.js +69 -0
  59. package/tests/generate-file-prompt.test.js +47 -0
  60. package/tests/generate-file-string.test.js +68 -0
  61. package/tests/generate-prompt-input-fields-methods.test.js +178 -0
  62. package/tests/generate-prompt-input-fields.test.js +181 -0
  63. package/tests/generate-prompt-input-object.test.js +41 -0
  64. package/tests/generate-prompt-output.test.js +60 -0
  65. package/tests/index.test.js +13 -0
  66. package/tests/mocks/answers.js +33 -0
  67. package/tests/mocks/answers.json +33 -0
  68. package/tests/mocks/enquirer-data.js +411 -0
  69. package/tests/mocks/enquirer-data.json +409 -0
  70. package/tests/utils/file-utils.test.js +70 -0
@@ -0,0 +1,243 @@
1
+ 'use strict';
2
+
3
+ const readline = require('readline');
4
+ const combos = require('./combos');
5
+
6
+ /* eslint-disable no-control-regex */
7
+ const metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
8
+ const fnKeyRe = /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
9
+ const keyName = {
10
+ /* xterm/gnome ESC O letter */
11
+ 'OP': 'f1',
12
+ 'OQ': 'f2',
13
+ 'OR': 'f3',
14
+ 'OS': 'f4',
15
+ /* xterm/rxvt ESC [ number ~ */
16
+ '[11~': 'f1',
17
+ '[12~': 'f2',
18
+ '[13~': 'f3',
19
+ '[14~': 'f4',
20
+ /* from Cygwin and used in libuv */
21
+ '[[A': 'f1',
22
+ '[[B': 'f2',
23
+ '[[C': 'f3',
24
+ '[[D': 'f4',
25
+ '[[E': 'f5',
26
+ /* common */
27
+ '[15~': 'f5',
28
+ '[17~': 'f6',
29
+ '[18~': 'f7',
30
+ '[19~': 'f8',
31
+ '[20~': 'f9',
32
+ '[21~': 'f10',
33
+ '[23~': 'f11',
34
+ '[24~': 'f12',
35
+ /* xterm ESC [ letter */
36
+ '[A': 'up',
37
+ '[B': 'down',
38
+ '[C': 'right',
39
+ '[D': 'left',
40
+ '[E': 'clear',
41
+ '[F': 'end',
42
+ '[H': 'home',
43
+ /* xterm/gnome ESC O letter */
44
+ 'OA': 'up',
45
+ 'OB': 'down',
46
+ 'OC': 'right',
47
+ 'OD': 'left',
48
+ 'OE': 'clear',
49
+ 'OF': 'end',
50
+ 'OH': 'home',
51
+ /* xterm/rxvt ESC [ number ~ */
52
+ '[1~': 'home',
53
+ '[2~': 'insert',
54
+ '[3~': 'delete',
55
+ '[4~': 'end',
56
+ '[5~': 'pageup',
57
+ '[6~': 'pagedown',
58
+ /* putty */
59
+ '[[5~': 'pageup',
60
+ '[[6~': 'pagedown',
61
+ /* rxvt */
62
+ '[7~': 'home',
63
+ '[8~': 'end',
64
+ /* rxvt keys with modifiers */
65
+ '[a': 'up',
66
+ '[b': 'down',
67
+ '[c': 'right',
68
+ '[d': 'left',
69
+ '[e': 'clear',
70
+
71
+ '[2$': 'insert',
72
+ '[3$': 'delete',
73
+ '[5$': 'pageup',
74
+ '[6$': 'pagedown',
75
+ '[7$': 'home',
76
+ '[8$': 'end',
77
+
78
+ 'Oa': 'up',
79
+ 'Ob': 'down',
80
+ 'Oc': 'right',
81
+ 'Od': 'left',
82
+ 'Oe': 'clear',
83
+
84
+ '[2^': 'insert',
85
+ '[3^': 'delete',
86
+ '[5^': 'pageup',
87
+ '[6^': 'pagedown',
88
+ '[7^': 'home',
89
+ '[8^': 'end',
90
+ /* misc. */
91
+ '[Z': 'tab',
92
+ }
93
+
94
+ function isShiftKey(code) {
95
+ return ['[a', '[b', '[c', '[d', '[e', '[2$', '[3$', '[5$', '[6$', '[7$', '[8$', '[Z'].includes(code)
96
+ }
97
+
98
+ function isCtrlKey(code) {
99
+ return [ 'Oa', 'Ob', 'Oc', 'Od', 'Oe', '[2^', '[3^', '[5^', '[6^', '[7^', '[8^'].includes(code)
100
+ }
101
+
102
+ const keypress = (s = '', event = {}) => {
103
+ let parts;
104
+ let key = {
105
+ name: event.name,
106
+ ctrl: false,
107
+ meta: false,
108
+ shift: false,
109
+ option: false,
110
+ sequence: s,
111
+ raw: s,
112
+ ...event
113
+ };
114
+
115
+ if (Buffer.isBuffer(s)) {
116
+ if (s[0] > 127 && s[1] === void 0) {
117
+ s[0] -= 128;
118
+ s = '\x1b' + String(s);
119
+ } else {
120
+ s = String(s);
121
+ }
122
+ } else if (s !== void 0 && typeof s !== 'string') {
123
+ s = String(s);
124
+ } else if (!s) {
125
+ s = key.sequence || '';
126
+ }
127
+
128
+ key.sequence = key.sequence || s || key.name;
129
+
130
+ if (s === '\r') {
131
+ // carriage return
132
+ key.raw = void 0;
133
+ key.name = 'return';
134
+ } else if (s === '\n') {
135
+ // enter, should have been called linefeed
136
+ key.name = 'enter';
137
+ } else if (s === '\t') {
138
+ // tab
139
+ key.name = 'tab';
140
+ } else if (s === '\b' || s === '\x7f' || s === '\x1b\x7f' || s === '\x1b\b') {
141
+ // backspace or ctrl+h
142
+ key.name = 'backspace';
143
+ key.meta = s.charAt(0) === '\x1b';
144
+ } else if (s === '\x1b' || s === '\x1b\x1b') {
145
+ // escape key
146
+ key.name = 'escape';
147
+ key.meta = s.length === 2;
148
+ } else if (s === ' ' || s === '\x1b ') {
149
+ key.name = 'space';
150
+ key.meta = s.length === 2;
151
+ } else if (s <= '\x1a') {
152
+ // ctrl+letter
153
+ key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1);
154
+ key.ctrl = true;
155
+ } else if (s.length === 1 && s >= '0' && s <= '9') {
156
+ // number
157
+ key.name = 'number';
158
+ } else if (s.length === 1 && s >= 'a' && s <= 'z') {
159
+ // lowercase letter
160
+ key.name = s;
161
+ } else if (s.length === 1 && s >= 'A' && s <= 'Z') {
162
+ // shift+letter
163
+ key.name = s.toLowerCase();
164
+ key.shift = true;
165
+ } else if ((parts = metaKeyCodeRe.exec(s))) {
166
+ // meta+character key
167
+ key.meta = true;
168
+ key.shift = /^[A-Z]$/.test(parts[1]);
169
+ } else if ((parts = fnKeyRe.exec(s))) {
170
+ let segs = [...s];
171
+
172
+ if (segs[0] === '\u001b' && segs[1] === '\u001b') {
173
+ key.option = true;
174
+ }
175
+
176
+ // ansi escape sequence
177
+ // reassemble the key code leaving out leading \x1b's,
178
+ // the modifier key bitflag and any meaningless "1;" sequence
179
+ let code = [parts[1], parts[2], parts[4], parts[6]].filter(Boolean).join('');
180
+ let modifier = (parts[3] || parts[5] || 1) - 1;
181
+
182
+ // Parse the key modifier
183
+ key.ctrl = !!(modifier & 4);
184
+ key.meta = !!(modifier & 10);
185
+ key.shift = !!(modifier & 1);
186
+ key.code = code;
187
+
188
+ key.name = keyName[code];
189
+ key.shift = isShiftKey(code) || key.shift;
190
+ key.ctrl = isCtrlKey(code) || key.ctrl;
191
+ }
192
+ return key;
193
+ };
194
+
195
+ keypress.listen = (options = {}, onKeypress) => {
196
+ let { stdin } = options;
197
+
198
+ if (!stdin || (stdin !== process.stdin && !stdin.isTTY)) {
199
+ throw new Error('Invalid stream passed');
200
+ }
201
+
202
+ let rl = readline.createInterface({ terminal: true, input: stdin });
203
+ readline.emitKeypressEvents(stdin, rl);
204
+
205
+ let on = (buf, key) => onKeypress(buf, keypress(buf, key), rl);
206
+ let isRaw = stdin.isRaw;
207
+
208
+ if (stdin.isTTY) stdin.setRawMode(true);
209
+ stdin.on('keypress', on);
210
+ rl.resume();
211
+
212
+ let off = () => {
213
+ if (stdin.isTTY) stdin.setRawMode(isRaw);
214
+ stdin.removeListener('keypress', on);
215
+ rl.pause();
216
+ rl.close();
217
+ };
218
+
219
+ return off;
220
+ };
221
+
222
+ keypress.action = (buf, key, customActions) => {
223
+ let obj = { ...combos, ...customActions };
224
+ if (key.ctrl) {
225
+ key.action = obj.ctrl[key.name];
226
+ return key;
227
+ }
228
+
229
+ if (key.option && obj.option) {
230
+ key.action = obj.option[key.name];
231
+ return key;
232
+ }
233
+
234
+ if (key.shift) {
235
+ key.action = obj.shift[key.name];
236
+ return key;
237
+ }
238
+
239
+ key.action = obj.keys[key.name];
240
+ return key;
241
+ };
242
+
243
+ module.exports = keypress;
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ const utils = require('./utils');
4
+
5
+ /**
6
+ * Render a placeholder value with cursor and styling based on the
7
+ * position of the cursor.
8
+ *
9
+ * @param {Object} `prompt` Prompt instance.
10
+ * @param {String} `input` Input string.
11
+ * @param {String} `initial` The initial user-provided value.
12
+ * @param {Number} `pos` Current cursor position.
13
+ * @param {Boolean} `showCursor` Render a simulated cursor using the inverse primary style.
14
+ * @return {String} Returns the styled placeholder string.
15
+ * @api public
16
+ */
17
+
18
+ module.exports = (prompt, options = {}) => {
19
+ prompt.cursorHide();
20
+
21
+ let { input = '', initial = '', pos, showCursor = true, color } = options;
22
+ let style = color || prompt.styles.placeholder;
23
+ let inverse = utils.inverse(prompt.styles.primary);
24
+ let blinker = str => inverse(prompt.styles.black(str));
25
+ let output = input;
26
+ let char = ' ';
27
+ let reverse = blinker(char);
28
+
29
+ if (prompt.blink && prompt.blink.off === true) {
30
+ blinker = str => str;
31
+ reverse = '';
32
+ }
33
+
34
+ if (showCursor && pos === 0 && initial === '' && input === '') {
35
+ return blinker(char);
36
+ }
37
+
38
+ if (showCursor && pos === 0 && (input === initial || input === '')) {
39
+ return blinker(initial[0]) + style(initial.slice(1));
40
+ }
41
+
42
+ initial = utils.isPrimitive(initial) ? `${initial}` : '';
43
+ input = utils.isPrimitive(input) ? `${input}` : '';
44
+
45
+ let placeholder = initial && initial.startsWith(input) && initial !== input;
46
+ let cursor = placeholder ? blinker(initial[input.length]) : reverse;
47
+
48
+ if (pos !== input.length && showCursor === true) {
49
+ output = input.slice(0, pos) + blinker(input[pos]) + input.slice(pos + 1);
50
+ cursor = '';
51
+ }
52
+
53
+ if (showCursor === false) {
54
+ cursor = '';
55
+ }
56
+
57
+ if (placeholder) {
58
+ let raw = prompt.styles.unstyle(output + cursor);
59
+ return output + cursor + style(initial.slice(raw.length));
60
+ }
61
+
62
+ return output + cursor;
63
+ };