@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/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
+ }