atl-fetch 1.0.0 → 1.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.
@@ -0,0 +1,247 @@
1
+ /**
2
+ * CLI スピナー・進捗表示ユーティリティ
3
+ *
4
+ * ora と picocolors を使用した統一的な進捗表示を提供する。
5
+ */
6
+ import ora, {} from 'ora';
7
+ import pc from 'picocolors';
8
+ /**
9
+ * 事前定義されたスピナーステップ
10
+ */
11
+ export const SPINNER_STEPS = {
12
+ AUTH_CHECK: {
13
+ name: 'auth_check',
14
+ successText: '認証情報を確認しました',
15
+ text: '認証情報を確認中...',
16
+ },
17
+ DOWNLOAD_ATTACHMENTS: {
18
+ name: 'download_attachments',
19
+ successText: '添付ファイルをダウンロードしました',
20
+ text: '添付ファイルをダウンロード中...',
21
+ },
22
+ FETCH_CONFLUENCE: {
23
+ name: 'fetch_confluence',
24
+ successText: 'Confluence ページを取得しました',
25
+ text: 'Confluence ページを取得中...',
26
+ },
27
+ FETCH_DATA: {
28
+ name: 'fetch_data',
29
+ successText: 'データを取得しました',
30
+ text: 'データを取得中...',
31
+ },
32
+ FETCH_JIRA: {
33
+ name: 'fetch_jira',
34
+ successText: 'Jira Issue を取得しました',
35
+ text: 'Jira Issue を取得中...',
36
+ },
37
+ FORMAT_OUTPUT: {
38
+ name: 'format_output',
39
+ successText: '出力を整形しました',
40
+ text: '出力を整形中...',
41
+ },
42
+ SAVE_FILES: {
43
+ name: 'save_files',
44
+ successText: 'ファイルを保存しました',
45
+ text: 'ファイルを保存中...',
46
+ },
47
+ URL_PARSE: {
48
+ name: 'url_parse',
49
+ successText: 'URLを解析しました',
50
+ text: 'URLを解析中...',
51
+ },
52
+ };
53
+ /**
54
+ * CLI 出力のカラーヘルパー
55
+ */
56
+ export const colors = {
57
+ /** 太字 */
58
+ bold: (text) => pc.bold(text),
59
+ /** シアン(ファイルパスなど) */
60
+ cyan: (text) => pc.cyan(text),
61
+ /** 薄いテキスト(グレー) */
62
+ dim: (text) => pc.dim(text),
63
+ /** エラーメッセージ(赤) */
64
+ error: (text) => pc.red(text),
65
+ /** 情報メッセージ(青) */
66
+ info: (text) => pc.blue(text),
67
+ /** マゼンタ(URL など) */
68
+ magenta: (text) => pc.magenta(text),
69
+ /** 成功メッセージ(緑) */
70
+ success: (text) => pc.green(text),
71
+ /** 警告メッセージ(黄) */
72
+ warn: (text) => pc.yellow(text),
73
+ };
74
+ /**
75
+ * CLI スピナー管理クラス
76
+ *
77
+ * 処理の進捗状況をユーザーに表示するためのスピナーを管理する。
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * const spinner = new CliSpinner();
82
+ * spinner.start('データを取得中...');
83
+ * // ... 処理 ...
84
+ * spinner.succeed('データを取得しました');
85
+ * ```
86
+ */
87
+ export class CliSpinner {
88
+ spinner = null;
89
+ enabled;
90
+ /**
91
+ * CliSpinner インスタンスを作成する
92
+ *
93
+ * @param enabled スピナーを有効にするかどうか(CI環境などでは無効にする)
94
+ */
95
+ constructor(enabled = true) {
96
+ // CI環境やテスト環境ではスピナーを無効化
97
+ this.enabled = enabled && !process.env['CI'] && process.stdout.isTTY === true;
98
+ }
99
+ /**
100
+ * スピナーを開始する
101
+ *
102
+ * @param text 表示するテキスト
103
+ */
104
+ start(text) {
105
+ if (!this.enabled) {
106
+ return;
107
+ }
108
+ this.spinner = ora({
109
+ spinner: 'dots',
110
+ text,
111
+ }).start();
112
+ }
113
+ /**
114
+ * スピナーのテキストを更新する
115
+ *
116
+ * @param text 新しいテキスト
117
+ */
118
+ update(text) {
119
+ if (this.spinner) {
120
+ this.spinner.text = text;
121
+ }
122
+ }
123
+ /**
124
+ * スピナーを成功状態で終了する
125
+ *
126
+ * @param text 成功時に表示するテキスト
127
+ */
128
+ succeed(text) {
129
+ if (this.spinner) {
130
+ this.spinner.succeed(text);
131
+ this.spinner = null;
132
+ }
133
+ }
134
+ /**
135
+ * スピナーを失敗状態で終了する
136
+ *
137
+ * @param text 失敗時に表示するテキスト
138
+ */
139
+ fail(text) {
140
+ if (this.spinner) {
141
+ this.spinner.fail(text);
142
+ this.spinner = null;
143
+ }
144
+ }
145
+ /**
146
+ * スピナーを警告状態で終了する
147
+ *
148
+ * @param text 警告時に表示するテキスト
149
+ */
150
+ warn(text) {
151
+ if (this.spinner) {
152
+ this.spinner.warn(text);
153
+ this.spinner = null;
154
+ }
155
+ }
156
+ /**
157
+ * スピナーを情報状態で終了する
158
+ *
159
+ * @param text 情報として表示するテキスト
160
+ */
161
+ info(text) {
162
+ if (this.spinner) {
163
+ this.spinner.info(text);
164
+ this.spinner = null;
165
+ }
166
+ }
167
+ /**
168
+ * スピナーを停止する(状態なし)
169
+ */
170
+ stop() {
171
+ if (this.spinner) {
172
+ this.spinner.stop();
173
+ this.spinner = null;
174
+ }
175
+ }
176
+ /**
177
+ * 事前定義されたステップでスピナーを開始する
178
+ *
179
+ * @param step スピナーステップ定義
180
+ */
181
+ startStep(step) {
182
+ this.start(step.text);
183
+ }
184
+ /**
185
+ * 事前定義されたステップを成功状態で終了する
186
+ *
187
+ * @param step スピナーステップ定義
188
+ */
189
+ succeedStep(step) {
190
+ this.succeed(step.successText ?? step.text);
191
+ }
192
+ }
193
+ /**
194
+ * エラーメッセージを整形して出力する
195
+ *
196
+ * @param code エラーコード
197
+ * @param message エラーメッセージ
198
+ * @param cause 原因の説明(オプション)
199
+ * @param solution 解決策の説明(オプション)
200
+ * @returns 整形されたエラーメッセージ
201
+ */
202
+ export function formatError(code, message, cause, solution) {
203
+ const lines = [];
204
+ lines.push(colors.error(`${colors.bold(code)}: ${message}`));
205
+ if (cause) {
206
+ lines.push(colors.dim(` 原因: ${cause}`));
207
+ }
208
+ if (solution) {
209
+ lines.push(colors.info(` 解決策: ${solution}`));
210
+ }
211
+ return lines.join('\n');
212
+ }
213
+ /**
214
+ * 成功メッセージを整形する
215
+ *
216
+ * @param message メッセージ
217
+ * @param details 詳細情報(オプション)
218
+ * @returns 整形されたメッセージ
219
+ */
220
+ export function formatSuccess(message, details) {
221
+ const lines = [];
222
+ lines.push(colors.success(`✓ ${message}`));
223
+ if (details) {
224
+ for (const [key, value] of Object.entries(details)) {
225
+ lines.push(colors.dim(` ${key}: ${colors.cyan(value)}`));
226
+ }
227
+ }
228
+ return lines.join('\n');
229
+ }
230
+ /**
231
+ * 情報メッセージを整形する
232
+ *
233
+ * @param message メッセージ
234
+ * @returns 整形されたメッセージ
235
+ */
236
+ export function formatInfo(message) {
237
+ return colors.info(`ℹ ${message}`);
238
+ }
239
+ /**
240
+ * 警告メッセージを整形する
241
+ *
242
+ * @param message メッセージ
243
+ * @returns 整形されたメッセージ
244
+ */
245
+ export function formatWarn(message) {
246
+ return colors.warn(`⚠ ${message}`);
247
+ }
@@ -3,7 +3,7 @@ import { fetchConfluencePage } from '../confluence/confluence-service.js';
3
3
  import { fetchJiraIssue } from '../jira/jira-service.js';
