trello-cli-unofficial 0.7.6 → 0.8.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 (31) hide show
  1. package/README.md +27 -0
  2. package/bun.lock +225 -2
  3. package/dist/main.js +26490 -25401
  4. package/main.ts +6 -3
  5. package/package.json +15 -3
  6. package/src/application/use-cases/AuthenticateUserUseCase.ts +7 -6
  7. package/src/application/use-cases/CreateBoardUseCase.ts +19 -0
  8. package/src/application/use-cases/CreateCardUseCase.ts +2 -1
  9. package/src/application/use-cases/CreateListUseCase.ts +19 -0
  10. package/src/application/use-cases/GetBoardDetailsUseCase.ts +41 -0
  11. package/src/application/use-cases/UpdateCardUseCase.ts +2 -1
  12. package/src/application/use-cases/index.ts +3 -0
  13. package/src/domain/entities/Board.ts +10 -2
  14. package/src/domain/entities/Card.ts +12 -1
  15. package/src/domain/entities/Config.ts +3 -1
  16. package/src/domain/entities/List.ts +14 -2
  17. package/src/domain/repositories/TrelloRepository.ts +4 -0
  18. package/src/i18n/index.ts +62 -5
  19. package/src/i18n/locales/en.json +154 -17
  20. package/src/i18n/locales/pt-BR.json +154 -17
  21. package/src/infrastructure/repositories/FileConfigRepository.ts +6 -3
  22. package/src/infrastructure/repositories/TrelloApiRepository.ts +155 -10
  23. package/src/presentation/cli/AuthController.ts +2 -1
  24. package/src/presentation/cli/BoardController.ts +160 -17
  25. package/src/presentation/cli/CardController.ts +169 -45
  26. package/src/presentation/cli/CommandController.ts +293 -27
  27. package/src/presentation/cli/ConfigController.ts +4 -3
  28. package/src/presentation/cli/TrelloCliController.ts +10 -2
  29. package/src/shared/ErrorHandler.ts +233 -0
  30. package/src/shared/OutputFormatter.ts +210 -0
  31. package/src/shared/index.ts +2 -0
@@ -1,5 +1,7 @@
1
- import type { CardEntity, ListEntity } from '@domain/entities';
1
+ import type { BoardEntity, CardEntity, ListEntity } from '@domain/entities';
2
2
  import type { TrelloRepository } from '@domain/repositories';
3
+ import type { BoardController } from './BoardController';
4
+ import type { OutputFormatter } from '@/shared';
3
5
 
