@beauraines/rtm-cli 1.5.2

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 (51) hide show
  1. package/.github/FUNDING.yml +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +143 -0
  4. package/build.js +86 -0
  5. package/config.json +40 -0
  6. package/package.json +58 -0
  7. package/screens/ls.png +0 -0
  8. package/screens/lsd.png +0 -0
  9. package/screens/lsp.png +0 -0
  10. package/screens/planner.png +0 -0
  11. package/src/cli.js +434 -0
  12. package/src/cmd/add.js +100 -0
  13. package/src/cmd/addList.js +92 -0
  14. package/src/cmd/addTags.js +85 -0
  15. package/src/cmd/archiveList.js +78 -0
  16. package/src/cmd/comp.js +82 -0
  17. package/src/cmd/decPri.js +82 -0
  18. package/src/cmd/due.js +82 -0
  19. package/src/cmd/edit.js +82 -0
  20. package/src/cmd/incPri.js +82 -0
  21. package/src/cmd/lists.js +60 -0
  22. package/src/cmd/login.js +27 -0
  23. package/src/cmd/logout.js +31 -0
  24. package/src/cmd/ls.js +181 -0
  25. package/src/cmd/lsd.js +193 -0
  26. package/src/cmd/lsp.js +171 -0
  27. package/src/cmd/move.js +83 -0
  28. package/src/cmd/notes.js +150 -0
  29. package/src/cmd/planner.js +510 -0
  30. package/src/cmd/postpone.js +82 -0
  31. package/src/cmd/pri.js +82 -0
  32. package/src/cmd/remove.js +82 -0
  33. package/src/cmd/removeList.js +79 -0
  34. package/src/cmd/removeTags.js +85 -0
  35. package/src/cmd/renameList.js +80 -0
  36. package/src/cmd/reset.js +35 -0
  37. package/src/cmd/setUrl.js +99 -0
  38. package/src/cmd/tags.js +101 -0
  39. package/src/cmd/uncomp.js +82 -0
  40. package/src/cmd/url.js +92 -0
  41. package/src/cmd/whoami.js +36 -0
  42. package/src/interactive.js +65 -0
  43. package/src/utils/config.js +236 -0
  44. package/src/utils/filter.js +43 -0
  45. package/src/utils/finish.js +21 -0
  46. package/src/utils/index.js +10 -0
  47. package/src/utils/log.js +163 -0
  48. package/src/utils/login.js +69 -0
  49. package/src/utils/printIndicator.js +43 -0
  50. package/src/utils/prompt.js +126 -0
  51. package/src/utils/sort.js +283 -0
