@md2do/todoist 0.2.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/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +597 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/client.ts.html +694 -0
- package/coverage/coverage-final.json +4 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +146 -0
- package/coverage/index.ts.html +118 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/client.ts.html +694 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +146 -0
- package/coverage/lcov-report/index.ts.html +118 -0
- package/coverage/lcov-report/mapper.ts.html +760 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +523 -0
- package/coverage/mapper.ts.html +760 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/index.d.mts +121 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +318 -0
- package/dist/index.mjs +285 -0
- package/package.json +50 -0
- package/src/client.ts +203 -0
- package/src/index.ts +11 -0
- package/src/mapper.ts +225 -0
- package/tests/mapper.test.ts +283 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +25 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
TodoistClient: () => TodoistClient,
|
|
24
|
+
extractTaskContent: () => extractTaskContent,
|
|
25
|
+
formatTaskContent: () => formatTaskContent,
|
|
26
|
+
md2doToTodoist: () => md2doToTodoist,
|
|
27
|
+
md2doToTodoistPriority: () => md2doToTodoistPriority,
|
|
28
|
+
todoistToMd2do: () => todoistToMd2do,
|
|
29
|
+
todoistToMd2doPriority: () => todoistToMd2doPriority
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
|
|
33
|
+
// src/client.ts
|
|
34
|
+
var import_todoist_api_typescript = require("@doist/todoist-api-typescript");
|
|
35
|
+
var TodoistClient = class {
|
|
36
|
+
api;
|
|
37
|
+
constructor(config) {
|
|
38
|
+
this.api = new import_todoist_api_typescript.TodoistApi(config.apiToken);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get all active tasks
|
|
42
|
+
*/
|
|
43
|
+
async getTasks(options) {
|
|
44
|
+
try {
|
|
45
|
+
return await this.api.getTasks(options);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Failed to get tasks: ${error instanceof Error ? error.message : String(error)}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get a specific task by ID
|
|
54
|
+
*/
|
|
55
|
+
async getTask(taskId) {
|
|
56
|
+
try {
|
|
57
|
+
return await this.api.getTask(taskId);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Failed to get task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a new task
|
|
66
|
+
*/
|
|
67
|
+
async createTask(params) {
|
|
68
|
+
try {
|
|
69
|
+
return await this.api.addTask(params);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Failed to create task: ${error instanceof Error ? error.message : String(error)}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Update an existing task
|
|
78
|
+
*/
|
|
79
|
+
async updateTask(taskId, params) {
|
|
80
|
+
try {
|
|
81
|
+
return await this.api.updateTask(taskId, params);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Failed to update task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Complete a task
|
|
90
|
+
*/
|
|
91
|
+
async completeTask(taskId) {
|
|
92
|
+
try {
|
|
93
|
+
return await this.api.closeTask(taskId);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Failed to complete task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reopen a completed task
|
|
102
|
+
*/
|
|
103
|
+
async reopenTask(taskId) {
|
|
104
|
+
try {
|
|
105
|
+
return await this.api.reopenTask(taskId);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Failed to reopen task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Delete a task
|
|
114
|
+
*/
|
|
115
|
+
async deleteTask(taskId) {
|
|
116
|
+
try {
|
|
117
|
+
return await this.api.deleteTask(taskId);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Failed to delete task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get all projects
|
|
126
|
+
*/
|
|
127
|
+
async getProjects() {
|
|
128
|
+
try {
|
|
129
|
+
return await this.api.getProjects();
|
|
130
|
+
} catch (error) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`Failed to get projects: ${error instanceof Error ? error.message : String(error)}`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get a specific project by ID
|
|
138
|
+
*/
|
|
139
|
+
async getProject(projectId) {
|
|
140
|
+
try {
|
|
141
|
+
return await this.api.getProject(projectId);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Failed to get project ${projectId}: ${error instanceof Error ? error.message : String(error)}`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Find project by name
|
|
150
|
+
*/
|
|
151
|
+
async findProjectByName(name) {
|
|
152
|
+
const projects = await this.getProjects();
|
|
153
|
+
return projects.find((p) => p.name.toLowerCase() === name.toLowerCase()) ?? null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get all labels
|
|
157
|
+
*/
|
|
158
|
+
async getLabels() {
|
|
159
|
+
try {
|
|
160
|
+
return await this.api.getLabels();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Failed to get labels: ${error instanceof Error ? error.message : String(error)}`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Create a label if it doesn't exist
|
|
169
|
+
*/
|
|
170
|
+
async ensureLabel(name) {
|
|
171
|
+
const labels = await this.getLabels();
|
|
172
|
+
const existing = labels.find(
|
|
173
|
+
(l) => l.name.toLowerCase() === name.toLowerCase()
|
|
174
|
+
);
|
|
175
|
+
if (existing) {
|
|
176
|
+
return existing;
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
return await this.api.addLabel({ name });
|
|
180
|
+
} catch (error) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`Failed to create label ${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Test the API connection
|
|
188
|
+
*/
|
|
189
|
+
async test() {
|
|
190
|
+
try {
|
|
191
|
+
await this.getProjects();
|
|
192
|
+
return true;
|
|
193
|
+
} catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// src/mapper.ts
|
|
200
|
+
function md2doToTodoistPriority(priority) {
|
|
201
|
+
switch (priority) {
|
|
202
|
+
case "urgent":
|
|
203
|
+
return 4;
|
|
204
|
+
case "high":
|
|
205
|
+
return 3;
|
|
206
|
+
case "normal":
|
|
207
|
+
return 2;
|
|
208
|
+
case "low":
|
|
209
|
+
default:
|
|
210
|
+
return 1;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function todoistToMd2doPriority(priority) {
|
|
214
|
+
switch (priority) {
|
|
215
|
+
case 4:
|
|
216
|
+
return "urgent";
|
|
217
|
+
case 3:
|
|
218
|
+
return "high";
|
|
219
|
+
case 2:
|
|
220
|
+
return "normal";
|
|
221
|
+
case 1:
|
|
222
|
+
return "low";
|
|
223
|
+
default:
|
|
224
|
+
return void 0;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function extractTaskContent(text) {
|
|
228
|
+
return text.replace(/@\w+/g, "").replace(/!+/g, "").replace(/#\w+/g, "").replace(/\(\d{4}-\d{2}-\d{2}\)/g, "").replace(/\[todoist:\s*\d+\]/gi, "").replace(/\s+/g, " ").trim();
|
|
229
|
+
}
|
|
230
|
+
function formatTaskContent(content, options) {
|
|
231
|
+
let result = content;
|
|
232
|
+
if (options.assignee) {
|
|
233
|
+
result += ` @${options.assignee}`;
|
|
234
|
+
}
|
|
235
|
+
if (options.priority === "urgent") {
|
|
236
|
+
result += " !!!";
|
|
237
|
+
} else if (options.priority === "high") {
|
|
238
|
+
result += " !!";
|
|
239
|
+
} else if (options.priority === "normal") {
|
|
240
|
+
result += " !";
|
|
241
|
+
}
|
|
242
|
+
if (options.tags && options.tags.length > 0) {
|
|
243
|
+
result += " " + options.tags.map((tag) => `#${tag}`).join(" ");
|
|
244
|
+
}
|
|
245
|
+
if (options.due) {
|
|
246
|
+
const year = options.due.getUTCFullYear();
|
|
247
|
+
const month = String(options.due.getUTCMonth() + 1).padStart(2, "0");
|
|
248
|
+
const day = String(options.due.getUTCDate()).padStart(2, "0");
|
|
249
|
+
result += ` (${year}-${month}-${day})`;
|
|
250
|
+
}
|
|
251
|
+
if (options.todoistId) {
|
|
252
|
+
result += ` [todoist:${options.todoistId}]`;
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
function md2doToTodoist(task, projectId) {
|
|
257
|
+
const params = {
|
|
258
|
+
content: extractTaskContent(task.text),
|
|
259
|
+
priority: md2doToTodoistPriority(task.priority)
|
|
260
|
+
};
|
|
261
|
+
if (task.tags && task.tags.length > 0) {
|
|
262
|
+
params.labels = task.tags;
|
|
263
|
+
}
|
|
264
|
+
if (task.dueDate) {
|
|
265
|
+
const year = task.dueDate.getUTCFullYear();
|
|
266
|
+
const month = String(task.dueDate.getUTCMonth() + 1).padStart(2, "0");
|
|
267
|
+
const day = String(task.dueDate.getUTCDate()).padStart(2, "0");
|
|
268
|
+
params.due_date = `${year}-${month}-${day}`;
|
|
269
|
+
}
|
|
270
|
+
if (projectId) {
|
|
271
|
+
params.project_id = projectId;
|
|
272
|
+
}
|
|
273
|
+
return params;
|
|
274
|
+
}
|
|
275
|
+
function todoistToMd2do(todoistTask, assignee) {
|
|
276
|
+
const priority = todoistToMd2doPriority(todoistTask.priority);
|
|
277
|
+
const due = todoistTask.due?.date ? /* @__PURE__ */ new Date(`${todoistTask.due.date}T00:00:00.000Z`) : void 0;
|
|
278
|
+
const formatOptions = {
|
|
279
|
+
todoistId: todoistTask.id
|
|
280
|
+
};
|
|
281
|
+
if (assignee !== void 0) {
|
|
282
|
+
formatOptions.assignee = assignee;
|
|
283
|
+
}
|
|
284
|
+
if (priority !== void 0) {
|
|
285
|
+
formatOptions.priority = priority;
|
|
286
|
+
}
|
|
287
|
+
if (todoistTask.labels.length > 0) {
|
|
288
|
+
formatOptions.tags = todoistTask.labels;
|
|
289
|
+
}
|
|
290
|
+
if (due !== void 0) {
|
|
291
|
+
formatOptions.due = due;
|
|
292
|
+
}
|
|
293
|
+
const update = {
|
|
294
|
+
text: formatTaskContent(todoistTask.content, formatOptions),
|
|
295
|
+
completed: todoistTask.isCompleted ?? false,
|
|
296
|
+
todoistId: todoistTask.id
|
|
297
|
+
};
|
|
298
|
+
if (priority !== void 0) {
|
|
299
|
+
update.priority = priority;
|
|
300
|
+
}
|
|
301
|
+
if (todoistTask.labels.length > 0) {
|
|
302
|
+
update.tags = todoistTask.labels;
|
|
303
|
+
}
|
|
304
|
+
if (due !== void 0) {
|
|
305
|
+
update.due = due;
|
|
306
|
+
}
|
|
307
|
+
return update;
|
|
308
|
+
}
|
|
309
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
310
|
+
0 && (module.exports = {
|
|
311
|
+
TodoistClient,
|
|
312
|
+
extractTaskContent,
|
|
313
|
+
formatTaskContent,
|
|
314
|
+
md2doToTodoist,
|
|
315
|
+
md2doToTodoistPriority,
|
|
316
|
+
todoistToMd2do,
|
|
317
|
+
todoistToMd2doPriority
|
|
318
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import { TodoistApi } from "@doist/todoist-api-typescript";
|
|
3
|
+
var TodoistClient = class {
|
|
4
|
+
api;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.api = new TodoistApi(config.apiToken);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Get all active tasks
|
|
10
|
+
*/
|
|
11
|
+
async getTasks(options) {
|
|
12
|
+
try {
|
|
13
|
+
return await this.api.getTasks(options);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Failed to get tasks: ${error instanceof Error ? error.message : String(error)}`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get a specific task by ID
|
|
22
|
+
*/
|
|
23
|
+
async getTask(taskId) {
|
|
24
|
+
try {
|
|
25
|
+
return await this.api.getTask(taskId);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Failed to get task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create a new task
|
|
34
|
+
*/
|
|
35
|
+
async createTask(params) {
|
|
36
|
+
try {
|
|
37
|
+
return await this.api.addTask(params);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`Failed to create task: ${error instanceof Error ? error.message : String(error)}`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Update an existing task
|
|
46
|
+
*/
|
|
47
|
+
async updateTask(taskId, params) {
|
|
48
|
+
try {
|
|
49
|
+
return await this.api.updateTask(taskId, params);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Failed to update task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Complete a task
|
|
58
|
+
*/
|
|
59
|
+
async completeTask(taskId) {
|
|
60
|
+
try {
|
|
61
|
+
return await this.api.closeTask(taskId);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Failed to complete task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Reopen a completed task
|
|
70
|
+
*/
|
|
71
|
+
async reopenTask(taskId) {
|
|
72
|
+
try {
|
|
73
|
+
return await this.api.reopenTask(taskId);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Failed to reopen task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Delete a task
|
|
82
|
+
*/
|
|
83
|
+
async deleteTask(taskId) {
|
|
84
|
+
try {
|
|
85
|
+
return await this.api.deleteTask(taskId);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Failed to delete task ${taskId}: ${error instanceof Error ? error.message : String(error)}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get all projects
|
|
94
|
+
*/
|
|
95
|
+
async getProjects() {
|
|
96
|
+
try {
|
|
97
|
+
return await this.api.getProjects();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Failed to get projects: ${error instanceof Error ? error.message : String(error)}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get a specific project by ID
|
|
106
|
+
*/
|
|
107
|
+
async getProject(projectId) {
|
|
108
|
+
try {
|
|
109
|
+
return await this.api.getProject(projectId);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
`Failed to get project ${projectId}: ${error instanceof Error ? error.message : String(error)}`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Find project by name
|
|
118
|
+
*/
|
|
119
|
+
async findProjectByName(name) {
|
|
120
|
+
const projects = await this.getProjects();
|
|
121
|
+
return projects.find((p) => p.name.toLowerCase() === name.toLowerCase()) ?? null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get all labels
|
|
125
|
+
*/
|
|
126
|
+
async getLabels() {
|
|
127
|
+
try {
|
|
128
|
+
return await this.api.getLabels();
|
|
129
|
+
} catch (error) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Failed to get labels: ${error instanceof Error ? error.message : String(error)}`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Create a label if it doesn't exist
|
|
137
|
+
*/
|
|
138
|
+
async ensureLabel(name) {
|
|
139
|
+
const labels = await this.getLabels();
|
|
140
|
+
const existing = labels.find(
|
|
141
|
+
(l) => l.name.toLowerCase() === name.toLowerCase()
|
|
142
|
+
);
|
|
143
|
+
if (existing) {
|
|
144
|
+
return existing;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
return await this.api.addLabel({ name });
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Failed to create label ${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Test the API connection
|
|
156
|
+
*/
|
|
157
|
+
async test() {
|
|
158
|
+
try {
|
|
159
|
+
await this.getProjects();
|
|
160
|
+
return true;
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// src/mapper.ts
|
|
168
|
+
function md2doToTodoistPriority(priority) {
|
|
169
|
+
switch (priority) {
|
|
170
|
+
case "urgent":
|
|
171
|
+
return 4;
|
|
172
|
+
case "high":
|
|
173
|
+
return 3;
|
|
174
|
+
case "normal":
|
|
175
|
+
return 2;
|
|
176
|
+
case "low":
|
|
177
|
+
default:
|
|
178
|
+
return 1;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function todoistToMd2doPriority(priority) {
|
|
182
|
+
switch (priority) {
|
|
183
|
+
case 4:
|
|
184
|
+
return "urgent";
|
|
185
|
+
case 3:
|
|
186
|
+
return "high";
|
|
187
|
+
case 2:
|
|
188
|
+
return "normal";
|
|
189
|
+
case 1:
|
|
190
|
+
return "low";
|
|
191
|
+
default:
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function extractTaskContent(text) {
|
|
196
|
+
return text.replace(/@\w+/g, "").replace(/!+/g, "").replace(/#\w+/g, "").replace(/\(\d{4}-\d{2}-\d{2}\)/g, "").replace(/\[todoist:\s*\d+\]/gi, "").replace(/\s+/g, " ").trim();
|
|
197
|
+
}
|
|
198
|
+
function formatTaskContent(content, options) {
|
|
199
|
+
let result = content;
|
|
200
|
+
if (options.assignee) {
|
|
201
|
+
result += ` @${options.assignee}`;
|
|
202
|
+
}
|
|
203
|
+
if (options.priority === "urgent") {
|
|
204
|
+
result += " !!!";
|
|
205
|
+
} else if (options.priority === "high") {
|
|
206
|
+
result += " !!";
|
|
207
|
+
} else if (options.priority === "normal") {
|
|
208
|
+
result += " !";
|
|
209
|
+
}
|
|
210
|
+
if (options.tags && options.tags.length > 0) {
|
|
211
|
+
result += " " + options.tags.map((tag) => `#${tag}`).join(" ");
|
|
212
|
+
}
|
|
213
|
+
if (options.due) {
|
|
214
|
+
const year = options.due.getUTCFullYear();
|
|
215
|
+
const month = String(options.due.getUTCMonth() + 1).padStart(2, "0");
|
|
216
|
+
const day = String(options.due.getUTCDate()).padStart(2, "0");
|
|
217
|
+
result += ` (${year}-${month}-${day})`;
|
|
218
|
+
}
|
|
219
|
+
if (options.todoistId) {
|
|
220
|
+
result += ` [todoist:${options.todoistId}]`;
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
function md2doToTodoist(task, projectId) {
|
|
225
|
+
const params = {
|
|
226
|
+
content: extractTaskContent(task.text),
|
|
227
|
+
priority: md2doToTodoistPriority(task.priority)
|
|
228
|
+
};
|
|
229
|
+
if (task.tags && task.tags.length > 0) {
|
|
230
|
+
params.labels = task.tags;
|
|
231
|
+
}
|
|
232
|
+
if (task.dueDate) {
|
|
233
|
+
const year = task.dueDate.getUTCFullYear();
|
|
234
|
+
const month = String(task.dueDate.getUTCMonth() + 1).padStart(2, "0");
|
|
235
|
+
const day = String(task.dueDate.getUTCDate()).padStart(2, "0");
|
|
236
|
+
params.due_date = `${year}-${month}-${day}`;
|
|
237
|
+
}
|
|
238
|
+
if (projectId) {
|
|
239
|
+
params.project_id = projectId;
|
|
240
|
+
}
|
|
241
|
+
return params;
|
|
242
|
+
}
|
|
243
|
+
function todoistToMd2do(todoistTask, assignee) {
|
|
244
|
+
const priority = todoistToMd2doPriority(todoistTask.priority);
|
|
245
|
+
const due = todoistTask.due?.date ? /* @__PURE__ */ new Date(`${todoistTask.due.date}T00:00:00.000Z`) : void 0;
|
|
246
|
+
const formatOptions = {
|
|
247
|
+
todoistId: todoistTask.id
|
|
248
|
+
};
|
|
249
|
+
if (assignee !== void 0) {
|
|
250
|
+
formatOptions.assignee = assignee;
|
|
251
|
+
}
|
|
252
|
+
if (priority !== void 0) {
|
|
253
|
+
formatOptions.priority = priority;
|
|
254
|
+
}
|
|
255
|
+
if (todoistTask.labels.length > 0) {
|
|
256
|
+
formatOptions.tags = todoistTask.labels;
|
|
257
|
+
}
|
|
258
|
+
if (due !== void 0) {
|
|
259
|
+
formatOptions.due = due;
|
|
260
|
+
}
|
|
261
|
+
const update = {
|
|
262
|
+
text: formatTaskContent(todoistTask.content, formatOptions),
|
|
263
|
+
completed: todoistTask.isCompleted ?? false,
|
|
264
|
+
todoistId: todoistTask.id
|
|
265
|
+
};
|
|
266
|
+
if (priority !== void 0) {
|
|
267
|
+
update.priority = priority;
|
|
268
|
+
}
|
|
269
|
+
if (todoistTask.labels.length > 0) {
|
|
270
|
+
update.tags = todoistTask.labels;
|
|
271
|
+
}
|
|
272
|
+
if (due !== void 0) {
|
|
273
|
+
update.due = due;
|
|
274
|
+
}
|
|
275
|
+
return update;
|
|
276
|
+
}
|
|
277
|
+
export {
|
|
278
|
+
TodoistClient,
|
|
279
|
+
extractTaskContent,
|
|
280
|
+
formatTaskContent,
|
|
281
|
+
md2doToTodoist,
|
|
282
|
+
md2doToTodoistPriority,
|
|
283
|
+
todoistToMd2do,
|
|
284
|
+
todoistToMd2doPriority
|
|
285
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@md2do/todoist",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Todoist API integration for md2do",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"todoist",
|
|
7
|
+
"task-sync",
|
|
8
|
+
"integration"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://md2do.com",
|
|
11
|
+
"bugs": "https://github.com/TeamNickHart/md2do/issues",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/TeamNickHart/md2do.git",
|
|
15
|
+
"directory": "packages/todoist"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Nicholas Hart <nickhart@gmail.com>",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"module": "./dist/index.mjs",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.mjs",
|
|
29
|
+
"require": "./dist/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@doist/todoist-api-typescript": "^3.0.3",
|
|
34
|
+
"date-fns": "^3.0.6",
|
|
35
|
+
"@md2do/core": "0.2.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"tsup": "^8.0.1"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
42
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
43
|
+
"test": "vitest",
|
|
44
|
+
"test:run": "vitest run",
|
|
45
|
+
"test:coverage": "vitest run --coverage",
|
|
46
|
+
"test:ui": "vitest --ui",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"clean": "rm -rf dist"
|
|
49
|
+
}
|
|
50
|
+
}
|