4
6
  import {
5
7
  CreateCardUseCase,
@@ -20,7 +22,8 @@ export class CardController {
20
22
 
21
23
  constructor(
22
24
  private trelloRepository: TrelloRepository,
23
- private boardController: unknown, // Will be injected to avoid circular dependency
25
+ private boardController: BoardController, // Will be injected to avoid circular dependency
26
+ private outputFormatter: OutputFormatter,
24
27
  ) {
25
28
  this.createCardUseCase = new CreateCardUseCase(trelloRepository);
26
29
  this.updateCardUseCase = new UpdateCardUseCase(trelloRepository);
@@ -29,28 +32,28 @@ export class CardController {
29
32
  }
30
33
 
31
34
  async createCardInteractive(): Promise<void> {
32
- const boards = await (this.boardController as any).getBoards();
35
+ const boards = await this.boardController.getBoards();
33
36
 
34
37
  const { selectedBoard } = await inquirer.prompt([
35
38
  {
36
39
  type: 'list',
37
40
  name: 'selectedBoard',
38
41
  message: t('card.selectBoard'),
39
- choices: boards.map((board: any) => ({
42
+ choices: boards.map((board: BoardEntity) => ({
40
43
  name: board.name,
41
44
  value: board.id,
42
45
  })),
43
46
  },
44
47
  ]);
45
48
 
46
- const lists = await (this.boardController as any).getLists(selectedBoard);
49
+ const lists = await this.boardController.getLists(selectedBoard);
47
50
 
48
51
  const { selectedList } = await inquirer.prompt([
49
52
  {
50
53
  type: 'list',
51
54
  name: 'selectedList',
52
55
  message: t('card.selectList'),
53
- choices: lists.map((list: any) => ({
56
+ choices: lists.map((list: ListEntity) => ({
54
57
  name: list.name,
55
58
  value: list.id,
56
59
  })),
@@ -62,7 +65,8 @@ export class CardController {
62
65
  type: 'input',
63
66
  name: 'cardName',
64
67
  message: t('card.enterName'),
65
- validate: input => input.length > 0 || 'Nome é obrigatório',
68
+ validate: input =>
69
+ input.length > 0 || t('card.validation.requiredName'),
66
70
  },
67
71
  {
68
72
  type: 'input',
@@ -92,7 +96,7 @@ export class CardController {
92
96
  },
93
97
  ]);
94
98
 
95
- const cards = await (this.boardController as any).getCards(selectedList);
99
+ const cards = await this.boardController.getCards(selectedList);
96
100
 
97
101
  if (cards.length === 0) {
98
102
  console.log(t('card.emptyList'));
@@ -100,18 +104,20 @@ export class CardController {
100
104
  }
101
105
 
102
106
  console.log(
103
- `🃏 Cartões em "${lists.find(l => l.id === selectedList)?.name}":`,
107
+ t('card.cardsInList', {
108
+ listName: lists.find(l => l.id === selectedList)?.name,
109
+ }),
104
110
  );
105
- cards.forEach((card: any, index: number) => {
111
+ cards.forEach((card: CardEntity, index: number) => {
106
112
  console.log(`${index + 1}. ${card.name}`);
107
113
  if (card.desc) {
108
114
  const desc
109
115
  = card.desc.length > 100
110
116
  ? `${card.desc.substring(0, 100)}...`
111
117
  : card.desc;
112
- console.log(` 📝 ${desc}`);
118
+ console.log(t('card.cardDescription', { description: desc }));
113
119
  }
114
- console.log(` 🔗 ${card.url}\n`);
120
+ console.log(`${t('card.cardUrl', { url: card.url })}\n`);
115
121
  });
116
122
 
117
123
  // Opções adicionais
@@ -124,7 +130,7 @@ export class CardController {
124
130
  { name: t('card.actions.back'), value: CARD_ACTIONS.BACK },
125
131
  { name: t('card.actions.edit'), value: CARD_ACTIONS.EDIT },
126
132
  { name: t('card.actions.delete'), value: CARD_ACTIONS.DELETE },
127
- { name: '📦 Mover cartão', value: CARD_ACTIONS.MOVE },
133
+ { name: t('card.actions.moveCard'), value: CARD_ACTIONS.MOVE },
128
134
  ],
129
135
  },
130
136
  ]);
@@ -135,14 +141,16 @@ export class CardController {
135
141
  type: 'list',
136
142
  name: 'selectedCard',
137
143
  message: t('card.selectCard'),
138
- choices: cards.map((card: any) => ({
144
+ choices: cards.map((card: CardEntity) => ({
139
145
  name: card.name,
140
146
  value: card.id,
141
147
  })),
142
148
  },
143
149
  ]);
144
150
 
145
- const selectedCardEntity = cards.find((c: any) => c.id === selectedCard)!;
151
+ const selectedCardEntity = cards.find(
152
+ (c: CardEntity) => c.id === selectedCard,
153
+ )!;
146
154
 
147
155
  switch (nextAction) {
148
156
  case CARD_ACTIONS.EDIT:
@@ -195,7 +203,7 @@ export class CardController {
195
203
  ]);
196
204
 
197
205
  if (confirm) {
198
- await this.deleteCard(cardId, card);
206
+ await this.deleteCard(cardId);
199
207
  }
200
208
  }
201
209
 
@@ -226,15 +234,15 @@ export class CardController {
226
234
  cardName: string,
227
235
  description?: string,
228
236
  ): Promise<void> {
229
- const boards = await (this.boardController as any).getBoards();
230
- const board = boards.find((b: any) => b.name === boardName);
237
+ const boards = await this.boardController.getBoards();
238
+ const board = boards.find((b: BoardEntity) => b.name === boardName);
231
239
 
232
240
  if (!board) {
233
241
  throw new Error(t('board.notFound', { name: boardName }));
234
242
  }
235
243
 
236
- const lists = await (this.boardController as any).getLists(board.id);
237
- const list = lists.find((l: any) => l.name === listName);
244
+ const lists = await this.boardController.getLists(board.id);
245
+ const list = lists.find((l: ListEntity) => l.name === listName);
238
246
 
239
247
  if (!list) {
240
248
  throw new Error(t('list.notFound', { listName, boardName }));
@@ -255,20 +263,22 @@ export class CardController {
255
263
  async moveCard(cardId: string, targetListName: string): Promise<void> {
256
264
  // Primeiro precisamos encontrar em qual board o cartão está
257
265
  // Para isso, vamos buscar todas as listas de todos os boards
258
- const boards = await (this.boardController as any).getBoards();
266
+ const boards = await this.boardController.getBoards();
259
267
 
260
268
  for (const board of boards) {
261
- const lists = await (this.boardController as any).getLists(board.id);
269
+ const lists = await this.boardController.getLists(board.id);
262
270
 
263
271
  // Verificar se alguma lista contém o cartão
264
272
  for (const list of lists) {
265
273
  try {
266
- const cards = await (this.boardController as any).getCards(list.id);
267
- const card = cards.find((c: any) => c.id === cardId);
274
+ const cards = await this.boardController.getCards(list.id);
275
+ const card = cards.find((c: CardEntity) => c.id === cardId);
268
276
 
269
277
  if (card) {
270
278
  // Encontrou o cartão! Agora procurar a lista de destino
271
- const targetList = lists.find((l: any) => l.name === targetListName);
279
+ const targetList = lists.find(
280
+ (l: ListEntity) => l.name === targetListName,
281
+ );
272
282
 
273
283
  if (!targetList) {
274
284
  throw new Error(
@@ -295,38 +305,152 @@ export class CardController {
295
305
  throw new Error(t('card.notFound', { cardId }));
296
306
  }
297
307
 
298
- async deleteCard(cardId: string, card?: CardEntity): Promise<void> {
299
- // Se não passou o card, tentar encontrar
308
+ async deleteCard(cardId: string): Promise<void> {
309
+ // Primeiro precisamos encontrar o cartão para mostrar informações
310
+ const boards = await this.trelloRepository.getBoards();
311
+ let card: CardEntity | undefined;
312
+
313
+ for (const board of boards) {
314
+ const lists = await this.trelloRepository.getLists(board.id);
315
+
316
+ for (const list of lists) {
317
+ try {
318
+ const cards = await this.trelloRepository.getCards(list.id);
319
+ card = cards.find((c: CardEntity) => c.id === cardId);
320
+
321
+ if (card) {
322
+ break;
323
+ }
324
+ } catch {
325
+ continue;
326
+ }
327
+ }
328
+ if (card) {
329
+ break;
330
+ }
331
+ }
332
+
300
333
  if (!card) {
301
- const boards = await (this.boardController as any).getBoards();
334
+ throw new Error(t('card.notFound', { cardId }));
335
+ }
336
+
337
+ await this.deleteCardUseCase.execute(cardId);
338
+ console.log(t('card.deleted'));
339
+ console.log(t('card.cardName', { name: card.name }));
340
+ }
341
+
342
+ async createCardByListId(
343
+ listId: string,
344
+ cardName: string,
345
+ description?: string,
346
+ ): Promise<void> {
347
+ const newCard = await this.createCardUseCase.execute({
348
+ name: cardName,
349
+ desc: description || '',
350
+ listId,
351
+ });
352
+
353
+ console.log(t('card.created'));
354
+ console.log(t('card.cardName', { name: newCard.name }));
355
+ console.log(t('card.cardUrl', { url: newCard.url }));
356
+ console.log(t('card.cardId', { id: newCard.id }));
357
+ }
302
358
 
303
- for (const board of boards) {
304
- const lists = await (this.boardController as any).getLists(board.id);
359
+ async updateCard(
360
+ cardId: string,
361
+ name?: string,
362
+ desc?: string,
363
+ ): Promise<void> {
364
+ // Primeiro precisamos encontrar o cartão para mostrar informações
365
+ const boards = await this.trelloRepository.getBoards();
366
+ let card: CardEntity | undefined;
305
367
 
306
- for (const list of lists) {
307
- try {
308
- const cards = await (this.boardController as any).getCards(list.id);
309
- card = cards.find((c: any) => c.id === cardId);
368
+ for (const board of boards) {
369
+ const lists = await this.trelloRepository.getLists(board.id);
310
370
 
311
- if (card) {
312
- break;
313
- }
314
- } catch {
315
- continue;
371
+ for (const list of lists) {
372
+ try {
373
+ const cards = await this.trelloRepository.getCards(list.id);
374
+ card = cards.find((c: CardEntity) => c.id === cardId);
375
+
376
+ if (card) {
377
+ break;
316
378
  }
379
+ } catch {
380
+ continue;
317
381
  }
318
- if (card) {
319
- break;
382
+ }
383
+ if (card) {
384
+ break;
385
+ }
386
+ }
387
+
388
+ if (!card) {
389
+ throw new Error(t('card.notFound', { cardId }));
390
+ }
391
+
392
+ const updateData: { name?: string; desc?: string } = {};
393
+ if (name !== undefined) {
394
+ updateData.name = name;
395
+ }
396
+ if (desc !== undefined) {
397
+ updateData.desc = desc;
398
+ }
399
+
400
+ const updatedCard = await this.updateCardUseCase.execute(
401
+ cardId,
402
+ updateData,
403
+ );
404
+ console.log(t('card.updated'));
405
+ console.log(t('card.cardName', { name: updatedCard.name }));
406
+ }
407
+
408
+ async moveCardToList(cardId: string, targetListId: string): Promise<void> {
409
+ // Primeiro precisamos encontrar o cartão para mostrar informações
410
+ const boards = await this.trelloRepository.getBoards();
411
+ let card: CardEntity | undefined;
412
+
413
+ for (const board of boards) {
414
+ const lists = await this.trelloRepository.getLists(board.id);
415
+
416
+ for (const list of lists) {
417
+ try {
418
+ const cards = await this.trelloRepository.getCards(list.id);
419
+ card = cards.find((c: CardEntity) => c.id === cardId);
420
+
421
+ if (card) {
422
+ break;
423
+ }
424
+ } catch {
425
+ continue;
320
426
  }
321
427
  }
428
+ if (card) {
429
+ break;
430
+ }
431
+ }
432
+
433
+ if (!card) {
434
+ throw new Error(t('card.notFound', { cardId }));
435
+ }
322
436
 
323
- if (!card) {
324
- throw new Error(t('card.notFound', { cardId }));
437
+ // Verificar se a lista de destino existe procurando em todos os boards
438
+ let targetList: ListEntity | undefined;
439
+ for (const board of boards) {
440
+ const lists = await this.trelloRepository.getLists(board.id);
441
+ targetList = lists.find((l: ListEntity) => l.id === targetListId);
442
+ if (targetList) {
443
+ break;
325
444
  }
326
445
  }
327
446
 
328
- await this.deleteCardUseCase.execute(cardId);
329
- console.log(t('card.deleted'));
447
+ if (!targetList) {
448
+ throw new Error(t('list.notFound', { listId: targetListId }));
449
+ }
450
+
451
+ await this.moveCardUseCase.execute(cardId, targetListId);
452
+ console.log(t('card.moved'));
330
453
  console.log(t('card.cardName', { name: card.name }));
454
+ console.log(t('card.movedTo', { listName: targetList.name }));
331
455
  }
332
456
  }