4
4
  import { formatConfluencePage, formatJiraIssue, writeToFile } from '../output/output-service.js';
5
5
  import { saveConfluencePage, saveConfluenceVersions, saveJiraIssue } from '../storage/storage-service.js';
6
- import { convertAdfToPlainText, convertStorageFormatToPlainText } from '../text-converter/text-converter.js';
6
+ import { convertStorageFormatToPlainText } from '../text-converter/text-converter.js';
7
7
  import { parseUrl } from '../url-parser/url-parser.js';
8
8
  /**
9
9
  * Jira エラーを FetchError に変換する
@@ -230,15 +230,14 @@ export async function fetchAndSave(url, options) {
230
230
  return err(mapJiraErrorToFetchError(issueResult.error));
231
231
  }
232
232
  const issue = issueResult.value;
233
- // ADF をプレーンテキストに変換
234
- const descriptionPlainText = issue.description !== null ? convertAdfToPlainText(issue.description) : null;
235
233
  // Jira Issue をディレクトリ構造で保存
234
+ // description は ADF 形式で保存、descriptionPlainText は後方互換性のため維持
236
235
  const saveResult = await saveJiraIssue({
237
236
  attachments: issue.attachments,
238
237
  changelog: issue.changelog,
239
238
  comments: issue.comments,
240
- description: issue.description,
241
- descriptionPlainText,
239
+ description: issue.descriptionAdf,
240
+ descriptionPlainText: issue.description,
242
241
  key: issue.key,
243
242
  summary: issue.summary,
244
243
  }, {
@@ -108,6 +108,7 @@ function mapApiCommentToJiraComment(apiComment) {
108
108
  return {
109
109
  author: apiComment.author.displayName,
110
110
  body: extractTextFromAdf(apiComment.body),
111
+ bodyAdf: apiComment.body,
111
112
  created: apiComment.created,
112
113
  id: apiComment.id,
113
114
  updated: apiComment.updated,
@@ -254,6 +255,7 @@ export async function fetchJiraIssue(organization, issueKey) {
254
255
  changelog: (apiResponse.changelog?.histories ?? []).map(mapApiChangelogEntryToJiraChangelogEntry),
255
256
  comments: (apiResponse.fields.comment?.comments ?? []).map(mapApiCommentToJiraComment),
256
257
  description: apiResponse.fields.description ? extractTextFromAdf(apiResponse.fields.description) : null,
258
+ descriptionAdf: apiResponse.fields.description,
257
259
  key: apiResponse.key,
258
260
  summary: apiResponse.fields.summary,
259
261
  };
@@ -16,9 +16,11 @@ import type { ConfluenceSaveData, ConfluenceSaveResult, ConfluenceStorageOptions
16
16
  * ├── manifest.json # 取得メタデータ
17
17
  * ├── issue.json # Issue 全データ(JSON 形式)
18
18
  * ├── description.txt # 説明文のプレーンテキスト
19
- * ├── content.md # Markdown 形式
20
- * ├── changelog.json # 変更履歴
21
- * ├── comments.json # コメント一覧
19
+ * ├── content.md # Markdown 形式(Description + Attachments)
20
+ * ├── comments.md # コメント一覧(Markdown 形式)
21
+ * ├── changelog.md # 変更履歴(Markdown 形式)
22
+ * ├── changelog.json # 変更履歴(JSON 形式)
23
+ * ├── comments.json # コメント一覧(JSON 形式)
22
24
  * ├── attachments.json # 添付ファイル一覧メタデータ
23
25
  * └── attachments/ # 添付ファイル実体
24
26
  * └── {id}_{filename}