Skip to content

Commit be94832

Browse files
authored
refactor: commonize command setup helpers
* refactor: commonize command setup helpers * fix: sanitize users presence json output
1 parent 920d823 commit be94832

File tree

8 files changed

+227
-226
lines changed

8 files changed

+227
-226
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@urugus/slack-cli",
3-
"version": "0.20.14",
3+
"version": "0.20.15",
44
"description": "A command-line tool for sending messages to Slack",
55
"main": "dist/index.js",
66
"bin": {

src/commands/canvas.ts

Lines changed: 44 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ import chalk from 'chalk';
22
import { Command } from 'commander';
33
import { CanvasListOptions, CanvasReadOptions } from '../types/commands';
44
import { CanvasFile, CanvasSection, CanvasSectionElement } from '../types/slack';
5-
import { createSlackClient } from '../utils/client-factory';
5+
import { renderByFormat, withSlackClient } from '../utils/command-support';
66
import { wrapCommand } from '../utils/command-wrapper';
7-
import { parseFormat, parseProfile } from '../utils/option-parsers';
8-
import { sanitizeTerminalData, sanitizeTerminalText } from '../utils/terminal-sanitizer';
7+
import { sanitizeTerminalText } from '../utils/terminal-sanitizer';
98
import { createValidationHook, optionValidators } from '../utils/validators';
109

1110
function extractText(elements: CanvasSectionElement[]): string {
@@ -18,21 +17,7 @@ function extractText(elements: CanvasSectionElement[]): string {
1817
.join('');
1918
}
2019

21-
function formatSections(sections: CanvasSection[], format: string): void {
22-
if (format === 'json') {
23-
console.log(JSON.stringify(sanitizeTerminalData(sections)));
24-
return;
25-
}
26-
27-
if (format === 'simple') {
28-
sections.forEach((section) => {
29-
const text = section.elements ? extractText(section.elements) : '';
30-
console.log(`${sanitizeTerminalText(section.id || '(no id)')}\t${text || '(no content)'}`);
31-
});
32-
return;
33-
}
34-
35-
// table format (default)
20+
function formatSectionsTable(sections: CanvasSection[]): void {
3621
sections.forEach((section) => {
3722
const text = section.elements ? extractText(section.elements) : '';
3823
console.log(
@@ -42,22 +27,14 @@ function formatSections(sections: CanvasSection[], format: string): void {
4227
});
4328
}
4429

45-
function formatCanvases(canvases: CanvasFile[], format: string): void {
46-
if (format === 'json') {
47-
console.log(JSON.stringify(sanitizeTerminalData(canvases)));
48-
return;
49-
}
50-
51-
if (format === 'simple') {
52-
canvases.forEach((canvas) => {
53-
console.log(
54-
`${sanitizeTerminalText(canvas.id || '(no id)')}\t${sanitizeTerminalText(canvas.name || '(no name)')}`
55-
);
56-
});
57-
return;
58-
}
30+
function formatSectionsSimple(sections: CanvasSection[]): void {
31+
sections.forEach((section) => {
32+
const text = section.elements ? extractText(section.elements) : '';
33+
console.log(`${sanitizeTerminalText(section.id || '(no id)')}\t${text || '(no content)'}`);
34+
});
35+
}
5936

60-
// table format (default)
37+
function formatCanvasesTable(canvases: CanvasFile[]): void {
6138
canvases.forEach((canvas) => {
6239
console.log(
6340
chalk.cyan(`ID: ${sanitizeTerminalText(canvas.id || '(no id)')}`) +
@@ -66,6 +43,14 @@ function formatCanvases(canvases: CanvasFile[], format: string): void {
6643
});
6744
}
6845

46+
function formatCanvasesSimple(canvases: CanvasFile[]): void {
47+
canvases.forEach((canvas) => {
48+
console.log(
49+
`${sanitizeTerminalText(canvas.id || '(no id)')}\t${sanitizeTerminalText(canvas.name || '(no name)')}`
50+
);
51+
});
52+
}
53+
6954
export function setupCanvasCommand(): Command {
7055
const canvasCommand = new Command('canvas').description('Manage Slack Canvases');
7156

@@ -77,18 +62,19 @@ export function setupCanvasCommand(): Command {
7762
.hook('preAction', createValidationHook([optionValidators.format]))
7863
.action(
7964
wrapCommand(async (options: CanvasReadOptions) => {
80-
const profile = parseProfile(options.profile);
81-
const client = await createSlackClient(profile);
82-
83-
const sections = await client.readCanvas(options.id);
84-
85-
if (sections.length === 0) {
86-
console.log('No sections found in canvas');
87-
return;
88-
}
89-
90-
const format = parseFormat(options.format);
91-
formatSections(sections, format);
65+
await withSlackClient(options, async (client) => {
66+
const sections = await client.readCanvas(options.id);
67+
68+
if (sections.length === 0) {
69+
console.log('No sections found in canvas');
70+
return;
71+
}
72+
73+
renderByFormat(options, sections, {
74+
table: formatSectionsTable,
75+
simple: formatSectionsSimple,
76+
});
77+
});
9278
})
9379
);
9480

@@ -100,18 +86,19 @@ export function setupCanvasCommand(): Command {
10086
.hook('preAction', createValidationHook([optionValidators.format]))
10187
.action(
10288
wrapCommand(async (options: CanvasListOptions) => {
103-
const profile = parseProfile(options.profile);
104-
const client = await createSlackClient(profile);
105-
106-
const canvases = await client.listCanvases(options.channel);
107-
108-
if (canvases.length === 0) {
109-
console.log('No canvases found in channel');
110-
return;
111-
}
112-
113-
const format = parseFormat(options.format);
114-
formatCanvases(canvases, format);
89+
await withSlackClient(options, async (client) => {
90+
const canvases = await client.listCanvases(options.channel);
91+
92+
if (canvases.length === 0) {
93+
console.log('No canvases found in channel');
94+
return;
95+
}
96+
97+
renderByFormat(options, canvases, {
98+
table: formatCanvasesTable,
99+
simple: formatCanvasesSimple,
100+
});
101+
});
115102
})
116103
);
117104

src/commands/channels.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Command } from 'commander';
22
import { ChannelsOptions } from '../types/commands';
33
import { getChannelTypes, mapChannelToInfo } from '../utils/channel-formatter';
4-
import { createSlackClient } from '../utils/client-factory';
4+
import { withSlackClient } from '../utils/command-support';
55
import { wrapCommand } from '../utils/command-wrapper';
66
import { ERROR_MESSAGES } from '../utils/constants';
77
import { createChannelsListFormatter } from '../utils/formatters/channels-list-formatters';
@@ -19,30 +19,25 @@ export function setupChannelsCommand(): Command {
1919
.option('--profile <profile>', 'Use specific workspace profile')
2020
.action(
2121
wrapCommand(async (options: ChannelsOptions) => {
22-
// Create Slack client
23-
const client = await createSlackClient(options.profile);
22+
await withSlackClient(options, async (client) => {
23+
const types = getChannelTypes(options.type);
24+
const limit = parseLimit(options.limit, 100);
25+
const channels = await client.listChannels({
26+
types,
27+
exclude_archived: !parseBoolean(options.includeArchived),
28+
limit,
29+
});
2430

25-
// Map channel type to API types
26-
const types = getChannelTypes(options.type);
31+
if (channels.length === 0) {
32+
console.log(ERROR_MESSAGES.NO_CHANNELS_FOUND);
33+
return;
34+
}
2735

28-
// List channels
29-
const limit = parseLimit(options.limit, 100);
30-
const channels = await client.listChannels({
31-
types,
32-
exclude_archived: !parseBoolean(options.includeArchived),
33-
limit: limit,
36+
const channelInfos = channels.map(mapChannelToInfo);
37+
const format = parseFormat(options.format);
38+
const formatter = createChannelsListFormatter(format);
39+
formatter.format({ channels: channelInfos });
3440
});
35-
36-
if (channels.length === 0) {
37-
console.log(ERROR_MESSAGES.NO_CHANNELS_FOUND);
38-
return;
39-
}
40-
41-
// Format and display channels
42-
const channelInfos = channels.map(mapChannelToInfo);
43-
const format = parseFormat(options.format);
44-
const formatter = createChannelsListFormatter(format);
45-
formatter.format({ channels: channelInfos });
4641
})
4742
);
4843

src/commands/history.ts

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Command } from 'commander';
22
import { HistoryOptions } from '../types/commands';
33
import { HistoryOptions as ApiHistoryOptions, Message } from '../types/slack';
4-
import { createSlackClient } from '../utils/client-factory';
4+
import { withSlackClient } from '../utils/command-support';
55
import { wrapCommand } from '../utils/command-wrapper';
66
import { API_LIMITS } from '../utils/constants';
7-
import { parseCount, parseFormat, parseProfile } from '../utils/option-parsers';
7+
import { parseCount, parseFormat } from '../utils/option-parsers';
88
import { createValidationHook, optionValidators } from '../utils/validators';
99
import { displayHistoryResults } from './history-display';
1010
import { prepareSinceTimestamp } from './history-validators';
@@ -30,55 +30,54 @@ export function setupHistoryCommand(): Command {
3030
)
3131
.action(
3232
wrapCommand(async (options: HistoryOptions) => {
33-
const profile = parseProfile(options.profile);
34-
const client = await createSlackClient(profile);
33+
await withSlackClient(options, async (client) => {
34+
const limit = parseCount(
35+
options.number,
36+
API_LIMITS.DEFAULT_MESSAGE_COUNT,
37+
API_LIMITS.MIN_MESSAGE_COUNT,
38+
API_LIMITS.MAX_MESSAGE_COUNT
39+
);
3540

36-
const limit = parseCount(
37-
options.number,
38-
API_LIMITS.DEFAULT_MESSAGE_COUNT,
39-
API_LIMITS.MIN_MESSAGE_COUNT,
40-
API_LIMITS.MAX_MESSAGE_COUNT
41-
);
41+
let messages: Message[];
42+
let users: Map<string, string>;
43+
if (options.thread) {
44+
if (options.number !== undefined) {
45+
console.log('Warning: --number is ignored when --thread is specified.');
46+
}
47+
if (options.since !== undefined) {
48+
console.log('Warning: --since is ignored when --thread is specified.');
49+
}
50+
({ messages, users } = await client.getThreadHistory(options.channel, options.thread));
51+
} else {
52+
const historyOptions: ApiHistoryOptions = {
53+
limit,
54+
};
4255

43-
let messages: Message[];
44-
let users: Map<string, string>;
45-
if (options.thread) {
46-
if (options.number !== undefined) {
47-
console.log('Warning: --number is ignored when --thread is specified.');
48-
}
49-
if (options.since !== undefined) {
50-
console.log('Warning: --since is ignored when --thread is specified.');
51-
}
52-
({ messages, users } = await client.getThreadHistory(options.channel, options.thread));
53-
} else {
54-
const historyOptions: ApiHistoryOptions = {
55-
limit,
56-
};
56+
const oldest = prepareSinceTimestamp(options.since);
57+
if (oldest) {
58+
historyOptions.oldest = oldest;
59+
}
5760

58-
const oldest = prepareSinceTimestamp(options.since);
59-
if (oldest) {
60-
historyOptions.oldest = oldest;
61+
({ messages, users } = await client.getHistory(options.channel, historyOptions));
6162
}
6263

63-
({ messages, users } = await client.getHistory(options.channel, historyOptions));
64-
}
65-
66-
let permalinks: Map<string, string> | undefined;
67-
if (options.withLink && messages.length > 0) {
68-
try {
69-
permalinks = await client.getPermalinks(
70-
options.channel,
71-
messages.map((m) => m.ts)
72-
);
73-
} catch {
74-
// Degrade gracefully: show history without links
64+
let permalinks: Map<string, string> | undefined;
65+
if (options.withLink && messages.length > 0) {
66+
try {
67+
permalinks = await client.getPermalinks(
68+
options.channel,
69+
messages.map((m) => m.ts)
70+
);
71+
} catch {
72+
// Degrade gracefully: show history without links
73+
}
7574
}
76-
}
7775

78-
const format = parseFormat(options.format);
79-
displayHistoryResults(messages, users, options.channel, format, {
80-
preserveOrder: Boolean(options.thread),
81-
permalinks,
76+
const format = parseFormat(options.format);
77+
displayHistoryResults(messages, users, options.channel, format, {
78+
preserveOrder: Boolean(options.thread),
79+
permalinks,
80+
});
8281
});
8382
})
8483
);

0 commit comments

Comments
 (0)