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.
- package/README.md +54 -43
- package/dist/cli/cli.d.ts +8 -0
- package/dist/cli/cli.js +157 -4
- package/dist/cli/spinner.d.ts +189 -0
- package/dist/cli/spinner.js +247 -0
- package/dist/services/fetch/fetch-service.js +4 -5
- package/dist/services/jira/jira-service.js +2 -0
- package/dist/services/storage/storage-service.d.ts +5 -3
- package/dist/services/storage/storage-service.js +297 -36
- package/dist/services/text-converter/text-converter.d.ts +8 -0
- package/dist/services/text-converter/text-converter.js +293 -20
- package/dist/types/jira.d.ts +5 -1
- package/dist/types/storage.d.ts +3 -3
- package/package.json +3 -1
- package/dist/types/result.d.ts +0 -104
- package/dist/types/result.js +0 -119
|
@@ -135,6 +135,236 @@ export const convertAdfToPlainText = (adf) => {
|
|
|
135
135
|
}
|
|
136
136
|
return '';
|
|
137
137
|
};
|
|
138
|
+
// ============================================================
|
|
139
|
+
// ADF → Markdown 変換(Confluence と同じ TurndownService を使用)
|
|
140
|
+
// ============================================================
|
|
141
|
+
/**
|
|
142
|
+
* HTML 特殊文字をエスケープする
|
|
143
|
+
*
|
|
144
|
+
* @param text エスケープ対象の文字列
|
|
145
|
+
* @returns エスケープ済み文字列
|
|
146
|
+
*/
|
|
147
|
+
const escapeHtml = (text) => {
|
|
148
|
+
return text
|
|
149
|
+
.replace(/&/g, '&')
|
|
150
|
+
.replace(/</g, '<')
|
|
151
|
+
.replace(/>/g, '>')
|
|
152
|
+
.replace(/"/g, '"')
|
|
153
|
+
.replace(/'/g, ''');
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* ADF マークを HTML タグで囲む
|
|
157
|
+
*
|
|
158
|
+
* @param text 対象のテキスト
|
|
159
|
+
* @param marks 適用するマーク配列
|
|
160
|
+
* @returns マークを適用した HTML
|
|
161
|
+
*/
|
|
162
|
+
const applyMarksToHtml = (text, marks) => {
|
|
163
|
+
let result = text;
|
|
164
|
+
for (const mark of marks) {
|
|
165
|
+
switch (mark.type) {
|
|
166
|
+
case 'strong':
|
|
167
|
+
result = `<strong>${result}</strong>`;
|
|
168
|
+
break;
|
|
169
|
+
case 'em':
|
|
170
|
+
result = `<em>${result}</em>`;
|
|
171
|
+
break;
|
|
172
|
+
case 'code':
|
|
173
|
+
result = `<code>${result}</code>`;
|
|
174
|
+
break;
|
|
175
|
+
case 'strike':
|
|
176
|
+
result = `<s>${result}</s>`;
|
|
177
|
+
break;
|
|
178
|
+
case 'underline':
|
|
179
|
+
result = `<u>${result}</u>`;
|
|
180
|
+
break;
|
|
181
|
+
case 'link': {
|
|
182
|
+
const href = mark.attrs?.['href'];
|
|
183
|
+
if (typeof href === 'string') {
|
|
184
|
+
result = `<a href="${escapeHtml(href)}">${result}</a>`;
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
case 'textColor': {
|
|
189
|
+
const color = mark.attrs?.['color'];
|
|
190
|
+
if (typeof color === 'string') {
|
|
191
|
+
result = `<span style="color: ${escapeHtml(color)}">${result}</span>`;
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
case 'subsup': {
|
|
196
|
+
const subType = mark.attrs?.['type'];
|
|
197
|
+
if (subType === 'sub') {
|
|
198
|
+
result = `<sub>${result}</sub>`;
|
|
199
|
+
}
|
|
200
|
+
else if (subType === 'sup') {
|
|
201
|
+
result = `<sup>${result}</sup>`;
|
|
202
|
+
}
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
// 未知のマークタイプは無視
|
|
206
|
+
default:
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* ADF ノードを HTML に変換する
|
|
214
|
+
*
|
|
215
|
+
* @param node ADF ノード
|
|
216
|
+
* @param attachmentPaths 添付ファイル ID → ローカルパスのマッピング
|
|
217
|
+
* @returns HTML 文字列
|
|
218
|
+
*/
|
|
219
|
+
const convertAdfNodeToHtml = (node, attachmentPaths) => {
|
|
220
|
+
// テキストノードの場合
|
|
221
|
+
if (node.type === 'text' && node.text !== undefined) {
|
|
222
|
+
const escapedText = escapeHtml(node.text);
|
|
223
|
+
if (node.marks !== undefined && node.marks.length > 0) {
|
|
224
|
+
return applyMarksToHtml(escapedText, node.marks);
|
|
225
|
+
}
|
|
226
|
+
return escapedText;
|
|
227
|
+
}
|
|
228
|
+
// hardBreak の場合
|
|
229
|
+
if (node.type === 'hardBreak') {
|
|
230
|
+
return '<br>';
|
|
231
|
+
}
|
|
232
|
+
// rule(水平線)の場合
|
|
233
|
+
if (node.type === 'rule') {
|
|
234
|
+
return '<hr>';
|
|
235
|
+
}
|
|
236
|
+
// メンションの場合
|
|
237
|
+
if (node.type === 'mention' && node.attrs !== undefined) {
|
|
238
|
+
const text = node.attrs['text'];
|
|
239
|
+
if (typeof text === 'string') {
|
|
240
|
+
return escapeHtml(text);
|
|
241
|
+
}
|
|
242
|
+
return '@ユーザー';
|
|
243
|
+
}
|
|
244
|
+
// 絵文字の場合
|
|
245
|
+
if (node.type === 'emoji' && node.attrs !== undefined) {
|
|
246
|
+
const text = node.attrs['text'];
|
|
247
|
+
const shortName = node.attrs['shortName'];
|
|
248
|
+
if (typeof text === 'string') {
|
|
249
|
+
return text;
|
|
250
|
+
}
|
|
251
|
+
if (typeof shortName === 'string') {
|
|
252
|
+
return shortName;
|
|
253
|
+
}
|
|
254
|
+
return '';
|
|
255
|
+
}
|
|
256
|
+
// media ノードの場合(添付ファイル)
|
|
257
|
+
if (node.type === 'media' && node.attrs !== undefined) {
|
|
258
|
+
const mediaId = node.attrs['id'];
|
|
259
|
+
const mediaType = node.attrs['type'];
|
|
260
|
+
if (typeof mediaId === 'string' && attachmentPaths?.[mediaId] !== undefined) {
|
|
261
|
+
const localPath = attachmentPaths[mediaId];
|
|
262
|
+
const alt = typeof node.attrs['alt'] === 'string' ? node.attrs['alt'] : mediaId;
|
|
263
|
+
return `<img src="${escapeHtml(localPath)}" alt="${escapeHtml(alt)}">`;
|
|
264
|
+
}
|
|
265
|
+
// 外部リンクの場合
|
|
266
|
+
if (mediaType === 'external' || mediaType === 'link') {
|
|
267
|
+
const url = node.attrs['url'];
|
|
268
|
+
if (typeof url === 'string') {
|
|
269
|
+
return `<img src="${escapeHtml(url)}" alt="">`;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// マッピングがない場合はプレースホルダー
|
|
273
|
+
return '[添付ファイル]';
|
|
274
|
+
}
|
|
275
|
+
// mediaSingle(メディアコンテナ)の場合
|
|
276
|
+
if (node.type === 'mediaSingle' && node.content !== undefined) {
|
|
277
|
+
return node.content.map((child) => convertAdfNodeToHtml(child, attachmentPaths)).join('');
|
|
278
|
+
}
|
|
279
|
+
// mediaGroup の場合
|
|
280
|
+
if (node.type === 'mediaGroup' && node.content !== undefined) {
|
|
281
|
+
return node.content.map((child) => convertAdfNodeToHtml(child, attachmentPaths)).join('');
|
|
282
|
+
}
|
|
283
|
+
// inlineCard(インラインリンク)の場合
|
|
284
|
+
if (node.type === 'inlineCard' && node.attrs !== undefined) {
|
|
285
|
+
const url = node.attrs['url'];
|
|
286
|
+
if (typeof url === 'string') {
|
|
287
|
+
return `<a href="${escapeHtml(url)}">${escapeHtml(url)}</a>`;
|
|
288
|
+
}
|
|
289
|
+
return '';
|
|
290
|
+
}
|
|
291
|
+
// blockCard(ブロックリンク)の場合
|
|
292
|
+
if (node.type === 'blockCard' && node.attrs !== undefined) {
|
|
293
|
+
const url = node.attrs['url'];
|
|
294
|
+
if (typeof url === 'string') {
|
|
295
|
+
return `<p><a href="${escapeHtml(url)}">${escapeHtml(url)}</a></p>`;
|
|
296
|
+
}
|
|
297
|
+
return '';
|
|
298
|
+
}
|
|
299
|
+
// 子ノードがある場合
|
|
300
|
+
if (node.content !== undefined && Array.isArray(node.content)) {
|
|
301
|
+
const childrenHtml = node.content.map((child) => convertAdfNodeToHtml(child, attachmentPaths)).join('');
|
|
302
|
+
switch (node.type) {
|
|
303
|
+
case 'doc':
|
|
304
|
+
return childrenHtml;
|
|
305
|
+
case 'paragraph':
|
|
306
|
+
return `<p>${childrenHtml}</p>`;
|
|
307
|
+
case 'heading': {
|
|
308
|
+
const level = typeof node.attrs?.['level'] === 'number' ? node.attrs['level'] : 1;
|
|
309
|
+
const safeLevel = Math.max(1, Math.min(6, level));
|
|
310
|
+
return `<h${safeLevel}>${childrenHtml}</h${safeLevel}>`;
|
|
311
|
+
}
|
|
312
|
+
case 'bulletList':
|
|
313
|
+
return `<ul>${childrenHtml}</ul>`;
|
|
314
|
+
case 'orderedList':
|
|
315
|
+
return `<ol>${childrenHtml}</ol>`;
|
|
316
|
+
case 'listItem':
|
|
317
|
+
return `<li>${childrenHtml}</li>`;
|
|
318
|
+
case 'blockquote':
|
|
319
|
+
return `<blockquote>${childrenHtml}</blockquote>`;
|
|
320
|
+
case 'codeBlock': {
|
|
321
|
+
const language = typeof node.attrs?.['language'] === 'string' ? node.attrs['language'] : '';
|
|
322
|
+
const langClass = language ? ` class="language-${escapeHtml(language)}"` : '';
|
|
323
|
+
// コードブロック内のテキストは子ノードから取得
|
|
324
|
+
const codeText = node.content
|
|
325
|
+
.map((child) => (child.type === 'text' && child.text !== undefined ? child.text : ''))
|
|
326
|
+
.join('');
|
|
327
|
+
return `<pre><code${langClass}>${escapeHtml(codeText)}</code></pre>`;
|
|
328
|
+
}
|
|
329
|
+
case 'table':
|
|
330
|
+
return `<table>${childrenHtml}</table>`;
|
|
331
|
+
case 'tableRow':
|
|
332
|
+
return `<tr>${childrenHtml}</tr>`;
|
|
333
|
+
case 'tableHeader':
|
|
334
|
+
return `<th>${childrenHtml}</th>`;
|
|
335
|
+
case 'tableCell':
|
|
336
|
+
return `<td>${childrenHtml}</td>`;
|
|
337
|
+
case 'panel': {
|
|
338
|
+
// panel タイプを GitHub Alerts 形式に変換
|
|
339
|
+
const panelType = typeof node.attrs?.['panelType'] === 'string' ? node.attrs['panelType'] : 'info';
|
|
340
|
+
const alertTypeMap = {
|
|
341
|
+
error: 'WARNING',
|
|
342
|
+
info: 'NOTE',
|
|
343
|
+
note: 'NOTE',
|
|
344
|
+
success: 'TIP',
|
|
345
|
+
warning: 'WARNING',
|
|
346
|
+
};
|
|
347
|
+
const alertType = alertTypeMap[panelType] || 'NOTE';
|
|
348
|
+
return `<blockquote data-github-alert="${alertType}">${childrenHtml}</blockquote>`;
|
|
349
|
+
}
|
|
350
|
+
// 未知のノードタイプは子ノードの内容を返す
|
|
351
|
+
default:
|
|
352
|
+
return childrenHtml;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// 子ノードもテキストもない場合は空文字列
|
|
356
|
+
return '';
|
|
357
|
+
};
|
|
358
|
+
/**
|
|
359
|
+
* ADF ドキュメントを HTML に変換する
|
|
360
|
+
*
|
|
361
|
+
* @param content ADF ドキュメントのコンテンツ配列
|
|
362
|
+
* @param attachmentPaths 添付ファイル ID → ローカルパスのマッピング
|
|
363
|
+
* @returns HTML 文字列
|
|
364
|
+
*/
|
|
365
|
+
const convertAdfContentToHtml = (content, attachmentPaths) => {
|
|
366
|
+
return content.map((node) => convertAdfNodeToHtml(node, attachmentPaths)).join('');
|
|
367
|
+
};
|
|
138
368
|
/**
|
|
139
369
|
* HTML エンティティをデコードする
|
|
140
370
|
*
|
|
@@ -348,20 +578,12 @@ const preprocessHtmlForMarkdown = (html, attachmentPaths) => {
|
|
|
348
578
|
return result;
|
|
349
579
|
};
|
|
350
580
|
/**
|
|
351
|
-
*
|
|
581
|
+
* TurndownService インスタンスを作成する(共通設定)
|
|
582
|
+
* Jira ADF と Confluence Storage Format の両方で使用する
|
|
352
583
|
*
|
|
353
|
-
* @
|
|
354
|
-
* @param attachmentPaths 添付ファイル名 → ローカルパスのマッピング
|
|
355
|
-
* @returns Markdown 文字列
|
|
584
|
+
* @returns 設定済みの TurndownService インスタンス
|
|
356
585
|
*/
|
|
357
|
-
|
|
358
|
-
// null または undefined の場合は空文字列を返す
|
|
359
|
-
if (storageFormat === null || storageFormat === undefined || storageFormat === '') {
|
|
360
|
-
return '';
|
|
361
|
-
}
|
|
362
|
-
// 前処理
|
|
363
|
-
const preprocessedHtml = preprocessHtmlForMarkdown(storageFormat, attachmentPaths);
|
|
364
|
-
// Turndown インスタンス作成
|
|
586
|
+
const createTurndownService = () => {
|
|
365
587
|
const turndownService = new TurndownService({
|
|
366
588
|
bulletListMarker: '-',
|
|
367
589
|
codeBlockStyle: 'fenced',
|
|
@@ -371,9 +593,7 @@ export const convertStorageFormatToMarkdown = (storageFormat, attachmentPaths) =
|
|
|
371
593
|
});
|
|
372
594
|
// GFM プラグイン(テーブル、取り消し線など)を使用
|
|
373
595
|
turndownService.use(gfm);
|
|
374
|
-
// --------------------------------------------------
|
|
375
596
|
// カスタムルール: キャプション付き画像(<figure>)
|
|
376
|
-
// --------------------------------------------------
|
|
377
597
|
turndownService.addRule('figureWithCaption', {
|
|
378
598
|
filter: (node) => {
|
|
379
599
|
return node.nodeName === 'FIGURE';
|
|
@@ -397,9 +617,7 @@ export const convertStorageFormatToMarkdown = (storageFormat, attachmentPaths) =
|
|
|
397
617
|
return '';
|
|
398
618
|
},
|
|
399
619
|
});
|
|
400
|
-
// --------------------------------------------------
|
|
401
620
|
// カスタムルール: GitHub Alerts(<blockquote data-github-alert="...">)
|
|
402
|
-
// --------------------------------------------------
|
|
403
621
|
turndownService.addRule('githubAlerts', {
|
|
404
622
|
filter: (node) => {
|
|
405
623
|
if (node.nodeName !== 'BLOCKQUOTE')
|
|
@@ -417,9 +635,7 @@ export const convertStorageFormatToMarkdown = (storageFormat, attachmentPaths) =
|
|
|
417
635
|
return `\n> [!${alertType}]\n${quotedContent}\n`;
|
|
418
636
|
},
|
|
419
637
|
});
|
|
420
|
-
// --------------------------------------------------
|
|
421
638
|
// カスタムルール: 色変更テキスト(HTML のまま出力)
|
|
422
|
-
// --------------------------------------------------
|
|
423
639
|
turndownService.addRule('coloredText', {
|
|
424
640
|
filter: (node) => {
|
|
425
641
|
if (node.nodeName !== 'SPAN')
|
|
@@ -432,9 +648,7 @@ export const convertStorageFormatToMarkdown = (storageFormat, attachmentPaths) =
|
|
|
432
648
|
return node.outerHTML;
|
|
433
649
|
},
|
|
434
650
|
});
|
|
435
|
-
// --------------------------------------------------
|
|
436
651
|
// カスタムルール: セル結合/セル内改行のあるテーブル(HTML のまま出力)
|
|
437
|
-
// --------------------------------------------------
|
|
438
652
|
turndownService.addRule('complexTable', {
|
|
439
653
|
filter: (node) => {
|
|
440
654
|
if (node.nodeName !== 'TABLE')
|
|
@@ -447,6 +661,65 @@ export const convertStorageFormatToMarkdown = (storageFormat, attachmentPaths) =
|
|
|
447
661
|
return node.outerHTML;
|
|
448
662
|
},
|
|
449
663
|
});
|
|
664
|
+
return turndownService;
|
|
665
|
+
};
|
|
666
|
+
/**
|
|
667
|
+
* ADF(Atlassian Document Format)を Markdown に変換する
|
|
668
|
+
*
|
|
669
|
+
* @param adf ADF ドキュメント(オブジェクトまたは JSON 文字列)
|
|
670
|
+
* @param attachmentPaths 添付ファイル ID → ローカルパスのマッピング
|
|
671
|
+
* @returns Markdown 文字列
|
|
672
|
+
*/
|
|
673
|
+
export const convertAdfToMarkdown = (adf, attachmentPaths) => {
|
|
674
|
+
// null または undefined の場合は空文字列を返す
|
|
675
|
+
if (adf === null || adf === undefined) {
|
|
676
|
+
return '';
|
|
677
|
+
}
|
|
678
|
+
// 文字列の場合は JSON としてパースを試みる
|
|
679
|
+
if (typeof adf === 'string') {
|
|
680
|
+
// 空文字列の場合
|
|
681
|
+
if (adf === '') {
|
|
682
|
+
return '';
|
|
683
|
+
}
|
|
684
|
+
try {
|
|
685
|
+
const parsed = JSON.parse(adf);
|
|
686
|
+
if (isAdfDocument(parsed)) {
|
|
687
|
+
const html = convertAdfContentToHtml(parsed.content, attachmentPaths);
|
|
688
|
+
const turndownService = createTurndownService();
|
|
689
|
+
return turndownService.turndown(html).trim();
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
catch {
|
|
693
|
+
// JSON パースに失敗した場合は元の文字列を返す
|
|
694
|
+
return adf;
|
|
695
|
+
}
|
|
696
|
+
// パースできたが ADF 形式でない場合は元の文字列を返す
|
|
697
|
+
return adf;
|
|
698
|
+
}
|
|
699
|
+
// オブジェクトの場合は ADF ドキュメントとして処理
|
|
700
|
+
if (isAdfDocument(adf)) {
|
|
701
|
+
const html = convertAdfContentToHtml(adf.content, attachmentPaths);
|
|
702
|
+
const turndownService = createTurndownService();
|
|
703
|
+
return turndownService.turndown(html).trim();
|
|
704
|
+
}
|
|
705
|
+
return '';
|
|
706
|
+
};
|
|
707
|
+
/**
|
|
708
|
+
* Confluence Storage Format(XHTML)を Markdown に変換する
|
|
709
|
+
*
|
|
710
|
+
* @param storageFormat Storage Format 文字列(HTML/XHTML)
|
|
711
|
+
* @param attachmentPaths 添付ファイル名 → ローカルパスのマッピング
|
|
712
|
+
* @returns Markdown 文字列
|
|
713
|
+
*/
|
|
714
|
+
export const convertStorageFormatToMarkdown = (storageFormat, attachmentPaths) => {
|
|
715
|
+
// null または undefined の場合は空文字列を返す
|
|
716
|
+
if (storageFormat === null || storageFormat === undefined || storageFormat === '') {
|
|
717
|
+
return '';
|
|
718
|
+
}
|
|
719
|
+
// 前処理
|
|
720
|
+
const preprocessedHtml = preprocessHtmlForMarkdown(storageFormat, attachmentPaths);
|
|
721
|
+
// 共通の TurndownService を使用
|
|
722
|
+
const turndownService = createTurndownService();
|
|
450
723
|
// Markdown に変換
|
|
451
724
|
const markdown = turndownService.turndown(preprocessedHtml);
|
|
452
725
|
// 末尾の空白を除去
|
package/dist/types/jira.d.ts
CHANGED
|
@@ -6,8 +6,10 @@ export interface JiraComment {
|
|
|
6
6
|
readonly id: string;
|
|
7
7
|
/** 作成者の表示名 */
|
|
8
8
|
readonly author: string;
|
|
9
|
-
/**
|
|
9
|
+
/** コメント本文(プレーンテキスト) */
|
|
10
10
|
readonly body: string;
|
|
11
|
+
/** コメント本文(ADF 形式、Markdown 変換用) */
|
|
12
|
+
readonly bodyAdf: unknown;
|
|
11
13
|
/** 作成日時(ISO 8601 形式) */
|
|
12
14
|
readonly created: string;
|
|
13
15
|
/** 更新日時(ISO 8601 形式) */
|
|
@@ -62,6 +64,8 @@ export interface JiraIssue {
|
|
|
62
64
|
readonly summary: string;
|
|
63
65
|
/** Issue 説明(null の場合は説明なし) */
|
|
64
66
|
readonly description: string | null;
|
|
67
|
+
/** Issue 説明(ADF 形式、Markdown 変換用) */
|
|
68
|
+
readonly descriptionAdf: unknown;
|
|
65
69
|
/** コメント一覧 */
|
|
66
70
|
readonly comments: readonly JiraComment[];
|
|
67
71
|
/** 変更履歴一覧 */
|
package/dist/types/storage.d.ts
CHANGED
|
@@ -93,9 +93,9 @@ export interface JiraSaveData {
|
|
|
93
93
|
readonly key: string;
|
|
94
94
|
/** Issue タイトル(要約) */
|
|
95
95
|
readonly summary: string;
|
|
96
|
-
/** Issue 説明(null の場合は説明なし) */
|
|
97
|
-
readonly description:
|
|
98
|
-
/** 説明のプレーンテキスト(null
|
|
96
|
+
/** Issue 説明(ADF 形式、null の場合は説明なし) */
|
|
97
|
+
readonly description: unknown;
|
|
98
|
+
/** 説明のプレーンテキスト(null の場合は説明なし、後方互換性のため維持) */
|
|
99
99
|
readonly descriptionPlainText: string | null;
|
|
100
100
|
/** コメント一覧 */
|
|
101
101
|
readonly comments: readonly JiraComment[];
|
package/package.json
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"got": "14.6.6",
|
|
13
13
|
"jsdom": "27.4.0",
|
|
14
14
|
"neverthrow": "8.2.0",
|
|
15
|
+
"ora": "^9.0.0",
|
|
16
|
+
"picocolors": "^1.1.1",
|
|
15
17
|
"turndown": "7.2.2",
|
|
16
18
|
"turndown-plugin-gfm": "1.0.2",
|
|
17
19
|
"yaml": "2.8.2",
|
|
@@ -80,7 +82,7 @@
|
|
|
80
82
|
},
|
|
81
83
|
"type": "module",
|
|
82
84
|
"types": "./dist/index.d.ts",
|
|
83
|
-
"version": "1.
|
|
85
|
+
"version": "1.2.0",
|
|
84
86
|
"scripts": {
|
|
85
87
|
"build": "tsc",
|
|
86
88
|
"dev": "tsc --watch",
|
package/dist/types/result.d.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Result 型 - 成功または失敗を表現する discriminated union
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```typescript
|
|
6
|
-
* function divide(a: number, b: number): Result<number, DivisionError> {
|
|
7
|
-
* if (b === 0) {
|
|
8
|
-
* return err({ kind: 'DIVISION_BY_ZERO', message: 'Cannot divide by zero' });
|
|
9
|
-
* }
|
|
10
|
-
* return ok(a / b);
|
|
11
|
-
* }
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* 成功を表す型
|
|
16
|
-
*/
|
|
17
|
-
export interface Ok<T> {
|
|
18
|
-
readonly success: true;
|
|
19
|
-
readonly value: T;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* 失敗を表す型
|
|
23
|
-
*/
|
|
24
|
-
export interface Err<E> {
|
|
25
|
-
readonly success: false;
|
|
26
|
-
readonly error: E;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Result 型 - 成功(Ok)または失敗(Err)のどちらかを表す
|
|
30
|
-
*/
|
|
31
|
-
export type Result<T, E> = Ok<T> | Err<E>;
|
|
32
|
-
/**
|
|
33
|
-
* 成功 Result を作成する
|
|
34
|
-
*
|
|
35
|
-
* @param value - 成功値
|
|
36
|
-
* @returns 成功 Result
|
|
37
|
-
*/
|
|
38
|
-
export declare function ok<T>(value: T): Ok<T>;
|
|
39
|
-
/**
|
|
40
|
-
* 失敗 Result を作成する
|
|
41
|
-
*
|
|
42
|
-
* @param error - エラー値
|
|
43
|
-
* @returns 失敗 Result
|
|
44
|
-
*/
|
|
45
|
-
export declare function err<E>(error: E): Err<E>;
|
|
46
|
-
/**
|
|
47
|
-
* Result が成功かどうかを判定する型ガード
|
|
48
|
-
*
|
|
49
|
-
* @param result - 判定対象の Result
|
|
50
|
-
* @returns 成功の場合 true
|
|
51
|
-
*/
|
|
52
|
-
export declare function isOk<T, E>(result: Result<T, E>): result is Ok<T>;
|
|
53
|
-
/**
|
|
54
|
-
* Result が失敗かどうかを判定する型ガード
|
|
55
|
-
*
|
|
56
|
-
* @param result - 判定対象の Result
|
|
57
|
-
* @returns 失敗の場合 true
|
|
58
|
-
*/
|
|
59
|
-
export declare function isErr<T, E>(result: Result<T, E>): result is Err<E>;
|
|
60
|
-
/**
|
|
61
|
-
* 成功 Result から値を取り出す
|
|
62
|
-
* 失敗 Result の場合はエラーをスローする
|
|
63
|
-
*
|
|
64
|
-
* @param result - 対象の Result
|
|
65
|
-
* @returns 成功値
|
|
66
|
-
* @throws 失敗 Result の場合
|
|
67
|
-
*/
|
|
68
|
-
export declare function unwrap<T, E>(result: Result<T, E>): T;
|
|
69
|
-
/**
|
|
70
|
-
* 失敗 Result からエラー値を取り出す
|
|
71
|
-
* 成功 Result の場合はエラーをスローする
|
|
72
|
-
*
|
|
73
|
-
* @param result - 対象の Result
|
|
74
|
-
* @returns エラー値
|
|
75
|
-
* @throws 成功 Result の場合
|
|
76
|
-
*/
|
|
77
|
-
export declare function unwrapErr<T, E>(result: Result<T, E>): E;
|
|
78
|
-
/**
|
|
79
|
-
* 成功 Result から値を取り出す
|
|
80
|
-
* 失敗 Result の場合はデフォルト値を返す
|
|
81
|
-
*
|
|
82
|
-
* @param result - 対象の Result
|
|
83
|
-
* @param defaultValue - 失敗時のデフォルト値
|
|
84
|
-
* @returns 成功値またはデフォルト値
|
|
85
|
-
*/
|
|
86
|
-
export declare function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T;
|
|
87
|
-
/**
|
|
88
|
-
* 成功 Result の値を変換する
|
|
89
|
-
* 失敗 Result の場合はそのまま返す
|
|
90
|
-
*
|
|
91
|
-
* @param result - 対象の Result
|
|
92
|
-
* @param fn - 変換関数
|
|
93
|
-
* @returns 変換された Result
|
|
94
|
-
*/
|
|
95
|
-
export declare function mapResult<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
|
|
96
|
-
/**
|
|
97
|
-
* 失敗 Result のエラー値を変換する
|
|
98
|
-
* 成功 Result の場合はそのまま返す
|
|
99
|
-
*
|
|
100
|
-
* @param result - 対象の Result
|
|
101
|
-
* @param fn - 変換関数
|
|
102
|
-
* @returns 変換された Result
|
|
103
|
-
*/
|
|
104
|
-
export declare function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;
|
package/dist/types/result.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Result 型 - 成功または失敗を表現する discriminated union
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```typescript
|
|
6
|
-
* function divide(a: number, b: number): Result<number, DivisionError> {
|
|
7
|
-
* if (b === 0) {
|
|
8
|
-
* return err({ kind: 'DIVISION_BY_ZERO', message: 'Cannot divide by zero' });
|
|
9
|
-
* }
|
|
10
|
-
* return ok(a / b);
|
|
11
|
-
* }
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
/**
|
|
15
|
-
* 成功 Result を作成する
|
|
16
|
-
*
|
|
17
|
-
* @param value - 成功値
|
|
18
|
-
* @returns 成功 Result
|
|
19
|
-
*/
|
|
20
|
-
export function ok(value) {
|
|
21
|
-
return { success: true, value };
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* 失敗 Result を作成する
|
|
25
|
-
*
|
|
26
|
-
* @param error - エラー値
|
|
27
|
-
* @returns 失敗 Result
|
|
28
|
-
*/
|
|
29
|
-
export function err(error) {
|
|
30
|
-
return { error, success: false };
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Result が成功かどうかを判定する型ガード
|
|
34
|
-
*
|
|
35
|
-
* @param result - 判定対象の Result
|
|
36
|
-
* @returns 成功の場合 true
|
|
37
|
-
*/
|
|
38
|
-
export function isOk(result) {
|
|
39
|
-
return result.success;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Result が失敗かどうかを判定する型ガード
|
|
43
|
-
*
|
|
44
|
-
* @param result - 判定対象の Result
|
|
45
|
-
* @returns 失敗の場合 true
|
|
46
|
-
*/
|
|
47
|
-
export function isErr(result) {
|
|
48
|
-
return !result.success;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* 成功 Result から値を取り出す
|
|
52
|
-
* 失敗 Result の場合はエラーをスローする
|
|
53
|
-
*
|
|
54
|
-
* @param result - 対象の Result
|
|
55
|
-
* @returns 成功値
|
|
56
|
-
* @throws 失敗 Result の場合
|
|
57
|
-
*/
|
|
58
|
-
export function unwrap(result) {
|
|
59
|
-
if (isOk(result)) {
|
|
60
|
-
return result.value;
|
|
61
|
-
}
|
|
62
|
-
throw new Error(`Attempted to unwrap an Err value: ${String(result.error)}`);
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* 失敗 Result からエラー値を取り出す
|
|
66
|
-
* 成功 Result の場合はエラーをスローする
|
|
67
|
-
*
|
|
68
|
-
* @param result - 対象の Result
|
|
69
|
-
* @returns エラー値
|
|
70
|
-
* @throws 成功 Result の場合
|
|
71
|
-
*/
|
|
72
|
-
export function unwrapErr(result) {
|
|
73
|
-
if (isErr(result)) {
|
|
74
|
-
return result.error;
|
|
75
|
-
}
|
|
76
|
-
throw new Error('Attempted to unwrapErr an Ok value');
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* 成功 Result から値を取り出す
|
|
80
|
-
* 失敗 Result の場合はデフォルト値を返す
|
|
81
|
-
*
|
|
82
|
-
* @param result - 対象の Result
|
|
83
|
-
* @param defaultValue - 失敗時のデフォルト値
|
|
84
|
-
* @returns 成功値またはデフォルト値
|
|
85
|
-
*/
|
|
86
|
-
export function unwrapOr(result, defaultValue) {
|
|
87
|
-
if (isOk(result)) {
|
|
88
|
-
return result.value;
|
|
89
|
-
}
|
|
90
|
-
return defaultValue;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* 成功 Result の値を変換する
|
|
94
|
-
* 失敗 Result の場合はそのまま返す
|
|
95
|
-
*
|
|
96
|
-
* @param result - 対象の Result
|
|
97
|
-
* @param fn - 変換関数
|
|
98
|
-
* @returns 変換された Result
|
|
99
|
-
*/
|
|
100
|
-
export function mapResult(result, fn) {
|
|
101
|
-
if (isOk(result)) {
|
|
102
|
-
return ok(fn(result.value));
|
|
103
|
-
}
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* 失敗 Result のエラー値を変換する
|
|
108
|
-
* 成功 Result の場合はそのまま返す
|
|
109
|
-
*
|
|
110
|
-
* @param result - 対象の Result
|
|
111
|
-
* @param fn - 変換関数
|
|
112
|
-
* @returns 変換された Result
|
|
113
|
-
*/
|
|
114
|
-
export function mapErr(result, fn) {
|
|
115
|
-
if (isErr(result)) {
|
|
116
|
-
return err(fn(result.error));
|
|
117
|
-
}
|
|
118
|
-
return result;
|
|
119
|
-
}
|