@@ -0,0 +1,163 @@
1
+ 'use strict';
2
+
3
+ const chalk = require('chalk');
4
+ const spinner = require('ora')();
5
+
6
+
7
+ /**
8
+ * Log the specified text
9
+ * @param {string} text The text to log
10
+ * @param {boolean} [newline=true] End the log with a newline
11
+ */
12
+ function log(text="", newline=true) {
13
+ let nl = newline ? '\n' : '';
14
+ process.stdout.write(text + nl);
15
+ }
16
+
17
+ /**
18
+ * Log the specified text as an Info block
19
+ * @param {string} text The text to log
20
+ * @param {boolean} [newline=true] End the log with a newline
21
+ */
22
+ log.info = function(text, newline=true) {
23
+ if ( _plain() ) {
24
+ return log(text, newline);
25
+ }
26
+
27
+ let nl = newline ? '\n' : '';
28
+ process.stdout.write(chalk.bgYellow.black(" " + text + " " + nl));
29
+ };
30
+
31
+
32
+ /**
33
+ * Log the specified text with the specified `chalk` style
34
+ * @param {string} text The text to log
35
+ * @param {string} [style=reset] The chalk style attributes (ex: bgYellow.black)
36
+ * @param {boolean} [newline=false] End the log with a newline
37
+ */
38
+ log.style = function(text, style, newline) {
39
+ if ( style === undefined && newline === undefined ) {
40
+ style = 'reset';
41
+ newline = false;
42
+ }
43
+ else if ( newline === undefined && typeof style === 'boolean' ) {
44
+ newline = style;
45
+ style = 'reset';
46
+ }
47
+ else if ( newline === undefined ) {
48
+ newline = false;
49
+ }
50
+
51
+ if ( _plain() ) {
52
+ return log(text, newline);
53
+ }
54
+
55
+ let nl = newline ? '\n' : '';
56
+ let ch = chalk;
57
+ let parts = style.split('.');
58
+ for ( let i = 0; i < parts.length; i++ ) {
59
+ let part = parts[i];
60
+ ch = ch[part];
61
+ }
62
+ process.stdout.write(ch(text + nl));
63
+ };
64
+
65
+
66
+ /**
67
+ * Log an Error: use the spinner fail function
68
+ * @param {string} text The text to log
69
+ */
70
+ log.error = function(text) {
71
+ log.spinner.error(text);
72
+ };
73
+
74
+
75
+ /**
76
+ * Spinner-related functions
77
+ * @type {{start: log.spinner.start, stop: log.spinner.stop, success: log.spinner.success, error: log.spinner.error}}
78
+ */
79
+ log.spinner = {
80
+
81
+ /**
82
+ * Start the spinner with the specified text
83
+ * @param {string} text The text to log
84
+ */
85
+ start: function(text) {
86
+ if ( !_plain() && _status() ) {
87
+ spinner.start(text);
88
+ }
89
+ },
90
+
91
+ /**
92
+ * Stop and clear the spinner
93
+ */
94
+ stop: function() {
95
+ if ( !_plain() && _status() ) {
96
+ spinner.stop();
97
+ }
98
+ },
99
+
100
+ /**
101
+ * Set the spinner as a success with the specified text
102
+ * @param {string} text The text to log
103
+ */
104
+ success: function(text) {
105
+ if ( _status() ) {
106
+ if ( !_plain() ) {
107
+ spinner.succeed(text);
108
+ }
109
+ else {
110
+ log("[ok] " + text);
111
+ }
112
+ }
113
+ },
114
+
115
+ /**
116
+ * Set the spinner as an error with the specified text
117
+ * @param {string} text The text to log
118
+ */
119
+ error: function(text) {
120
+ if ( _status() ) {
121
+ if ( !_plain() ) {
122
+ spinner.fail(text);
123
+ }
124
+ else {
125
+ log("[error] " + text);
126
+ }
127
+ }
128
+ },
129
+
130
+ /**
131
+ * Set the spinner as a warning with the specified text
132
+ * @param {string} text The text to log
133
+ */
134
+ warn: function(text) {
135
+ if ( _status() ) {
136
+ if ( !_plain() ) {
137
+ spinner.warn(text);
138
+ }
139
+ else {
140
+ log("[warning] " + text);
141
+ }
142
+ }
143
+ }
144
+
145
+ };
146
+
147
+
148
+ /**
149
+ * Check for a --plain flag
150
+ * @returns {boolean}
151
+ * @private
152
+ */
153
+ function _plain() {
154
+ return require('./config.js').get().plain;
155
+ }
156
+
157
+ function _status() {
158
+ return require('./config.js').get().status;
159
+ }
160
+
161
+
162
+
163
+ module.exports = log;
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ const cp = require('copy-paste');
4
+ const log = require('./log.js');
5
+ const finish = require('../utils/finish.js');
6
+
7
+
8
+ /**
9
+ * Start the Login Process.
10
+ *
11
+ * This will save the logged in user to a configuration file.
12
+ * @private
13
+ */
14
+ function login(callback) {
15
+ const config = require('./config.js');
16
+ let client = config.client;
17
+
18
+ log.info("Authorization Required:");
19
+
20
+ // Get the Auth URL
21
+ log.spinner.start('Getting Login URL...');
22
+ client.auth.getAuthUrl(function(err, url, frob) {
23
+ if ( err ) {
24
+ log.spinner.error('Could not get Login URL (' + err.msg + ')');
25
+ return finish();
26
+ }
27
+ log.spinner.stop();
28
+
29
+ // Copy URL to clipboard
30
+ cp.copy(url);
31
+
32
+ // Display the URL
33
+ log.style('Please open the following URL (');
34
+ log.style('copied to clipboard', 'bold.underline');
35
+ log.style(') and authorize RTM CLI:', true);
36
+ log.style(url, 'blue.underline', true);
37
+
38
+ // Wait for User Input
39
+ global._rl.question('Press [enter] when done: ', function() {
40
+ log.spinner.start('Logging In...');
41
+
42
+ // Get the Authorized User
43
+ client.auth.getAuthToken(frob, function(err, user) {
44
+ if ( err ) {
45
+ log.spinner.error('Could not Log In (' + err.msg + ')');
46
+ return finish();
47
+ }
48
+
49
+ // Display success
50
+ log.spinner.success('Logged in As: ' + user.username);
51
+
52
+ // Save the User to the config
53
+ config.saveUser(user);
54
+
55
+ // Return the User
56
+ if ( callback ) {
57
+ return callback(user);
58
+ }
59
+ else {
60
+ return finish();
61
+ }
62
+
63
+ });
64
+ });
65
+ });
66
+ }
67
+
68
+
69
+ module.exports = login;
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ const config = require('./config.js');
4
+ const log = require('./log.js');
5
+
6
+ /**
7
+ *
8
+ * @param {string} type note|url|recurring
9
+ * @param {object} task the task to print the indicator
10
+ * @param {string} style emoji|text
11
+ */
12
+ function printIndicator(type,task) {
13
+ let styles = config.get().styles;
14
+ let iconType = config.get().iconType;
15
+
16
+ let indicatorStyle = task.isCompleted ? styles.completed : styles[type];
17
+ let notesIndicator,urlIndicator,recurringIndicator,subTaskIndicator;
18
+ iconType = iconType || 'text'; // defaults to text if nothing included
19
+ switch (iconType) {
20
+ case 'emoji':
21
+ notesIndicator = '📓';
22
+ urlIndicator = '🔗';
23
+ recurringIndicator = '🔁';
24
+ subTaskIndicator = '⤴️ '
25
+ break;
26
+ case 'text':
27
+ default:
28
+ notesIndicator = '*';
29
+ urlIndicator = '+';
30
+ recurringIndicator = 'r';
31
+ subTaskIndicator = '(s) '
32
+ break;
33
+ }
34
+ let indicators = {
35
+ notes: notesIndicator,
36
+ url: urlIndicator,
37
+ recurring: recurringIndicator,
38
+ subtask: subTaskIndicator
39
+ }
40
+ log.style(indicators[type], indicatorStyle);
41
+ }
42
+
43
+ module.exports = printIndicator;
@@ -0,0 +1,126 @@
1
+ 'use strict';
2
+
3
+ const finish = require('./finish.js');
4
+ const log = require('./log.js');
5
+ const promptSync = require('prompt-sync')();
6
+
7
+ /**
8
+ * Prompt the User for a set of answers
9
+ * @param {string} prompt One or more prompts to question the User
10
+ * @param {function} callback Callback function(answers)
11
+ * @deprecated Use indexPrompt
12
+ instead
13
+ */
14
+ function prompt(prompt, callback) {
15
+
16
+ // Set callback
17
+ callback = arguments[arguments.length-1];
18
+
19
+ // Set prompts
20
+ let prompts = [];
21
+ for ( let i = 0; i < arguments.length-1; i++ ) {
22
+ prompts.push(arguments[i]);
23
+ }
24
+
25
+ // Start first prompt
26
+ log.style("[Enter a blank line when finished]", "dim", true);
27
+ _prompt(0, prompts, 0, [], callback);
28
+
29
+ }
30
+
31
+
32
+ /**
33
+ * Display the current prompt
34
+ * @param promptIndex Current prompt
35
+ * @param prompts Set of prompts
36
+ * @param answerIndex Current Answer
37
+ * @param answers Set of accumulated Answers
38
+ * @param callback Final Callback
39
+ * @private
40
+ */
41
+ function _prompt(promptIndex, prompts, answerIndex, answers, callback) {
42
+ global._rl.question(prompts[promptIndex] + " ", function(answer) {
43
+
44
+ // Return with the answers
45
+ if ( promptIndex === 0 && answer === '' ) {
46
+ return _finish(answers, prompts.length, callback);
47
+ }
48
+
49
+ // Keep prompting
50
+ else {
51
+
52
+ // Set Answer
53
+ if ( !answers[answerIndex] ) {
54
+ answers[answerIndex] = [];
55
+ }
56
+ answers[answerIndex][promptIndex] = answer;
57
+
58
+ // Next Prompt
59
+ if ( promptIndex < prompts.length - 1 ) {
60
+ promptIndex++;
61
+ _prompt(promptIndex, prompts, answerIndex, answers, callback);
62
+ }
63
+
64
+ // Next Answer
65
+ else {
66
+ answerIndex++;
67
+ _prompt(0, prompts, answerIndex, answers, callback);
68
+ }
69
+
70
+ }
71
+
72
+ });
73
+
74
+ }
75
+
76
+
77
+ /**
78
+ * Remove any incomplete answers. Then return to the final callback
79
+ * @param answers
80
+ * @param promptcount
81
+ * @param callback
82
+ * @private
83
+ */
84
+ function _finish(answers, promptcount, callback) {
85
+ let rtn = [];
86
+ for ( let i = 0; i < answers.length; i++ ) {
87
+ let answer = answers[i];
88
+ if ( answer.length === promptcount ) {
89
+ rtn.push(answer);
90
+ }
91
+ }
92
+ if ( rtn.length === 0 ) {
93
+ return finish();
94
+ }
95
+ else {
96
+ return callback(rtn);
97
+ }
98
+ }
99
+
100
+
101
+ /**
102
+ * Prompts user for integer input until they enter a blank line
103
+ * @param {string} Prompt text to display
104
+ * @returns {number[]} array of user input integers
105
+ */
106
+ function indexPrompt(text) {
107
+ let tasks = []
108
+ let n
109
+ log.style('[Enter a blank line when finished]', 'dim', true);
110
+ while ( n != '' ) {
111
+ n = promptSync(text)
112
+ if (parseInt(n) ) {
113
+ tasks.push(n)
114
+ } else if (n == '') {
115
+ break
116
+ } else {
117
+ log.style('Enter a task index number, please.','red',true)
118
+ }
119
+ }
120
+
121
+ return tasks
122
+
123
+ }
124
+
125
+
126
+ module.exports = {prompt,indexPrompt};
@@ -0,0 +1,283 @@
1
+ 'use strict';
2
+
3
+
4
+ module.exports = {
5
+
6
+
7
+ // ==== LIST SORTING FUNCTIONS ==== //
8
+
9
+ lists: {
10
+
11
+ /**
12
+ * Sort the RTM Lists by the rtm-api added index field
13
+ * @param {RTMList} a RTM List a
14
+ * @param {RTMList} b RTM List b
15
+ * @returns {number}
16
+ */
17
+ index: function(a, b) {
18
+ return a.index - b.index;
19
+ },
20
+
21
+
22
+ /**
23
+ * Sort the RTM Lists by the RTM List id
24
+ * @param {RTMList} a RTM List a
25
+ * @param {RTMList} b RTM List b
26
+ * @returns {number}
27
+ */
28
+ id: function(a, b) {
29
+ return a.id - b.id;
30
+ },
31
+
32
+
33
+ /**
34
+ * Sort the RTM Lists by the RTM List name
35
+ * @param {RTMList} a RTM List a
36
+ * @param {RTMList} b RTM List b
37
+ * @returns {number}
38
+ */
39
+ name: function(a, b) {
40
+ if ( a.name.toLowerCase() < b.name.toLowerCase() ) {
41
+ return -1;
42
+ }
43
+ else if ( a.name.toLowerCase() > b.name.toLowerCase() ) {
44
+ return 1;
45
+ }
46
+ else {
47
+ return 0;
48
+ }
49
+ }
50
+
51
+ },
52
+
53
+
54
+ // ==== TASK SORTING FUNCTIONS ==== //
55
+
56
+ tasks: {
57
+
58
+ /**
59
+ * Sort Tasks by Index
60
+ * @param a
61
+ * @param b
62
+ * @returns {number}
63
+ */
64
+ index: function(a, b) {
65
+ return a.index - b.index;
66
+ },
67
+
68
+ /**
69
+ * Sort Tasks By Priority: 1,2,3,0
70
+ * @param a
71
+ * @param b
72
+ * @returns {number}
73
+ * @private
74
+ */
75
+ priority: function(a, b) {
76
+ let ap = a.priority === 0 ? 4 : a.priority;
77
+ let bp = b.priority === 0 ? 4 : b.priority;
78
+
79
+ return ap - bp;
80
+ },
81
+
82
+ /**
83
+ * Sort by Task Due Date (no due date first)
84
+ * @param a
85
+ * @param b
86
+ */
87
+ due: function(a, b) {
88
+ if ( a.due && !b.due ) {
89
+ return 1;
90
+ }
91
+ else if ( !a.due && b.due ) {
92
+ return -1;
93
+ }
94
+ else if ( a.due < b.due ) {
95
+ return -1;
96
+ }
97
+ else if ( a.due > b.due ) {
98
+ return 1;
99
+ }
100
+ else {
101
+ return 0;
102
+ }
103
+ },
104
+
105
+ /**
106
+ * Sort by Task Due Date (no due date last)
107
+ * @param a
108
+ * @param b
109
+ */
110
+ dueLast: function(a, b) {
111
+ if ( a.due && !b.due ) {
112
+ return -1;
113
+ }
114
+ else if ( !a.due && b.due ) {
115
+ return 1;
116
+ }
117
+ else if ( a.due < b.due ) {
118
+ return -1;
119
+ }
120
+ else if ( a.due > b.due ) {
121
+ return 1;
122
+ }
123
+ else {
124
+ return 0;
125
+ }
126
+ },
127
+
128
+ /**
129
+ * Sort by task completed status: uncompleted, completed
130
+ * @param a
131
+ * @param b
132
+ * @returns {number}
133
+ */
134
+ completed: function(a, b) {
135
+ if ( a.isCompleted && !b.isCompleted ) {
136
+ return 1;
137
+ }
138
+ else if ( !a.isCompleted && b.isCompleted ) {
139
+ return -1;
140
+ }
141
+ else {
142
+ return 0;
143
+ }
144
+ },
145
+
146
+ /**
147
+ * Sort Tasks By List Name (case insensitive)
148
+ * @param a
149
+ * @param b
150
+ * @returns {number}
151
+ * @private
152
+ */
153
+ listName: function(a, b) {
154
+ if ( a._list && b._list ) {
155
+ if ( a._list.name.toLowerCase() < b._list.name.toLowerCase() ) {
156
+ return -1;
157
+ }
158
+ else if ( a._list.name.toLowerCase() > b._list.name.toLowerCase() ) {
159
+ return 1;
160
+ }
161
+ else {
162
+ return 0;
163
+ }
164
+ }
165
+ return 0;
166
+ },
167
+
168
+ /**
169
+ * Sort Tasks for `ls` display (list name, priority)
170
+ * @param a
171
+ * @param b
172
+ * @returns {number}
173
+ * @private
174
+ */
175
+ ls: function(a, b) {
176
+ let sort = require(__filename);
177
+
178
+ // Sort by list
179
+ let list = sort.tasks.listName(a, b);
180
+ if ( list === 0 ) {
181
+
182
+ // Sort by completed status
183
+ let comp = sort.tasks.completed(a, b);
184
+ if ( comp === 0 ) {
185
+
186
+ // Sort by priority
187
+ let pri = sort.tasks.priority(a, b);
188
+ if ( pri === 0 ) {
189
+
190
+ // Sort by Due date
191
+ return sort.tasks.dueLast(a, b);
192
+
193
+ }
194
+ else {
195
+ return pri;
196
+ }
197
+
198
+ }
199
+ else {
200
+ return comp;
201
+ }
202
+ }
203
+ else {
204
+ return list;
205
+ }
206
+ },
207
+
208
+ /**
209
+ * Sort tasks for `lsd` display (due date, priority, list name)
210
+ * @param a
211
+ * @param b
212
+ * @returns {number}
213
+ * @private
214
+ */
215
+ lsd: function(a, b) {
216
+ let sort = require(__filename);
217
+
218
+ // Sort by Due Date
219
+ let due = sort.tasks.dueLast(a, b);
220
+ if ( due === 0 ) {
221
+
222
+ // Sort by Completed Status
223
+ let comp = sort.tasks.completed(a, b);
224
+ if ( comp === 0 ) {
225
+
226
+ // Sort By Priority
227
+ let pri = sort.tasks.priority(a, b);
228
+ if ( pri === 0 ) {
229
+
230
+ // Sort by List Name
231
+ return sort.tasks.listName(a, b);
232
+
233
+ }
234
+ else {
235
+ return pri;
236
+ }
237
+
238
+ }
239
+ else {
240
+ return comp;
241
+ }
242
+
243
+ }
244
+ else {
245
+ return due;
246
+ }
247
+ },
248
+
249
+ /**
250
+ * Sort tasks for `lsp` display (priority, due date)
251
+ * @param a
252
+ * @param b
253
+ * @returns {*}
254
+ */
255
+ lsp: function(a, b) {
256
+ let sort = require(__filename);
257
+
258
+ // Sort by Completed Status
259
+ let comp = sort.tasks.completed(a, b);
260
+ if ( comp === 0 ) {
261
+
262
+ // Sort by Priority
263
+ let pri = sort.tasks.priority(a, b);
264
+ if ( pri === 0 ) {
265
+
266
+ // Sort by Due Date
267
+ return sort.tasks.dueLast(a, b);
268
+
269
+ }
270
+ else {
271
+ return pri;
272
+ }
273
+
274
+ }
275
+ else {
276
+ return comp;
277
+ }
278
+
279
+ }
280
+
281
+ }
282
+
283
+ };