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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -0
  3. package/dist/cli/cli.d.ts +61 -0
  4. package/dist/cli/cli.js +131 -0
  5. package/dist/cli/index.d.ts +5 -0
  6. package/dist/cli/index.js +4 -0
  7. package/dist/index.d.ts +8 -0
  8. package/dist/index.js +13 -0
  9. package/dist/ports/file/file-port.d.ts +89 -0
  10. package/dist/ports/file/file-port.js +155 -0
  11. package/dist/ports/file/index.d.ts +1 -0
  12. package/dist/ports/file/index.js +1 -0
  13. package/dist/ports/http/http-port.d.ts +107 -0
  14. package/dist/ports/http/http-port.js +238 -0
  15. package/dist/ports/http/index.d.ts +1 -0
  16. package/dist/ports/http/index.js +1 -0
  17. package/dist/services/auth/auth-service.d.ts +79 -0
  18. package/dist/services/auth/auth-service.js +158 -0
  19. package/dist/services/auth/index.d.ts +1 -0
  20. package/dist/services/auth/index.js +1 -0
  21. package/dist/services/confluence/confluence-service.d.ts +152 -0
  22. package/dist/services/confluence/confluence-service.js +510 -0
  23. package/dist/services/confluence/index.d.ts +1 -0
  24. package/dist/services/confluence/index.js +1 -0
  25. package/dist/services/diff/diff-service.d.ts +84 -0
  26. package/dist/services/diff/diff-service.js +881 -0
  27. package/dist/services/diff/index.d.ts +1 -0
  28. package/dist/services/diff/index.js +1 -0
  29. package/dist/services/fetch/fetch-service.d.ts +112 -0
  30. package/dist/services/fetch/fetch-service.js +302 -0
  31. package/dist/services/fetch/index.d.ts +1 -0
  32. package/dist/services/fetch/index.js +1 -0
  33. package/dist/services/jira/index.d.ts +1 -0
  34. package/dist/services/jira/index.js +1 -0
  35. package/dist/services/jira/jira-service.d.ts +100 -0
  36. package/dist/services/jira/jira-service.js +354 -0
  37. package/dist/services/output/index.d.ts +4 -0
  38. package/dist/services/output/index.js +4 -0
  39. package/dist/services/output/output-service.d.ts +67 -0
  40. package/dist/services/output/output-service.js +228 -0
  41. package/dist/services/storage/index.d.ts +6 -0
  42. package/dist/services/storage/index.js +6 -0
  43. package/dist/services/storage/storage-service.d.ts +77 -0
  44. package/dist/services/storage/storage-service.js +738 -0
  45. package/dist/services/text-converter/index.d.ts +1 -0
  46. package/dist/services/text-converter/index.js +1 -0
  47. package/dist/services/text-converter/text-converter.d.ts +35 -0
  48. package/dist/services/text-converter/text-converter.js +681 -0
  49. package/dist/services/url-parser/index.d.ts +1 -0
  50. package/dist/services/url-parser/index.js +1 -0
  51. package/dist/services/url-parser/url-parser.d.ts +43 -0
  52. package/dist/services/url-parser/url-parser.js +283 -0
  53. package/dist/types/auth.d.ts +25 -0
  54. package/dist/types/auth.js +1 -0
  55. package/dist/types/confluence.d.ts +68 -0
  56. package/dist/types/confluence.js +1 -0
  57. package/dist/types/diff.d.ts +77 -0
  58. package/dist/types/diff.js +7 -0
  59. package/dist/types/fetch.d.ts +65 -0
  60. package/dist/types/fetch.js +1 -0
  61. package/dist/types/file.d.ts +22 -0
  62. package/dist/types/file.js +1 -0
  63. package/dist/types/http.d.ts +45 -0
  64. package/dist/types/http.js +1 -0
  65. package/dist/types/jira.d.ts +90 -0
  66. package/dist/types/jira.js +1 -0
  67. package/dist/types/output.d.ts +55 -0
  68. package/dist/types/output.js +7 -0
  69. package/dist/types/result.d.ts +104 -0
  70. package/dist/types/result.js +119 -0
  71. package/dist/types/storage.d.ts +209 -0
  72. package/dist/types/storage.js +6 -0
  73. package/dist/types/url-parser.d.ts +46 -0
  74. package/dist/types/url-parser.js +1 -0
  75. package/package.json +106 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 仙波 琉一朗 / Ryuichiro Semba
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # atl-fetch
2
+
3
+ [![CI](https://github.com/semba-yui/atl-fetch/actions/workflows/ci.yml/badge.svg)](https://github.com/semba-yui/atl-fetch/actions/workflows/ci.yml)
4
+ [![npm version](https://badge.fury.io/js/atl-fetch.svg)](https://www.npmjs.com/package/atl-fetch)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=semba-yui_atl-fetch\&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=semba-yui_atl-fetch)
7
+ ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/semba-yui/atl-fetch?utm_source=oss\&utm_medium=github\&utm_campaign=semba-yui%2Fatl-fetch\&labelColor=171717\&color=FF570A\&link=https%3A%2F%2Fcoderabbit.ai\&label=CodeRabbit+Reviews)
8
+ [![DeepWiki](https://img.shields.io/badge/DeepWiki-semba--yui%2Fatl--fetch-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/semba-yui/atl-fetch)
9
+
10
+ Atlassian Cloud(Jira / Confluence)から情報を取得する Node.js CLI ツール兼ライブラリです。
11
+
12
+ ## 主な機能
13
+
14
+ - **Jira Issue 取得**: タイトル、説明、コメント、変更履歴、添付ファイル
15
+ - **Confluence ページ取得**: タイトル、本文、バージョン履歴、添付ファイル
16
+ - **複数出力形式**: JSON / Markdown / YAML
17
+ - **差分表示**: バージョン間の Unified diff 形式表示
18
+ - **添付ファイルダウンロード**: 指定ディレクトリへの保存
19
+
20
+ ## 動作要件
21
+
22
+ - Node.js 22.0.0 以上
23
+ - pnpm(推奨)または npm
24
+
25
+ ## インストール
26
+
27
+ ```bash
28
+ # npm
29
+ npm install -g atl-fetch
30
+
31
+ # pnpm
32
+ pnpm add -g atl-fetch
33
+ ```
34
+
35
+ ## クイックスタート
36
+
37
+ ### 1. 環境変数の設定
38
+
39
+ ```bash
40
+ export ATLASSIAN_DOMAIN="your-domain.atlassian.net"
41
+ export ATLASSIAN_EMAIL="your-email@example.com"
42
+ export ATLASSIAN_API_TOKEN="your-api-token"
43
+ ```
44
+
45
+ API トークンは [Atlassian Account Settings](https://id.atlassian.com/manage-profile/security/api-tokens) から取得できます。
46
+
47
+ ### 2. 基本的な使用方法
48
+
49
+ ```bash
50
+ # Jira Issue を取得
51
+ atl-fetch https://your-domain.atlassian.net/browse/PROJECT-123
52
+
53
+ # Confluence ページを取得
54
+ atl-fetch https://your-domain.atlassian.net/wiki/spaces/SPACE/pages/123456/Page+Title
55
+
56
+ # Markdown 形式で出力
57
+ atl-fetch https://your-domain.atlassian.net/browse/PROJECT-123 --format markdown
58
+
59
+ # ファイルに保存
60
+ atl-fetch https://your-domain.atlassian.net/browse/PROJECT-123 --output result.json
61
+ ```
62
+
63
+ ## CLI オプション
64
+
65
+ | オプション | 短縮形 | 説明 | デフォルト |
66
+ | ------------------------ | ---- | ---------------------------- | ------------- |
67
+ | `--format` | `-f` | 出力形式(json / markdown / yaml) | json |
68
+ | `--output` | `-o` | 出力ファイルパス | stdout |
69
+ | `--include-comments` | `-c` | コメントを含める | false |
70
+ | `--include-history` | `-h` | 変更履歴を含める | false |
71
+ | `--include-attachments` | `-a` | 添付ファイルを含める | false |
72
+ | `--download-attachments` | `-d` | 添付ファイルをダウンロード | false |
73
+ | `--attachments-dir` | | 添付ファイルの保存先 | ./attachments |
74
+ | `--diff` | | 指定バージョンとの差分を表示 | - |
75
+ | `--help` | | ヘルプを表示 | - |
76
+ | `--version` | | バージョンを表示 | - |
77
+
78
+ ## ライブラリとしての使用
79
+
80
+ ```typescript
81
+ import { fetchJiraIssue, fetchConfluencePage } from 'atl-fetch';
82
+
83
+ // Jira Issue を取得
84
+ const jiraResult = await fetchJiraIssue({
85
+ url: 'https://your-domain.atlassian.net/browse/PROJECT-123',
86
+ includeComments: true,
87
+ includeHistory: false,
88
+ });
89
+
90
+ if (jiraResult.isOk()) {
91
+ console.log(jiraResult.value);
92
+ } else {
93
+ console.error(jiraResult.error);
94
+ }
95
+
96
+ // Confluence ページを取得
97
+ const confluenceResult = await fetchConfluencePage({
98
+ url: 'https://your-domain.atlassian.net/wiki/spaces/SPACE/pages/123456/Page+Title',
99
+ includeHistory: true,
100
+ });
101
+
102
+ if (confluenceResult.isOk()) {
103
+ console.log(confluenceResult.value);
104
+ }
105
+ ```
106
+
107
+ ## ライセンス
108
+
109
+ [MIT](LICENSE)
110
+
111
+ ## 貢献
112
+
113
+ [CONTRIBUTING.md](CONTRIBUTING.md) をご覧ください。
@@ -0,0 +1,61 @@
1
+ /**
2
+ * CLI エントリーポイント
3
+ *
4
+ * yargs を使用した CLI インターフェースを提供する。
5
+ */
6
+ /**
7
+ * CLI の引数の型
8
+ */
9
+ export interface CliArgs {
10
+ /** Atlassian Cloud URL */
11
+ url: string;
12
+ /** 出力形式(json/markdown/yaml) */
13
+ format: 'json' | 'markdown' | 'yaml';
14
+ /** 添付ファイルダウンロードを有効にする */
15
+ download: boolean;
16
+ /** 保存先ディレクトリ */
17
+ dir?: string;
18
+ /** 差分のみを出力する */
19
+ diff: boolean;
20
+ /** カラー出力を有効にする */
21
+ color: boolean;
22
+ }
23
+ /**
24
+ * CLI 作成オプション
25
+ */
26
+ export interface CliOptions {
27
+ /** process.exit を呼び出すかどうか(テスト時は false にする) */
28
+ exitProcess?: boolean;
29
+ }
30
+ /**
31
+ * CLI インスタンスを作成する
32
+ *
33
+ * yargs を使用して CLI 引数をパースするインスタンスを返す。
34
+ *
35
+ * @param options CLI 作成オプション
36
+ * @returns yargs インスタンス
37
+ */
38
+ export declare function createCli(options?: CliOptions): import("yargs").Argv<{
39
+ format: "json" | "markdown" | "yaml";
40
+ } & {
41
+ download: boolean;
42
+ } & {
43
+ dir: string | undefined;
44
+ } & {
45
+ diff: boolean;
46
+ } & {
47
+ color: boolean;
48
+ }>;
49
+ /**
50
+ * CLI を実行する
51
+ *
52
+ * process.argv から引数を取得してパースし、適切な処理を実行する。
53
+ * メインエントリーポイントとして使用する。
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * // メインエントリーポイント
58
+ * await runCli();
59
+ * ```
60
+ */
61
+ export declare function runCli(): Promise<void>;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * CLI エントリーポイント
3
+ *
4
+ * yargs を使用した CLI インターフェースを提供する。
5
+ */
6
+ import { createRequire } from 'node:module';
7
+ import yargs from 'yargs';
8
+ import { hideBin } from 'yargs/helpers';
9
+ import { fetchAndOutput, fetchAndSave } from '../services/fetch/fetch-service.js';
10
+ const require = createRequire(import.meta.url);
11
+ const packageJson = require('../../package.json');
12
+ /**
13
+ * CLI バージョン(package.json から取得)
14
+ */
15
+ const CLI_VERSION = packageJson.version;
16
+ /**
17
+ * CLI インスタンスを作成する
18
+ *
19
+ * yargs を使用して CLI 引数をパースするインスタンスを返す。
20
+ *
21
+ * @param options CLI 作成オプション
22
+ * @returns yargs インスタンス
23
+ */
24
+ export function createCli(options = {}) {
25
+ const { exitProcess = true } = options;
26
+ return yargs()
27
+ .scriptName('atl-fetch')
28
+ .usage('Usage: $0 <url> [options]')
29
+ .command('$0 <url>', 'Atlassian Cloud の URL から情報を取得する', (yargs) => {
30
+ return yargs.positional('url', {
31
+ demandOption: true,
32
+ describe: 'Atlassian Cloud URL (Jira Issue または Confluence ページ)',
33
+ type: 'string',
34
+ });
35
+ })
36
+ .option('format', {
37
+ alias: 'f',
38
+ choices: ['json', 'markdown', 'yaml'],
39
+ default: 'json',
40
+ describe: '出力形式',
41
+ type: 'string',
42
+ })
43
+ .option('download', {
44
+ alias: 'd',
45
+ default: false,
46
+ describe: '添付ファイルをダウンロードする',
47
+ type: 'boolean',
48
+ })
49
+ .option('dir', {
50
+ alias: 'o',
51
+ describe: '保存先ディレクトリ',
52
+ type: 'string',
53
+ })
54
+ .check((argv) => {
55
+ // --dir オプションは --download オプションと一緒に指定する必要がある
56
+ if (argv['dir'] !== undefined && !argv['download']) {
57
+ throw new Error('--dir オプションは --download オプションと一緒に指定してください');
58
+ }
59
+ return true;
60
+ })
61
+ .option('diff', {
62
+ default: false,
63
+ describe: '差分のみを出力する',
64
+ type: 'boolean',
65
+ })
66
+ .option('color', {
67
+ default: true,
68
+ describe: 'カラー出力を有効にする',
69
+ type: 'boolean',
70
+ })
71
+ .help('help')
72
+ .alias('h', 'help')
73
+ .version(CLI_VERSION)
74
+ .alias('V', 'version')
75
+ .strict()
76
+ .exitProcess(exitProcess)
77
+ .demandCommand(1, 'URL を指定してください')
78
+ .fail((msg, err) => {
79
+ if (err) {
80
+ throw err;
81
+ }
82
+ throw new Error(msg);
83
+ })
84
+ .wrap(null);
85
+ }
86
+ /**
87
+ * CLI を実行する
88
+ *
89
+ * process.argv から引数を取得してパースし、適切な処理を実行する。
90
+ * メインエントリーポイントとして使用する。
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * // メインエントリーポイント
95
+ * await runCli();
96
+ * ```
97
+ */
98
+ export async function runCli() {
99
+ const cli = createCli();
100
+ const argv = await cli.parse(hideBin(process.argv));
101
+ const url = argv['url'];
102
+ const format = argv['format'];
103
+ const download = argv['download'];
104
+ const dir = argv['dir'];
105
+ const colorEnabled = argv['color'];
106
+ // ダウンロードモード
107
+ if (download) {
108
+ const baseDir = dir ?? process.cwd();
109
+ const result = await fetchAndSave(url, {
110
+ baseDir,
111
+ cliVersion: CLI_VERSION,
112
+ sourceUrl: url,
113
+ });
114
+ if (result.isErr()) {
115
+ console.error(`エラー: ${result.error.message}`);
116
+ process.exit(1);
117
+ }
118
+ console.log(`保存完了: ${result.value.directory}`);
119
+ return;
120
+ }
121
+ // 通常モード(標準出力)
122
+ const result = await fetchAndOutput(url, {
123
+ colorEnabled,
124
+ format,
125
+ });
126
+ if (result.isErr()) {
127
+ console.error(`エラー: ${result.error.message}`);
128
+ process.exit(1);
129
+ }
130
+ console.log(result.value);
131
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * CLI モジュールのバレルエクスポート
3
+ */
4
+ export type { CliArgs, CliOptions } from './cli.js';
5
+ export { createCli, runCli } from './cli.js';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * CLI モジュールのバレルエクスポート
3
+ */
4
+ export { createCli, runCli } from './cli.js';
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * atl-fetch - Atlassian Cloud からコンテンツを取得する CLI ツール
4
+ *
5
+ * CLI エントリーポイント。
6
+ * このファイルは `npx atl-fetch` または `atl-fetch` コマンドとして実行される。
7
+ */
8
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * atl-fetch - Atlassian Cloud からコンテンツを取得する CLI ツール
4
+ *
5
+ * CLI エントリーポイント。
6
+ * このファイルは `npx atl-fetch` または `atl-fetch` コマンドとして実行される。
7
+ */
8
+ import { runCli } from './cli/index.js';
9
+ // CLI を実行
10
+ runCli().catch((error) => {
11
+ console.error('エラーが発生しました:', error instanceof Error ? error.message : error);
12
+ process.exit(1);
13
+ });
@@ -0,0 +1,89 @@
1
+ import type { Readable } from 'node:stream';
2
+ import { type Result } from 'neverthrow';
3
+ import type { FileError } from '../../types/file.js';
4
+ /**
5
+ * ファイルにテキストコンテンツを書き込む
6
+ *
7
+ * UTF-8 エンコーディングで指定されたパスにテキストを書き込む。
8
+ * 親ディレクトリが存在しない場合はエラーを返す。
9
+ *
10
+ * @param path - 書き込み先のファイルパス
11
+ * @param content - 書き込むテキストコンテンツ
12
+ * @returns 成功時は Ok(void)、失敗時は Err(FileError)
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const result = await writeFileContent('/path/to/file.txt', 'Hello, World!');
17
+ * if (result.isOk()) {
18
+ * console.log('ファイルを書き込みました');
19
+ * }
20
+ * ```
21
+ */
22
+ export declare function writeFileContent(path: string, content: string): Promise<Result<void, FileError>>;
23
+ /**
24
+ * ストリームからファイルに書き込む
25
+ *
26
+ * Node.js の Readable ストリームを受け取り、指定されたパスにファイルとして書き込む。
27
+ * 大きなファイルのダウンロードに適している。
28
+ *
29
+ * @param path - 書き込み先のファイルパス
30
+ * @param stream - 読み取り元のストリーム
31
+ * @returns 成功時は Ok(void)、失敗時は Err(FileError)
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { Readable } from 'node:stream';
36
+ *
37
+ * const stream = Readable.from(['chunk1', 'chunk2']);
38
+ * const result = await writeStream('/path/to/file.bin', stream);
39
+ * if (result.isOk()) {
40
+ * console.log('ストリームを書き込みました');
41
+ * }
42
+ * ```
43
+ */
44
+ export declare function writeStream(path: string, stream: Readable): Promise<Result<void, FileError>>;
45
+ /**
46
+ * ディレクトリを再帰的に作成する
47
+ *
48
+ * 指定されたパスにディレクトリを作成する。中間ディレクトリも自動的に作成される。
49
+ * 既にディレクトリが存在する場合は何もせずに成功を返す。
50
+ *
51
+ * @param path - 作成するディレクトリパス
52
+ * @returns 成功時は Ok(void)、失敗時は Err(FileError)
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const result = await ensureDir('/path/to/nested/directory');
57
+ * if (result.isOk()) {
58
+ * console.log('ディレクトリを作成しました');
59
+ * }
60
+ * ```
61
+ */
62
+ export declare function ensureDir(path: string): Promise<Result<void, FileError>>;
63
+ /**
64
+ * ファイルまたはディレクトリの存在を確認する
65
+ *
66
+ * 指定されたパスにファイルまたはディレクトリが存在するかを確認する。
67
+ * アクセス権限がない場合も false を返す。
68
+ *
69
+ * @param path - 確認するパス
70
+ * @returns ファイルまたはディレクトリが存在する場合は true、そうでない場合は false
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * if (await exists('/path/to/file.txt')) {
75
+ * console.log('ファイルが存在します');
76
+ * }
77
+ * ```
78
+ */
79
+ export declare function exists(path: string): Promise<boolean>;
80
+ /**
81
+ * エラーを FileError にマッピングする
82
+ *
83
+ * @param path - 操作対象のパス
84
+ * @param error - キャッチしたエラー
85
+ * @returns 対応する FileError
86
+ *
87
+ * @internal テスト用に export
88
+ */
89
+ export declare function mapErrorToFileError(path: string, error: unknown): FileError;
@@ -0,0 +1,155 @@
1
+ import { createWriteStream } from 'node:fs';
2
+ import { access, mkdir, writeFile } from 'node:fs/promises';
3
+ import { pipeline } from 'node:stream/promises';
4
+ import { err, ok } from 'neverthrow';
5
+ /**
6
+ * ファイルにテキストコンテンツを書き込む
7
+ *
8
+ * UTF-8 エンコーディングで指定されたパスにテキストを書き込む。
9
+ * 親ディレクトリが存在しない場合はエラーを返す。
10
+ *
11
+ * @param path - 書き込み先のファイルパス
12
+ * @param content - 書き込むテキストコンテンツ
13
+ * @returns 成功時は Ok(void)、失敗時は Err(FileError)
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const result = await writeFileContent('/path/to/file.txt', 'Hello, World!');
18
+ * if (result.isOk()) {
19
+ * console.log('ファイルを書き込みました');
20
+ * }
21
+ * ```
22
+ */
23
+ export async function writeFileContent(path, content) {
24
+ try {
25
+ await writeFile(path, content, 'utf-8');
26
+ return ok(undefined);
27
+ }
28
+ catch (error) {
29
+ return err(mapErrorToFileError(path, error));
30
+ }
31
+ }
32
+ /**
33
+ * ストリームからファイルに書き込む
34
+ *
35
+ * Node.js の Readable ストリームを受け取り、指定されたパスにファイルとして書き込む。
36
+ * 大きなファイルのダウンロードに適している。
37
+ *
38
+ * @param path - 書き込み先のファイルパス
39
+ * @param stream - 読み取り元のストリーム
40
+ * @returns 成功時は Ok(void)、失敗時は Err(FileError)
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * import { Readable } from 'node:stream';
45
+ *
46
+ * const stream = Readable.from(['chunk1', 'chunk2']);
47
+ * const result = await writeStream('/path/to/file.bin', stream);
48
+ * if (result.isOk()) {
49
+ * console.log('ストリームを書き込みました');
50
+ * }
51
+ * ```
52
+ */
53
+ export async function writeStream(path, stream) {
54
+ try {
55
+ const writeStream = createWriteStream(path);
56
+ await pipeline(stream, writeStream);
57
+ return ok(undefined);
58
+ }
59
+ catch (error) {
60
+ return err(mapErrorToFileError(path, error));
61
+ }
62
+ }
63
+ /**
64
+ * ディレクトリを再帰的に作成する
65
+ *
66
+ * 指定されたパスにディレクトリを作成する。中間ディレクトリも自動的に作成される。
67
+ * 既にディレクトリが存在する場合は何もせずに成功を返す。
68
+ *
69
+ * @param path - 作成するディレクトリパス
70
+ * @returns 成功時は Ok(void)、失敗時は Err(FileError)
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const result = await ensureDir('/path/to/nested/directory');
75
+ * if (result.isOk()) {
76
+ * console.log('ディレクトリを作成しました');
77
+ * }
78
+ * ```
79
+ */
80
+ export async function ensureDir(path) {
81
+ try {
82
+ await mkdir(path, { recursive: true });
83
+ return ok(undefined);
84
+ }
85
+ catch (error) {
86
+ return err(mapErrorToFileError(path, error));
87
+ }
88
+ }
89
+ /**
90
+ * ファイルまたはディレクトリの存在を確認する
91
+ *
92
+ * 指定されたパスにファイルまたはディレクトリが存在するかを確認する。
93
+ * アクセス権限がない場合も false を返す。
94
+ *
95
+ * @param path - 確認するパス
96
+ * @returns ファイルまたはディレクトリが存在する場合は true、そうでない場合は false
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * if (await exists('/path/to/file.txt')) {
101
+ * console.log('ファイルが存在します');
102
+ * }
103
+ * ```
104
+ */
105
+ export async function exists(path) {
106
+ try {
107
+ await access(path);
108
+ return true;
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ }
114
+ /**
115
+ * エラーを FileError にマッピングする
116
+ *
117
+ * @param path - 操作対象のパス
118
+ * @param error - キャッチしたエラー
119
+ * @returns 対応する FileError
120
+ *
121
+ * @internal テスト用に export
122
+ */
123
+ export function mapErrorToFileError(path, error) {
124
+ if (!(error instanceof Error)) {
125
+ return {
126
+ kind: 'WRITE_FAILED',
127
+ message: '不明なエラーが発生しました',
128
+ path,
129
+ };
130
+ }
131
+ const nodeError = error;
132
+ const code = nodeError.code;
133
+ // パーミッションエラー
134
+ if (code === 'EACCES' || code === 'EPERM') {
135
+ return {
136
+ kind: 'PERMISSION_DENIED',
137
+ message: `ファイルへのアクセス権限がありません: ${error.message}`,
138
+ path,
139
+ };
140
+ }
141
+ // ディスク容量不足
142
+ if (code === 'ENOSPC') {
143
+ return {
144
+ kind: 'DISK_FULL',
145
+ message: `ディスク容量が不足しています: ${error.message}`,
146
+ path,
147
+ };
148
+ }
149
+ // その他のエラー(ディレクトリが存在しない、等)
150
+ return {
151
+ kind: 'WRITE_FAILED',
152
+ message: `ファイル書き込みに失敗しました: ${error.message}`,
153
+ path,
154
+ };
155
+ }
@@ -0,0 +1 @@
1
+ export { ensureDir, exists, writeFileContent, writeStream } from './file-port.js';
@@ -0,0 +1 @@
1
+ export { ensureDir, exists, writeFileContent, writeStream } from './file-port.js';