atl-fetch 1.0.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/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/cli/cli.d.ts +61 -0
- package/dist/cli/cli.js +131 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.js +4 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +13 -0
- package/dist/ports/file/file-port.d.ts +89 -0
- package/dist/ports/file/file-port.js +155 -0
- package/dist/ports/file/index.d.ts +1 -0
- package/dist/ports/file/index.js +1 -0
- package/dist/ports/http/http-port.d.ts +107 -0
- package/dist/ports/http/http-port.js +238 -0
- package/dist/ports/http/index.d.ts +1 -0
- package/dist/ports/http/index.js +1 -0
- package/dist/services/auth/auth-service.d.ts +79 -0
- package/dist/services/auth/auth-service.js +158 -0
- package/dist/services/auth/index.d.ts +1 -0
- package/dist/services/auth/index.js +1 -0
- package/dist/services/confluence/confluence-service.d.ts +152 -0
- package/dist/services/confluence/confluence-service.js +510 -0
- package/dist/services/confluence/index.d.ts +1 -0
- package/dist/services/confluence/index.js +1 -0
- package/dist/services/diff/diff-service.d.ts +84 -0
- package/dist/services/diff/diff-service.js +881 -0
- package/dist/services/diff/index.d.ts +1 -0
- package/dist/services/diff/index.js +1 -0
- package/dist/services/fetch/fetch-service.d.ts +112 -0
- package/dist/services/fetch/fetch-service.js +302 -0
- package/dist/services/fetch/index.d.ts +1 -0
- package/dist/services/fetch/index.js +1 -0
- package/dist/services/jira/index.d.ts +1 -0
- package/dist/services/jira/index.js +1 -0
- package/dist/services/jira/jira-service.d.ts +100 -0
- package/dist/services/jira/jira-service.js +354 -0
- package/dist/services/output/index.d.ts +4 -0
- package/dist/services/output/index.js +4 -0
- package/dist/services/output/output-service.d.ts +67 -0
- package/dist/services/output/output-service.js +228 -0
- package/dist/services/storage/index.d.ts +6 -0
- package/dist/services/storage/index.js +6 -0
- package/dist/services/storage/storage-service.d.ts +77 -0
- package/dist/services/storage/storage-service.js +738 -0
- package/dist/services/text-converter/index.d.ts +1 -0
- package/dist/services/text-converter/index.js +1 -0
- package/dist/services/text-converter/text-converter.d.ts +35 -0
- package/dist/services/text-converter/text-converter.js +681 -0
- package/dist/services/url-parser/index.d.ts +1 -0
- package/dist/services/url-parser/index.js +1 -0
- package/dist/services/url-parser/url-parser.d.ts +43 -0
- package/dist/services/url-parser/url-parser.js +283 -0
- package/dist/types/auth.d.ts +25 -0
- package/dist/types/auth.js +1 -0
- package/dist/types/confluence.d.ts +68 -0
- package/dist/types/confluence.js +1 -0
- package/dist/types/diff.d.ts +77 -0
- package/dist/types/diff.js +7 -0
- package/dist/types/fetch.d.ts +65 -0
- package/dist/types/fetch.js +1 -0
- package/dist/types/file.d.ts +22 -0
- package/dist/types/file.js +1 -0
- package/dist/types/http.d.ts +45 -0
- package/dist/types/http.js +1 -0
- package/dist/types/jira.d.ts +90 -0
- package/dist/types/jira.js +1 -0
- package/dist/types/output.d.ts +55 -0
- package/dist/types/output.js +7 -0
- package/dist/types/result.d.ts +104 -0
- package/dist/types/result.js +119 -0
- package/dist/types/storage.d.ts +209 -0
- package/dist/types/storage.js +6 -0
- package/dist/types/url-parser.d.ts +46 -0
- package/dist/types/url-parser.js +1 -0
- package/package.json +106 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { diffText, formatConfluenceVersionDiff, formatJiraChangelog } from './diff-service.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { diffText, formatConfluenceVersionDiff, formatJiraChangelog } from './diff-service.js';
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { type Result } from 'neverthrow';
|
|
2
|
+
import type { FetchAndSaveOptions, FetchAndSaveResult, FetchError, FetchResult } from '../../types/fetch.js';
|
|
3
|
+
import type { OutputOptions } from '../../types/output.js';
|
|
4
|
+
/**
|
|
5
|
+
* URL からリソースを取得する
|
|
6
|
+
*
|
|
7
|
+
* Atlassian Cloud の URL を解析し、リソースタイプ(Jira / Confluence)に応じて
|
|
8
|
+
* 適切なサービスを呼び出してデータを取得する。
|
|
9
|
+
*
|
|
10
|
+
* @param url - Atlassian Cloud の URL
|
|
11
|
+
* @returns 成功時は {@link FetchResult} を含む Ok、失敗時は {@link FetchError} を含む Err
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Jira Issue を取得
|
|
16
|
+
* const result = await fetchResource('https://mycompany.atlassian.net/browse/PROJ-123');
|
|
17
|
+
* if (result.isOk()) {
|
|
18
|
+
* if (result.value.type === 'jira') {
|
|
19
|
+
* console.log(result.value.data.summary);
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Confluence ページを取得
|
|
27
|
+
* const result = await fetchResource('https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789');
|
|
28
|
+
* if (result.isOk()) {
|
|
29
|
+
* if (result.value.type === 'confluence') {
|
|
30
|
+
* console.log(result.value.data.title);
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // エラーハンドリング
|
|
38
|
+
* const result = await fetchResource('https://invalid-url.com');
|
|
39
|
+
* if (result.isErr()) {
|
|
40
|
+
* console.log(result.error.kind); // 'URL_PARSE_ERROR'
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function fetchResource(url: string): Promise<Result<FetchResult, FetchError>>;
|
|
45
|
+
/**
|
|
46
|
+
* URL からリソースを取得し、指定形式で出力する
|
|
47
|
+
*
|
|
48
|
+
* Atlassian Cloud の URL を解析してリソースを取得し、
|
|
49
|
+
* 出力オプションに応じて JSON/Markdown/YAML 形式でフォーマットする。
|
|
50
|
+
* outputPath が指定されている場合はファイルに書き込む。
|
|
51
|
+
*
|
|
52
|
+
* @param url - Atlassian Cloud の URL
|
|
53
|
+
* @param options - 出力オプション(形式、出力先パス、カラー有効化)
|
|
54
|
+
* @returns 成功時はフォーマット済み文字列を含む Ok、失敗時は {@link FetchError} を含む Err
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // JSON 形式で標準出力
|
|
59
|
+
* const result = await fetchAndOutput(
|
|
60
|
+
* 'https://mycompany.atlassian.net/browse/PROJ-123',
|
|
61
|
+
* { format: 'json', colorEnabled: true }
|
|
62
|
+
* );
|
|
63
|
+
* if (result.isOk()) {
|
|
64
|
+
* console.log(result.value);
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* // Markdown 形式でファイル出力
|
|
71
|
+
* const result = await fetchAndOutput(
|
|
72
|
+
* 'https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789',
|
|
73
|
+
* { format: 'markdown', outputPath: '/tmp/page.md', colorEnabled: false }
|
|
74
|
+
* );
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function fetchAndOutput(url: string, options: OutputOptions): Promise<Result<string, FetchError>>;
|
|
78
|
+
/**
|
|
79
|
+
* URL からリソースを取得し、ディレクトリ構造で保存する
|
|
80
|
+
*
|
|
81
|
+
* Atlassian Cloud の URL を解析してリソースを取得し、
|
|
82
|
+
* ダウンロードオプションに応じて StorageService を呼び出してディレクトリ構造で保存する。
|
|
83
|
+
*
|
|
84
|
+
* @param url - Atlassian Cloud の URL
|
|
85
|
+
* @param options - 保存オプション(ベースディレクトリ、CLI バージョン、入力 URL)
|
|
86
|
+
* @returns 成功時は {@link FetchAndSaveResult} を含む Ok、失敗時は {@link FetchError} を含む Err
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* // Jira Issue をディレクトリ構造で保存
|
|
91
|
+
* const result = await fetchAndSave(
|
|
92
|
+
* 'https://mycompany.atlassian.net/browse/PROJ-123',
|
|
93
|
+
* { baseDir: '/tmp/output', cliVersion: '1.0.0', sourceUrl: 'https://mycompany.atlassian.net/browse/PROJ-123' }
|
|
94
|
+
* );
|
|
95
|
+
* if (result.isOk()) {
|
|
96
|
+
* console.log('保存先:', result.value.directory);
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* // Confluence ページをディレクトリ構造で保存
|
|
103
|
+
* const result = await fetchAndSave(
|
|
104
|
+
* 'https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789',
|
|
105
|
+
* { baseDir: '/tmp/output', cliVersion: '1.0.0', sourceUrl: 'https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789' }
|
|
106
|
+
* );
|
|
107
|
+
* if (result.isOk()) {
|
|
108
|
+
* console.log('保存先:', result.value.directory);
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export declare function fetchAndSave(url: string, options: FetchAndSaveOptions): Promise<Result<FetchAndSaveResult, FetchError>>;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { err, ok } from 'neverthrow';
|
|
2
|
+
import { fetchConfluencePage } from '../confluence/confluence-service.js';
|
|
3
|
+
import { fetchJiraIssue } from '../jira/jira-service.js';
|
|
4
|
+
import { formatConfluencePage, formatJiraIssue, writeToFile } from '../output/output-service.js';
|
|
5
|
+
import { saveConfluencePage, saveConfluenceVersions, saveJiraIssue } from '../storage/storage-service.js';
|
|
6
|
+
import { convertAdfToPlainText, convertStorageFormatToPlainText } from '../text-converter/text-converter.js';
|
|
7
|
+
import { parseUrl } from '../url-parser/url-parser.js';
|
|
8
|
+
/**
|
|
9
|
+
* Jira エラーを FetchError に変換する
|
|
10
|
+
*
|
|
11
|
+
* @param jiraError - Jira サービスから返されたエラー
|
|
12
|
+
* @returns FetchError
|
|
13
|
+
*/
|
|
14
|
+
function mapJiraErrorToFetchError(jiraError) {
|
|
15
|
+
switch (jiraError.kind) {
|
|
16
|
+
case 'NOT_FOUND':
|
|
17
|
+
return { kind: 'NOT_FOUND', message: jiraError.message };
|
|
18
|
+
case 'FORBIDDEN':
|
|
19
|
+
return { kind: 'FORBIDDEN', message: jiraError.message };
|
|
20
|
+
case 'AUTH_FAILED':
|
|
21
|
+
return { kind: 'AUTH_FAILED', message: jiraError.message };
|
|
22
|
+
case 'NETWORK_ERROR':
|
|
23
|
+
return { kind: 'NETWORK_ERROR', message: jiraError.message };
|
|
24
|
+
case 'PARSE_ERROR':
|
|
25
|
+
return { kind: 'JIRA_ERROR', message: jiraError.message };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Confluence エラーを FetchError に変換する
|
|
30
|
+
*
|
|
31
|
+
* @param confluenceError - Confluence サービスから返されたエラー
|
|
32
|
+
* @returns FetchError
|
|
33
|
+
*/
|
|
34
|
+
function mapConfluenceErrorToFetchError(confluenceError) {
|
|
35
|
+
switch (confluenceError.kind) {
|
|
36
|
+
case 'NOT_FOUND':
|
|
37
|
+
return { kind: 'NOT_FOUND', message: confluenceError.message };
|
|
38
|
+
case 'FORBIDDEN':
|
|
39
|
+
return { kind: 'FORBIDDEN', message: confluenceError.message };
|
|
40
|
+
case 'AUTH_FAILED':
|
|
41
|
+
return { kind: 'AUTH_FAILED', message: confluenceError.message };
|
|
42
|
+
case 'NETWORK_ERROR':
|
|
43
|
+
return { kind: 'NETWORK_ERROR', message: confluenceError.message };
|
|
44
|
+
case 'PARSE_ERROR':
|
|
45
|
+
return { kind: 'CONFLUENCE_ERROR', message: confluenceError.message };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* URL からリソースを取得する
|
|
50
|
+
*
|
|
51
|
+
* Atlassian Cloud の URL を解析し、リソースタイプ(Jira / Confluence)に応じて
|
|
52
|
+
* 適切なサービスを呼び出してデータを取得する。
|
|
53
|
+
*
|
|
54
|
+
* @param url - Atlassian Cloud の URL
|
|
55
|
+
* @returns 成功時は {@link FetchResult} を含む Ok、失敗時は {@link FetchError} を含む Err
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* // Jira Issue を取得
|
|
60
|
+
* const result = await fetchResource('https://mycompany.atlassian.net/browse/PROJ-123');
|
|
61
|
+
* if (result.isOk()) {
|
|
62
|
+
* if (result.value.type === 'jira') {
|
|
63
|
+
* console.log(result.value.data.summary);
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* // Confluence ページを取得
|
|
71
|
+
* const result = await fetchResource('https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789');
|
|
72
|
+
* if (result.isOk()) {
|
|
73
|
+
* if (result.value.type === 'confluence') {
|
|
74
|
+
* console.log(result.value.data.title);
|
|
75
|
+
* }
|
|
76
|
+
* }
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* // エラーハンドリング
|
|
82
|
+
* const result = await fetchResource('https://invalid-url.com');
|
|
83
|
+
* if (result.isErr()) {
|
|
84
|
+
* console.log(result.error.kind); // 'URL_PARSE_ERROR'
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export async function fetchResource(url) {
|
|
89
|
+
// URL を解析
|
|
90
|
+
const parseResult = parseUrl(url);
|
|
91
|
+
if (parseResult.isErr()) {
|
|
92
|
+
return err({
|
|
93
|
+
kind: 'URL_PARSE_ERROR',
|
|
94
|
+
message: parseResult.error.message,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const { type, organization, resourceId } = parseResult.value;
|
|
98
|
+
// リソースタイプに応じてサービスを呼び出す
|
|
99
|
+
if (type === 'jira') {
|
|
100
|
+
const issueResult = await fetchJiraIssue(organization, resourceId);
|
|
101
|
+
if (issueResult.isErr()) {
|
|
102
|
+
return err(mapJiraErrorToFetchError(issueResult.error));
|
|
103
|
+
}
|
|
104
|
+
return ok({
|
|
105
|
+
data: issueResult.value,
|
|
106
|
+
type: 'jira',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// type === 'confluence'
|
|
110
|
+
const pageResult = await fetchConfluencePage(organization, resourceId);
|
|
111
|
+
if (pageResult.isErr()) {
|
|
112
|
+
return err(mapConfluenceErrorToFetchError(pageResult.error));
|
|
113
|
+
}
|
|
114
|
+
return ok({
|
|
115
|
+
data: pageResult.value,
|
|
116
|
+
type: 'confluence',
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* URL からリソースを取得し、指定形式で出力する
|
|
121
|
+
*
|
|
122
|
+
* Atlassian Cloud の URL を解析してリソースを取得し、
|
|
123
|
+
* 出力オプションに応じて JSON/Markdown/YAML 形式でフォーマットする。
|
|
124
|
+
* outputPath が指定されている場合はファイルに書き込む。
|
|
125
|
+
*
|
|
126
|
+
* @param url - Atlassian Cloud の URL
|
|
127
|
+
* @param options - 出力オプション(形式、出力先パス、カラー有効化)
|
|
128
|
+
* @returns 成功時はフォーマット済み文字列を含む Ok、失敗時は {@link FetchError} を含む Err
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* // JSON 形式で標準出力
|
|
133
|
+
* const result = await fetchAndOutput(
|
|
134
|
+
* 'https://mycompany.atlassian.net/browse/PROJ-123',
|
|
135
|
+
* { format: 'json', colorEnabled: true }
|
|
136
|
+
* );
|
|
137
|
+
* if (result.isOk()) {
|
|
138
|
+
* console.log(result.value);
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* ```typescript
|
|
144
|
+
* // Markdown 形式でファイル出力
|
|
145
|
+
* const result = await fetchAndOutput(
|
|
146
|
+
* 'https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789',
|
|
147
|
+
* { format: 'markdown', outputPath: '/tmp/page.md', colorEnabled: false }
|
|
148
|
+
* );
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export async function fetchAndOutput(url, options) {
|
|
152
|
+
// リソースを取得
|
|
153
|
+
const fetchResult = await fetchResource(url);
|
|
154
|
+
if (fetchResult.isErr()) {
|
|
155
|
+
return err(fetchResult.error);
|
|
156
|
+
}
|
|
157
|
+
const { type, data } = fetchResult.value;
|
|
158
|
+
// リソースタイプに応じてフォーマット
|
|
159
|
+
const formatResult = type === 'jira'
|
|
160
|
+
? formatJiraIssue(data, { format: options.format })
|
|
161
|
+
: formatConfluencePage(data, { format: options.format });
|
|
162
|
+
if (formatResult.isErr()) {
|
|
163
|
+
return err({
|
|
164
|
+
kind: 'OUTPUT_ERROR',
|
|
165
|
+
message: formatResult.error.message,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const formattedContent = formatResult.value;
|
|
169
|
+
// ファイル出力が指定されている場合は書き込む
|
|
170
|
+
if (options.outputPath !== undefined) {
|
|
171
|
+
const writeResult = await writeToFile(formattedContent, options.outputPath);
|
|
172
|
+
if (writeResult.isErr()) {
|
|
173
|
+
return err({
|
|
174
|
+
kind: 'OUTPUT_ERROR',
|
|
175
|
+
message: writeResult.error.message,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return ok(formattedContent);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* URL からリソースを取得し、ディレクトリ構造で保存する
|
|
183
|
+
*
|
|
184
|
+
* Atlassian Cloud の URL を解析してリソースを取得し、
|
|
185
|
+
* ダウンロードオプションに応じて StorageService を呼び出してディレクトリ構造で保存する。
|
|
186
|
+
*
|
|
187
|
+
* @param url - Atlassian Cloud の URL
|
|
188
|
+
* @param options - 保存オプション(ベースディレクトリ、CLI バージョン、入力 URL)
|
|
189
|
+
* @returns 成功時は {@link FetchAndSaveResult} を含む Ok、失敗時は {@link FetchError} を含む Err
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* ```typescript
|
|
193
|
+
* // Jira Issue をディレクトリ構造で保存
|
|
194
|
+
* const result = await fetchAndSave(
|
|
195
|
+
* 'https://mycompany.atlassian.net/browse/PROJ-123',
|
|
196
|
+
* { baseDir: '/tmp/output', cliVersion: '1.0.0', sourceUrl: 'https://mycompany.atlassian.net/browse/PROJ-123' }
|
|
197
|
+
* );
|
|
198
|
+
* if (result.isOk()) {
|
|
199
|
+
* console.log('保存先:', result.value.directory);
|
|
200
|
+
* }
|
|
201
|
+
* ```
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* // Confluence ページをディレクトリ構造で保存
|
|
206
|
+
* const result = await fetchAndSave(
|
|
207
|
+
* 'https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789',
|
|
208
|
+
* { baseDir: '/tmp/output', cliVersion: '1.0.0', sourceUrl: 'https://mycompany.atlassian.net/wiki/spaces/DOCS/pages/123456789' }
|
|
209
|
+
* );
|
|
210
|
+
* if (result.isOk()) {
|
|
211
|
+
* console.log('保存先:', result.value.directory);
|
|
212
|
+
* }
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export async function fetchAndSave(url, options) {
|
|
216
|
+
// URL を解析
|
|
217
|
+
const parseResult = parseUrl(url);
|
|
218
|
+
if (parseResult.isErr()) {
|
|
219
|
+
return err({
|
|
220
|
+
kind: 'URL_PARSE_ERROR',
|
|
221
|
+
message: parseResult.error.message,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
const { type, organization, resourceId } = parseResult.value;
|
|
225
|
+
// リソースタイプに応じてサービスを呼び出す
|
|
226
|
+
if (type === 'jira') {
|
|
227
|
+
// Jira Issue を取得
|
|
228
|
+
const issueResult = await fetchJiraIssue(organization, resourceId);
|
|
229
|
+
if (issueResult.isErr()) {
|
|
230
|
+
return err(mapJiraErrorToFetchError(issueResult.error));
|
|
231
|
+
}
|
|
232
|
+
const issue = issueResult.value;
|
|
233
|
+
// ADF をプレーンテキストに変換
|
|
234
|
+
const descriptionPlainText = issue.description !== null ? convertAdfToPlainText(issue.description) : null;
|
|
235
|
+
// Jira Issue をディレクトリ構造で保存
|
|
236
|
+
const saveResult = await saveJiraIssue({
|
|
237
|
+
attachments: issue.attachments,
|
|
238
|
+
changelog: issue.changelog,
|
|
239
|
+
comments: issue.comments,
|
|
240
|
+
description: issue.description,
|
|
241
|
+
descriptionPlainText,
|
|
242
|
+
key: issue.key,
|
|
243
|
+
summary: issue.summary,
|
|
244
|
+
}, {
|
|
245
|
+
baseDir: options.baseDir,
|
|
246
|
+
cliVersion: options.cliVersion,
|
|
247
|
+
sourceUrl: options.sourceUrl,
|
|
248
|
+
});
|
|
249
|
+
if (saveResult.isErr()) {
|
|
250
|
+
return err({
|
|
251
|
+
kind: 'STORAGE_ERROR',
|
|
252
|
+
message: saveResult.error.message,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
return ok({
|
|
256
|
+
directory: saveResult.value.directory,
|
|
257
|
+
manifest: saveResult.value.manifest,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
// type === 'confluence'
|
|
261
|
+
// Confluence ページを取得
|
|
262
|
+
const pageResult = await fetchConfluencePage(organization, resourceId);
|
|
263
|
+
if (pageResult.isErr()) {
|
|
264
|
+
return err(mapConfluenceErrorToFetchError(pageResult.error));
|
|
265
|
+
}
|
|
266
|
+
const page = pageResult.value;
|
|
267
|
+
// Storage Format をプレーンテキストに変換
|
|
268
|
+
const bodyPlainText = convertStorageFormatToPlainText(page.body);
|
|
269
|
+
// Confluence ページをディレクトリ構造で保存
|
|
270
|
+
const saveResult = await saveConfluencePage({
|
|
271
|
+
attachments: page.attachments,
|
|
272
|
+
body: page.body,
|
|
273
|
+
bodyPlainText,
|
|
274
|
+
currentVersion: page.currentVersion,
|
|
275
|
+
id: page.id,
|
|
276
|
+
spaceKey: page.spaceKey,
|
|
277
|
+
title: page.title,
|
|
278
|
+
versions: page.versions,
|
|
279
|
+
}, {
|
|
280
|
+
baseDir: options.baseDir,
|
|
281
|
+
cliVersion: options.cliVersion,
|
|
282
|
+
sourceUrl: options.sourceUrl,
|
|
283
|
+
});
|
|
284
|
+
if (saveResult.isErr()) {
|
|
285
|
+
return err({
|
|
286
|
+
kind: 'STORAGE_ERROR',
|
|
287
|
+
message: saveResult.error.message,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
// バージョン別保存
|
|
291
|
+
const versionsResult = await saveConfluenceVersions(page.versions, saveResult.value.directory);
|
|
292
|
+
if (versionsResult.isErr()) {
|
|
293
|
+
return err({
|
|
294
|
+
kind: 'STORAGE_ERROR',
|
|
295
|
+
message: versionsResult.error.message,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
return ok({
|
|
299
|
+
directory: saveResult.value.directory,
|
|
300
|
+
manifest: saveResult.value.manifest,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { fetchAndOutput, fetchResource } from './fetch-service.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { fetchAndOutput, fetchResource } from './fetch-service.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { downloadJiraAttachment, fetchJiraIssue } from './jira-service.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { downloadJiraAttachment, fetchJiraIssue } from './jira-service.js';
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { type Result } from 'neverthrow';
|
|
2
|
+
import type { JiraAttachment, JiraError, JiraIssue } from '../../types/jira.js';
|
|
3
|
+
/**
|
|
4
|
+
* ADF (Atlassian Document Format) からプレーンテキストを抽出する
|
|
5
|
+
*
|
|
6
|
+
* Jira Cloud API v3 は説明やコメントを ADF 形式で返す。
|
|
7
|
+
* この関数は ADF ドキュメントからテキストコンテンツを抽出する。
|
|
8
|
+
*
|
|
9
|
+
* @param adf - ADF ドキュメント
|
|
10
|
+
* @returns プレーンテキスト
|
|
11
|
+
*
|
|
12
|
+
* @internal テスト用に export
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractTextFromAdf(adf: unknown): string;
|
|
15
|
+
/**
|
|
16
|
+
* HTTP エラーを JiraError に変換する
|
|
17
|
+
*
|
|
18
|
+
* @param status - HTTP ステータスコード
|
|
19
|
+
* @param message - エラーメッセージ
|
|
20
|
+
* @returns JiraError
|
|
21
|
+
*
|
|
22
|
+
* @internal テスト用に export
|
|
23
|
+
*/
|
|
24
|
+
export declare function mapHttpStatusToJiraError(status: number, message: string): JiraError;
|
|
25
|
+
/**
|
|
26
|
+
* Jira Issue を取得する
|
|
27
|
+
*
|
|
28
|
+
* Jira Cloud API を使用して Issue の基本情報(タイトル、説明、コメント、
|
|
29
|
+
* 変更履歴、添付ファイル)を取得する。
|
|
30
|
+
*
|
|
31
|
+
* @param organization - 組織名(.atlassian.net のサブドメイン)
|
|
32
|
+
* @param issueKey - Issue キー(例: PROJECT-123)
|
|
33
|
+
* @returns 成功時は {@link JiraIssue} を含む Ok、失敗時は {@link JiraError} を含む Err
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // 基本的な使用例
|
|
38
|
+
* const result = await fetchJiraIssue('my-company', 'PROJECT-123');
|
|
39
|
+
* if (result.isOk()) {
|
|
40
|
+
* console.log(result.value.summary);
|
|
41
|
+
* console.log(result.value.description);
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // エラーハンドリング
|
|
48
|
+
* const result = await fetchJiraIssue('my-company', 'NOTEXIST-999');
|
|
49
|
+
* if (result.isErr()) {
|
|
50
|
+
* if (result.error.kind === 'NOT_FOUND') {
|
|
51
|
+
* console.log('Issue が見つかりません');
|
|
52
|
+
* }
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function fetchJiraIssue(organization: string, issueKey: string): Promise<Result<JiraIssue, JiraError>>;
|
|
57
|
+
/**
|
|
58
|
+
* HTTP エラーステータスをダウンロード用の JiraError に変換する
|
|
59
|
+
*
|
|
60
|
+
* @param status - HTTP ステータスコード
|
|
61
|
+
* @returns JiraError
|
|
62
|
+
*
|
|
63
|
+
* @internal テスト用に export
|
|
64
|
+
*/
|
|
65
|
+
export declare function mapHttpStatusToDownloadError(status: number): JiraError;
|
|
66
|
+
/**
|
|
67
|
+
* Jira 添付ファイルをダウンロードする
|
|
68
|
+
*
|
|
69
|
+
* Jira Cloud API を使用して添付ファイルを指定パスにダウンロードする。
|
|
70
|
+
*
|
|
71
|
+
* @param attachment - ダウンロード対象の添付ファイル情報
|
|
72
|
+
* @param destPath - 保存先ファイルパス
|
|
73
|
+
* @param onProgress - 進捗コールバック関数(オプション)
|
|
74
|
+
* @returns 成功時は void を含む Ok、失敗時は {@link JiraError} を含む Err
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* // 基本的な使用例
|
|
79
|
+
* const attachment = issue.attachments[0];
|
|
80
|
+
* const result = await downloadJiraAttachment(attachment, '/path/to/save/file.png');
|
|
81
|
+
* if (result.isOk()) {
|
|
82
|
+
* console.log('ダウンロード完了');
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* // 進捗表示付き
|
|
89
|
+
* const result = await downloadJiraAttachment(
|
|
90
|
+
* attachment,
|
|
91
|
+
* '/path/to/save/file.png',
|
|
92
|
+
* (transferred, total) => {
|
|
93
|
+
* if (total) {
|
|
94
|
+
* console.log(`Progress: ${(transferred / total * 100).toFixed(1)}%`);
|
|
95
|
+
* }
|
|
96
|
+
* }
|
|
97
|
+
* );
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export declare function downloadJiraAttachment(attachment: JiraAttachment, destPath: string, onProgress?: (transferred: number, total: number | undefined) => void): Promise<Result<void, JiraError>>;
|