browser-git-ops 0.0.0 → 0.0.1
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 -21
- package/README.md +146 -146
- package/dist/git/githubAdapter.d.ts.map +1 -1
- package/dist/test/e2e/virtualfs.spec.js +61 -61
- package/dist/virtualfs/virtualfs.d.ts +3 -2
- package/dist/virtualfs/virtualfs.d.ts.map +1 -1
- package/dist/virtualfs/virtualfs.js +3 -4
- package/package.json +47 -47
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 nojaja
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nojaja
|
|
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
CHANGED
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
# browser-git-ops
|
|
2
|
-
|
|
3
|
-
**目的**: ブラウザネイティブ環境(OPFS + Github/Gitlab APIs)で動作する軽量な Git 操作ライブラリを提供します。VirtualFS によるローカル差分生成と、GitHub/GitLab 向けのアダプタを通じたリモート操作を抽象化します。
|
|
4
|
-
|
|
5
|
-
**主な特徴**
|
|
6
|
-
- **仮想ファイルシステム (VirtualFS)**: ローカルワークスペースとベーススナップショットを管理し、変更セット(create/update/delete)を生成します。
|
|
7
|
-
- **Git アダプタ抽象**: `GitAdapter` インターフェースに準拠するアダプタで GitHub/GitLab API を操作できます(サンプル実装あり)。
|
|
8
|
-
- **Idempotent push**: commitKey による冪等処理サポート。
|
|
9
|
-
- **衝突検知とマージ補助**: リモート差分取り込み時にローカルの未コミット変更を検出して conflicts を報告します。
|
|
10
|
-
|
|
11
|
-
**注意(⚠️)**: 実装はユーティリティ/ライブラリ向けで、環境やアクセストークンの管理、エラーハンドリング方針は利用側で制御してください。
|
|
12
|
-
|
|
13
|
-
**プロジェクト構成(抜粋)**
|
|
14
|
-
- **src/virtualfs/virtualfs.ts**: VirtualFS 本体(初期化、read/write、push/pull、差分生成) - [src/virtualfs/virtualfs.ts](src/virtualfs/virtualfs.ts)
|
|
15
|
-
- **src/virtualfs/persistence.ts**: ストレージバックエンドの抽象と Node 用実装 - [src/virtualfs/persistence.ts](src/virtualfs/persistence.ts)
|
|
16
|
-
- **src/git/adapter.ts**: `GitAdapter` インターフェース定義 - [src/git/adapter.ts](src/git/adapter.ts)
|
|
17
|
-
- **src/git/githubAdapter.ts**: GitHub 用アダプタ(blob/tree/commit フロー、再試行ロジック) - [src/git/githubAdapter.ts](src/git/githubAdapter.ts)
|
|
18
|
-
- **test/**: ユニット/E2E テスト群(Jest / Playwright) - [test](test)
|
|
19
|
-
|
|
20
|
-
**技術スタック**
|
|
21
|
-
- TypeScript 5.x
|
|
22
|
-
- Node.js (ESM, `type: "module"`)
|
|
23
|
-
- テスト: Jest(unit) / Playwright(E2E)
|
|
24
|
-
- ビルド: `tsc`
|
|
25
|
-
|
|
26
|
-
--------------------------------------------------
|
|
27
|
-
**クイックスタート(開発用)**
|
|
28
|
-
|
|
29
|
-
1. 依存インストール
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npm ci
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
2. ユニットテスト実行
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm run test
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
3. E2E テスト(Playwright)
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
npm run test:e2e
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
4. ビルド
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
npm run build
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
--------------------------------------------------
|
|
54
|
-
**ライブラリ利用ガイド(Library Usage)**
|
|
55
|
-
|
|
56
|
-
下記はライブラリの代表的な使い方(TypeScript)です。詳しい実装は各ファイルを参照してください。
|
|
57
|
-
|
|
58
|
-
例: `VirtualFS` を初期化してローカル編集を push する
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
import VirtualFS from './src/virtualfs/virtualfs'
|
|
62
|
-
import GitHubAdapter from './src/git/githubAdapter'
|
|
63
|
-
|
|
64
|
-
async function example() {
|
|
65
|
-
const vfs = new VirtualFS({ storageDir: '.apigit' })
|
|
66
|
-
await vfs.init()
|
|
67
|
-
|
|
68
|
-
// ワークスペース編集
|
|
69
|
-
await vfs.writeWorkspace('foo.txt', 'hello')
|
|
70
|
-
|
|
71
|
-
// 変更セット取得
|
|
72
|
-
const changes = await vfs.getChangeSet()
|
|
73
|
-
|
|
74
|
-
// GitHub アダプタを使って push
|
|
75
|
-
const gh = new GitHubAdapter({ owner: 'ORG', repo: 'REPO', token: process.env.GH_TOKEN })
|
|
76
|
-
const res = await vfs.push({ parentSha: vfs.getIndex().head, message: 'update', changes }, gh as any)
|
|
77
|
-
console.log('commitSha', res.commitSha)
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
API の概略(主要メソッド)
|
|
82
|
-
- `new VirtualFS(options?)` - オプション: `{ storageDir?: string, backend?: StorageBackend }`
|
|
83
|
-
- `init()` - バックエンド初期化と index 読み込み
|
|
84
|
-
- `writeWorkspace(filepath, content)` - ワークスペースにファイルを書き込む
|
|
85
|
-
- `deleteWorkspace(filepath)` - ワークスペース上のファイルを削除(トゥームストーン管理)
|
|
86
|
-
- `renameWorkspace(from, to)` - rename(内部では delete + create)
|
|
87
|
-
- `readWorkspace(filepath)` - ワークスペース/ベースから内容を読み出す
|
|
88
|
-
- `applyBaseSnapshot(snapshot, headSha)` - リモートスナップショットを適用
|
|
89
|
-
- `getIndex()` - 現在の index を返す
|
|
90
|
-
- `listPaths()` - 登録パス一覧
|
|
91
|
-
- `getChangeSet()` - create/update/delete の配列を生成
|
|
92
|
-
- `pull(remoteHead, baseSnapshot)` - リモート差分取り込み(conflicts を返す)
|
|
93
|
-
- `push(input, adapter?)` - 変更をコミットし(adapter があれば)リモートへ反映
|
|
94
|
-
|
|
95
|
-
GitAdapter インターフェース(`src/git/adapter.ts`)
|
|
96
|
-
- `createBlobs(changes, concurrency?)` -> Promise<Record<string,string>>
|
|
97
|
-
- `createTree(changes, baseTreeSha?)` -> Promise<string>
|
|
98
|
-
- `createCommit(message, parentSha, treeSha)` -> Promise<string>
|
|
99
|
-
- `updateRef(ref, commitSha, force?)` -> Promise<void>
|
|
100
|
-
|
|
101
|
-
実装済みアダプタの注意点:
|
|
102
|
-
- `GitHubAdapter` は `blob/tree/commit` フローを実装し、HTTP 再試行ロジックを内蔵しています(5xx, 429 のリトライ等)。実装は [src/git/githubAdapter.ts](src/git/githubAdapter.ts) を参照してください。
|
|
103
|
-
- GitLab 用実装はリポジトリ内に存在しますが、環境差異により API の振る舞いが異なるため本番運用前に検証してください。⚠️
|
|
104
|
-
|
|
105
|
-
--------------------------------------------------
|
|
106
|
-
**開発セットアップ**
|
|
107
|
-
- Node: 任意の recent Node.js(ESM サポート済み)
|
|
108
|
-
- 実行手順
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
git clone <repo>
|
|
112
|
-
cd APIGitWorkspace01
|
|
113
|
-
npm ci
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
- コマンド一覧
|
|
117
|
-
- `npm run test` : ユニットテスト(Jest)
|
|
118
|
-
- `npm run test:e2e` : Playwright E2E
|
|
119
|
-
- `npm run lint` : ESLint
|
|
120
|
-
- `npm run build` : TypeScript ビルド
|
|
121
|
-
|
|
122
|
-
テスト関連の注意:
|
|
123
|
-
- Jest は ESM を扱うため `node --experimental-vm-modules` を使用するスクリプトが package.json に設定されています。
|
|
124
|
-
|
|
125
|
-
--------------------------------------------------
|
|
126
|
-
**現在のステータス**
|
|
127
|
-
- 実装済み: `VirtualFS` のコア機能(差分生成、push/pull シミュレーション、index 管理)、`GitHubAdapter` の主要な API 呼び出し。
|
|
128
|
-
- テスト: unit テストと一部の E2E テストが含まれています(`test/` 配下)。
|
|
129
|
-
- 未確定/要検証: 外部サービス(GitLab)の細かい API 挙動、production 用のエラー・認可ポリシー。
|
|
130
|
-
|
|
131
|
-
--------------------------------------------------
|
|
132
|
-
**ライセンスとメタデータ**
|
|
133
|
-
- package name: `browser-git-ops`
|
|
134
|
-
- version: `0.0.0`
|
|
135
|
-
- module type: CommonJS (`type: commonjs`)
|
|
136
|
-
- License: MIT License
|
|
137
|
-
|
|
138
|
-
--------------------------------------------------
|
|
139
|
-
追加で欲しいもの
|
|
140
|
-
- サンプルユースケースを示す小さなサンプルリポジトリまたは `examples/` ディレクトリ
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
--------------------------------------------------
|
|
144
|
-
貢献・問い合わせ
|
|
145
|
-
- PR/Issue を歓迎します。まず issue を立て、簡単な実装提案(変更点の概要)を添えてください。
|
|
146
|
-
|
|
1
|
+
# browser-git-ops
|
|
2
|
+
|
|
3
|
+
**目的**: ブラウザネイティブ環境(OPFS + Github/Gitlab APIs)で動作する軽量な Git 操作ライブラリを提供します。VirtualFS によるローカル差分生成と、GitHub/GitLab 向けのアダプタを通じたリモート操作を抽象化します。
|
|
4
|
+
|
|
5
|
+
**主な特徴**
|
|
6
|
+
- **仮想ファイルシステム (VirtualFS)**: ローカルワークスペースとベーススナップショットを管理し、変更セット(create/update/delete)を生成します。
|
|
7
|
+
- **Git アダプタ抽象**: `GitAdapter` インターフェースに準拠するアダプタで GitHub/GitLab API を操作できます(サンプル実装あり)。
|
|
8
|
+
- **Idempotent push**: commitKey による冪等処理サポート。
|
|
9
|
+
- **衝突検知とマージ補助**: リモート差分取り込み時にローカルの未コミット変更を検出して conflicts を報告します。
|
|
10
|
+
|
|
11
|
+
**注意(⚠️)**: 実装はユーティリティ/ライブラリ向けで、環境やアクセストークンの管理、エラーハンドリング方針は利用側で制御してください。
|
|
12
|
+
|
|
13
|
+
**プロジェクト構成(抜粋)**
|
|
14
|
+
- **src/virtualfs/virtualfs.ts**: VirtualFS 本体(初期化、read/write、push/pull、差分生成) - [src/virtualfs/virtualfs.ts](src/virtualfs/virtualfs.ts)
|
|
15
|
+
- **src/virtualfs/persistence.ts**: ストレージバックエンドの抽象と Node 用実装 - [src/virtualfs/persistence.ts](src/virtualfs/persistence.ts)
|
|
16
|
+
- **src/git/adapter.ts**: `GitAdapter` インターフェース定義 - [src/git/adapter.ts](src/git/adapter.ts)
|
|
17
|
+
- **src/git/githubAdapter.ts**: GitHub 用アダプタ(blob/tree/commit フロー、再試行ロジック) - [src/git/githubAdapter.ts](src/git/githubAdapter.ts)
|
|
18
|
+
- **test/**: ユニット/E2E テスト群(Jest / Playwright) - [test](test)
|
|
19
|
+
|
|
20
|
+
**技術スタック**
|
|
21
|
+
- TypeScript 5.x
|
|
22
|
+
- Node.js (ESM, `type: "module"`)
|
|
23
|
+
- テスト: Jest(unit) / Playwright(E2E)
|
|
24
|
+
- ビルド: `tsc`
|
|
25
|
+
|
|
26
|
+
--------------------------------------------------
|
|
27
|
+
**クイックスタート(開発用)**
|
|
28
|
+
|
|
29
|
+
1. 依存インストール
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm ci
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
2. ユニットテスト実行
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm run test
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
3. E2E テスト(Playwright)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm run test:e2e
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
4. ビルド
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm run build
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
--------------------------------------------------
|
|
54
|
+
**ライブラリ利用ガイド(Library Usage)**
|
|
55
|
+
|
|
56
|
+
下記はライブラリの代表的な使い方(TypeScript)です。詳しい実装は各ファイルを参照してください。
|
|
57
|
+
|
|
58
|
+
例: `VirtualFS` を初期化してローカル編集を push する
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import VirtualFS from './src/virtualfs/virtualfs'
|
|
62
|
+
import GitHubAdapter from './src/git/githubAdapter'
|
|
63
|
+
|
|
64
|
+
async function example() {
|
|
65
|
+
const vfs = new VirtualFS({ storageDir: '.apigit' })
|
|
66
|
+
await vfs.init()
|
|
67
|
+
|
|
68
|
+
// ワークスペース編集
|
|
69
|
+
await vfs.writeWorkspace('foo.txt', 'hello')
|
|
70
|
+
|
|
71
|
+
// 変更セット取得
|
|
72
|
+
const changes = await vfs.getChangeSet()
|
|
73
|
+
|
|
74
|
+
// GitHub アダプタを使って push
|
|
75
|
+
const gh = new GitHubAdapter({ owner: 'ORG', repo: 'REPO', token: process.env.GH_TOKEN })
|
|
76
|
+
const res = await vfs.push({ parentSha: vfs.getIndex().head, message: 'update', changes }, gh as any)
|
|
77
|
+
console.log('commitSha', res.commitSha)
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
API の概略(主要メソッド)
|
|
82
|
+
- `new VirtualFS(options?)` - オプション: `{ storageDir?: string, backend?: StorageBackend }`
|
|
83
|
+
- `init()` - バックエンド初期化と index 読み込み
|
|
84
|
+
- `writeWorkspace(filepath, content)` - ワークスペースにファイルを書き込む
|
|
85
|
+
- `deleteWorkspace(filepath)` - ワークスペース上のファイルを削除(トゥームストーン管理)
|
|
86
|
+
- `renameWorkspace(from, to)` - rename(内部では delete + create)
|
|
87
|
+
- `readWorkspace(filepath)` - ワークスペース/ベースから内容を読み出す
|
|
88
|
+
- `applyBaseSnapshot(snapshot, headSha)` - リモートスナップショットを適用
|
|
89
|
+
- `getIndex()` - 現在の index を返す
|
|
90
|
+
- `listPaths()` - 登録パス一覧
|
|
91
|
+
- `getChangeSet()` - create/update/delete の配列を生成
|
|
92
|
+
- `pull(remoteHead, baseSnapshot)` - リモート差分取り込み(conflicts を返す)
|
|
93
|
+
- `push(input, adapter?)` - 変更をコミットし(adapter があれば)リモートへ反映
|
|
94
|
+
|
|
95
|
+
GitAdapter インターフェース(`src/git/adapter.ts`)
|
|
96
|
+
- `createBlobs(changes, concurrency?)` -> Promise<Record<string,string>>
|
|
97
|
+
- `createTree(changes, baseTreeSha?)` -> Promise<string>
|
|
98
|
+
- `createCommit(message, parentSha, treeSha)` -> Promise<string>
|
|
99
|
+
- `updateRef(ref, commitSha, force?)` -> Promise<void>
|
|
100
|
+
|
|
101
|
+
実装済みアダプタの注意点:
|
|
102
|
+
- `GitHubAdapter` は `blob/tree/commit` フローを実装し、HTTP 再試行ロジックを内蔵しています(5xx, 429 のリトライ等)。実装は [src/git/githubAdapter.ts](src/git/githubAdapter.ts) を参照してください。
|
|
103
|
+
- GitLab 用実装はリポジトリ内に存在しますが、環境差異により API の振る舞いが異なるため本番運用前に検証してください。⚠️
|
|
104
|
+
|
|
105
|
+
--------------------------------------------------
|
|
106
|
+
**開発セットアップ**
|
|
107
|
+
- Node: 任意の recent Node.js(ESM サポート済み)
|
|
108
|
+
- 実行手順
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
git clone <repo>
|
|
112
|
+
cd APIGitWorkspace01
|
|
113
|
+
npm ci
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
- コマンド一覧
|
|
117
|
+
- `npm run test` : ユニットテスト(Jest)
|
|
118
|
+
- `npm run test:e2e` : Playwright E2E
|
|
119
|
+
- `npm run lint` : ESLint
|
|
120
|
+
- `npm run build` : TypeScript ビルド
|
|
121
|
+
|
|
122
|
+
テスト関連の注意:
|
|
123
|
+
- Jest は ESM を扱うため `node --experimental-vm-modules` を使用するスクリプトが package.json に設定されています。
|
|
124
|
+
|
|
125
|
+
--------------------------------------------------
|
|
126
|
+
**現在のステータス**
|
|
127
|
+
- 実装済み: `VirtualFS` のコア機能(差分生成、push/pull シミュレーション、index 管理)、`GitHubAdapter` の主要な API 呼び出し。
|
|
128
|
+
- テスト: unit テストと一部の E2E テストが含まれています(`test/` 配下)。
|
|
129
|
+
- 未確定/要検証: 外部サービス(GitLab)の細かい API 挙動、production 用のエラー・認可ポリシー。
|
|
130
|
+
|
|
131
|
+
--------------------------------------------------
|
|
132
|
+
**ライセンスとメタデータ**
|
|
133
|
+
- package name: `browser-git-ops`
|
|
134
|
+
- version: `0.0.0`
|
|
135
|
+
- module type: CommonJS (`type: commonjs`)
|
|
136
|
+
- License: MIT License
|
|
137
|
+
|
|
138
|
+
--------------------------------------------------
|
|
139
|
+
追加で欲しいもの
|
|
140
|
+
- サンプルユースケースを示す小さなサンプルリポジトリまたは `examples/` ディレクトリ
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
--------------------------------------------------
|
|
144
|
+
貢献・問い合わせ
|
|
145
|
+
- PR/Issue を歓迎します。まず issue を立て、簡単な実装提案(変更点の概要)を添えてください。
|
|
146
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"githubAdapter.d.ts","sourceRoot":"","sources":["../../src/git/githubAdapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"githubAdapter.d.ts","sourceRoot":"","sources":["../../src/git/githubAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAGtC,KAAK,SAAS,GAAG;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAE5C;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAU/C;;;;;;;GAOG;AAEH,iBAAe,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,SAAI,EAAE,SAAS,SAAM,qBAcjG;AAED,iBAAS,cAAc,CAAC,MAAM,EAAE,MAAM,WAErC;AAED,iBAAS,mBAAmB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAI9E;AAED,iBAAe,wBAAwB,CAAC,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,qBAQlF;AAED;;;;;GAKG;AAEH,iBAAS,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,WAAW,SAAI,gBAc3F;AAED,qBAAa,aAAc,YAAW,UAAU;IAMlC,OAAO,CAAC,IAAI;IALxB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,eAAe,CAAqF;IAE5G,OAAO,CAAC,SAAS,CAAiC;gBAC9B,IAAI,EAAE,SAAS;IAU7B,WAAW,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,WAAW,SAAI;IAqB3C,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM;IAkB/C,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAQhE,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,UAAQ;CAQ9D;AAED,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,CAAA;AAC5G,eAAe,aAAa,CAAA"}
|
|
@@ -50,67 +50,67 @@ async function installMockApi(page, initialFiles = {}) {
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
// Simple in-page VirtualFS implementation used by tests
|
|
53
|
-
const vfsScript = `(() => {
|
|
54
|
-
const base = {}; // files that reflect remote base
|
|
55
|
-
const workspace = {}; // pending edits
|
|
56
|
-
const tombstone = new Set();
|
|
57
|
-
let head = 'initial';
|
|
58
|
-
|
|
59
|
-
async function pull() {
|
|
60
|
-
const res = await fetch('http://example.com/api/pull');
|
|
61
|
-
if (!res.ok) throw new Error('pull failed');
|
|
62
|
-
const body = await res.json();
|
|
63
|
-
for (const k of Object.keys(base)) delete base[k];
|
|
64
|
-
for (const [k,v] of Object.entries(body.files)) base[k]=v;
|
|
65
|
-
head = body.head;
|
|
66
|
-
// clear workspace/tombstone on successful pull
|
|
67
|
-
for (const k of Object.keys(workspace)) delete workspace[k];
|
|
68
|
-
tombstone.clear();
|
|
69
|
-
return { head };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function push() {
|
|
73
|
-
// compute actions from workspace/tombstone
|
|
74
|
-
const actions = [];
|
|
75
|
-
for (const k of Object.keys(workspace)) {
|
|
76
|
-
if (!(k in base)) actions.push({ action: 'create', path: k, content: workspace[k] });
|
|
77
|
-
else if (base[k] !== workspace[k]) actions.push({ action: 'update', path: k, content: workspace[k] });
|
|
78
|
-
}
|
|
79
|
-
for (const p of tombstone) actions.push({ action: 'delete', path: p });
|
|
80
|
-
if (actions.length === 0) return { noop: true };
|
|
81
|
-
const res = await fetch('http://example.com/api/commit', { method: 'POST', headers: {'content-type':'application/json'}, body: JSON.stringify({ actions, message: 'test commit' }) });
|
|
82
|
-
if (!res.ok) throw new Error('push failed');
|
|
83
|
-
const body = await res.json();
|
|
84
|
-
// apply commit to base
|
|
85
|
-
for (const a of actions) {
|
|
86
|
-
if (a.action === 'create' || a.action === 'update') base[a.path] = a.content ?? '';
|
|
87
|
-
else if (a.action === 'delete') delete base[a.path];
|
|
88
|
-
}
|
|
89
|
-
// clear workspace/tombstone
|
|
90
|
-
for (const k of Object.keys(workspace)) delete workspace[k];
|
|
91
|
-
tombstone.clear();
|
|
92
|
-
head = body.commit.id;
|
|
93
|
-
return { commit: body.commit };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
readFile: (p) => {
|
|
98
|
-
if (p in workspace) return workspace[p];
|
|
99
|
-
if (p in base) return base[p];
|
|
100
|
-
throw new Error('not found');
|
|
101
|
-
},
|
|
102
|
-
writeFile: (p, content) => { workspace[p] = content; tombstone.delete(p); },
|
|
103
|
-
delete: (p) => { delete workspace[p]; if (p in base) tombstone.add(p); },
|
|
104
|
-
rename: (from, to) => {
|
|
105
|
-
if (from in workspace) { workspace[to] = workspace[from]; delete workspace[from]; }
|
|
106
|
-
else if (from in base) { tombstone.add(from); workspace[to] = base[from]; }
|
|
107
|
-
},
|
|
108
|
-
status: () => ({ changed: Object.keys(workspace), deleted: Array.from(tombstone), conflicted: [] }),
|
|
109
|
-
pull, push,
|
|
110
|
-
_debug_getBase: () => ({ ...base }),
|
|
111
|
-
_debug_getWorkspace: () => ({ ...workspace }),
|
|
112
|
-
_debug_getTombstone: () => Array.from(tombstone),
|
|
113
|
-
};
|
|
53
|
+
const vfsScript = `(() => {
|
|
54
|
+
const base = {}; // files that reflect remote base
|
|
55
|
+
const workspace = {}; // pending edits
|
|
56
|
+
const tombstone = new Set();
|
|
57
|
+
let head = 'initial';
|
|
58
|
+
|
|
59
|
+
async function pull() {
|
|
60
|
+
const res = await fetch('http://example.com/api/pull');
|
|
61
|
+
if (!res.ok) throw new Error('pull failed');
|
|
62
|
+
const body = await res.json();
|
|
63
|
+
for (const k of Object.keys(base)) delete base[k];
|
|
64
|
+
for (const [k,v] of Object.entries(body.files)) base[k]=v;
|
|
65
|
+
head = body.head;
|
|
66
|
+
// clear workspace/tombstone on successful pull
|
|
67
|
+
for (const k of Object.keys(workspace)) delete workspace[k];
|
|
68
|
+
tombstone.clear();
|
|
69
|
+
return { head };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function push() {
|
|
73
|
+
// compute actions from workspace/tombstone
|
|
74
|
+
const actions = [];
|
|
75
|
+
for (const k of Object.keys(workspace)) {
|
|
76
|
+
if (!(k in base)) actions.push({ action: 'create', path: k, content: workspace[k] });
|
|
77
|
+
else if (base[k] !== workspace[k]) actions.push({ action: 'update', path: k, content: workspace[k] });
|
|
78
|
+
}
|
|
79
|
+
for (const p of tombstone) actions.push({ action: 'delete', path: p });
|
|
80
|
+
if (actions.length === 0) return { noop: true };
|
|
81
|
+
const res = await fetch('http://example.com/api/commit', { method: 'POST', headers: {'content-type':'application/json'}, body: JSON.stringify({ actions, message: 'test commit' }) });
|
|
82
|
+
if (!res.ok) throw new Error('push failed');
|
|
83
|
+
const body = await res.json();
|
|
84
|
+
// apply commit to base
|
|
85
|
+
for (const a of actions) {
|
|
86
|
+
if (a.action === 'create' || a.action === 'update') base[a.path] = a.content ?? '';
|
|
87
|
+
else if (a.action === 'delete') delete base[a.path];
|
|
88
|
+
}
|
|
89
|
+
// clear workspace/tombstone
|
|
90
|
+
for (const k of Object.keys(workspace)) delete workspace[k];
|
|
91
|
+
tombstone.clear();
|
|
92
|
+
head = body.commit.id;
|
|
93
|
+
return { commit: body.commit };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
readFile: (p) => {
|
|
98
|
+
if (p in workspace) return workspace[p];
|
|
99
|
+
if (p in base) return base[p];
|
|
100
|
+
throw new Error('not found');
|
|
101
|
+
},
|
|
102
|
+
writeFile: (p, content) => { workspace[p] = content; tombstone.delete(p); },
|
|
103
|
+
delete: (p) => { delete workspace[p]; if (p in base) tombstone.add(p); },
|
|
104
|
+
rename: (from, to) => {
|
|
105
|
+
if (from in workspace) { workspace[to] = workspace[from]; delete workspace[from]; }
|
|
106
|
+
else if (from in base) { tombstone.add(from); workspace[to] = base[from]; }
|
|
107
|
+
},
|
|
108
|
+
status: () => ({ changed: Object.keys(workspace), deleted: Array.from(tombstone), conflicted: [] }),
|
|
109
|
+
pull, push,
|
|
110
|
+
_debug_getBase: () => ({ ...base }),
|
|
111
|
+
_debug_getWorkspace: () => ({ ...workspace }),
|
|
112
|
+
_debug_getTombstone: () => Array.from(tombstone),
|
|
113
|
+
};
|
|
114
114
|
})();`;
|
|
115
115
|
test_1.test.describe('VirtualFS E2E (mocked API)', () => {
|
|
116
116
|
test_1.test.beforeEach(async ({ page }) => {
|
|
@@ -93,8 +93,9 @@ export declare class VirtualFS {
|
|
|
93
93
|
* @returns {TombstoneEntry[]}
|
|
94
94
|
*/
|
|
95
95
|
/**
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
* ワークスペースとインデックスから変更セットを生成します。
|
|
97
|
+
* @returns {Promise<Array<{type:string,path:string,content?:string,baseSha?:string}>>} 変更リスト
|
|
98
|
+
*/
|
|
98
99
|
getChangeSet(): Promise<({
|
|
99
100
|
type: 'create';
|
|
100
101
|
path: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtualfs.d.ts","sourceRoot":"","sources":["../../src/virtualfs/virtualfs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACnD,OAAO,EAAE,cAAc,EAAiB,MAAM,eAAe,CAAA;AAE7D;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,IAAI,CAAsD;IAClE,OAAO,CAAC,SAAS,CAAsD;IACvE,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,OAAO,CAAgB;IAE/B;;OAEG;gBACS,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,cAAc,CAAA;KAAE;IAOvE;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAIb;;;OAGG;IACG,IAAI;IAKV;;;OAGG;YACW,SAAS;IAmBvB;;;OAGG;YACW,SAAS;IAIvB;;OAEG;IACH;;;;;OAKG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAkBtD;;;;OAIG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM;IAqBtC;;;;OAIG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAa9C;;;;OAIG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM;IAWpC;;;;;OAKG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM;IA2BzE;;;OAGG;IACH,QAAQ,IAAI,SAAS;IAIrB;;;OAGG;IACH,SAAS,IAAI,MAAM,EAAE;IAIrB;;;OAGG;IACH,aAAa,IAAI,cAAc,EAAE;IAIjC;;;OAGG;IAEH
|
|
1
|
+
{"version":3,"file":"virtualfs.d.ts","sourceRoot":"","sources":["../../src/virtualfs/virtualfs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACnD,OAAO,EAAE,cAAc,EAAiB,MAAM,eAAe,CAAA;AAE7D;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,IAAI,CAAsD;IAClE,OAAO,CAAC,SAAS,CAAsD;IACvE,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,KAAK,CAAuC;IACpD,OAAO,CAAC,OAAO,CAAgB;IAE/B;;OAEG;gBACS,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,cAAc,CAAA;KAAE;IAOvE;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAIb;;;OAGG;IACG,IAAI;IAKV;;;OAGG;YACW,SAAS;IAmBvB;;;OAGG;YACW,SAAS;IAIvB;;OAEG;IACH;;;;;OAKG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAkBtD;;;;OAIG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM;IAqBtC;;;;OAIG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAa9C;;;;OAIG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM;IAWpC;;;;;OAKG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM;IA2BzE;;;OAGG;IACH,QAAQ,IAAI,SAAS;IAIrB;;;OAGG;IACH,SAAS,IAAI,MAAM,EAAE;IAIrB;;;OAGG;IACH,aAAa,IAAI,cAAc,EAAE;IAIjC;;;OAGG;IAEH;;;QAGI;IACI,YAAY;cAGN,QAAQ;cAAQ,MAAM;iBAAW,MAAM;;cACvC,QAAQ;cAAQ,MAAM;iBAAW,MAAM;;;cACvC,QAAQ;cAAQ,MAAM;iBAAW,MAAM;;IAQrD;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAM9B;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAOhC;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAWhC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAWnC;;;;OAIG;YACW,iBAAiB;IAS/B;;;OAGG;YACW,gBAAgB;IAa9B;;;OAGG;YACW,qBAAqB;IAkBnC;;;;OAIG;YACW,mBAAmB;IAqBjC;;;OAGG;YACW,qBAAqB;IAYnC;;;OAGG;YACW,gBAAgB;IAe9B;;;OAGG;YACW,mBAAmB;IAkBjC;;;;;OAKG;IACG,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;;IA6BnE;;;;;OAKG;IACG,IAAI,CAAC,KAAK,EAAE,OAAO,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,OAAO,gBAAgB,EAAE,UAAU;;;CAkD/F;AAED,eAAe,SAAS,CAAA"}
|
|
@@ -218,8 +218,9 @@ class VirtualFS {
|
|
|
218
218
|
* @returns {TombstoneEntry[]}
|
|
219
219
|
*/
|
|
220
220
|
/**
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
* ワークスペースとインデックスから変更セットを生成します。
|
|
222
|
+
* @returns {Promise<Array<{type:string,path:string,content?:string,baseSha?:string}>>} 変更リスト
|
|
223
|
+
*/
|
|
223
224
|
async getChangeSet() {
|
|
224
225
|
const changes = [];
|
|
225
226
|
changes.push(...this._changesFromTombstones());
|
|
@@ -467,7 +468,6 @@ class VirtualFS {
|
|
|
467
468
|
// If adapter supports createCommitWithActions (GitLab style), use it directly
|
|
468
469
|
if (adapter.createCommitWithActions) {
|
|
469
470
|
// ensure message contains commitKey
|
|
470
|
-
;
|
|
471
471
|
input.message = messageWithKey;
|
|
472
472
|
const res = await this._pushWithActions(adapter, input, branch);
|
|
473
473
|
// record commitKey in index metadata
|
|
@@ -475,7 +475,6 @@ class VirtualFS {
|
|
|
475
475
|
return res;
|
|
476
476
|
}
|
|
477
477
|
// Fallback to GitHub-style flow: delegate to helper
|
|
478
|
-
;
|
|
479
478
|
input.message = messageWithKey;
|
|
480
479
|
const res = await this._pushWithGitHubFlow(adapter, input, branch);
|
|
481
480
|
this.index.lastCommitKey = input.commitKey;
|
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "browser-git-ops",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"type": "commonjs",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"description": "A browser-native Git operations library built with OPFS and Web APIs.",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/nojaja/
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/nojaja/
|
|
14
|
-
},
|
|
15
|
-
"homepage": "https://github.com/nojaja/
|
|
16
|
-
"keywords": ["virtualfs", "git", "github", "vfs", "apigit"],
|
|
17
|
-
"author": "nojaja <free.riccia@gmail.com> (https://github.com/nojaja)",
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"files": [
|
|
20
|
-
"dist",
|
|
21
|
-
"README.md",
|
|
22
|
-
"LICENSE"
|
|
23
|
-
],
|
|
24
|
-
"scripts": {
|
|
25
|
-
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --runInBand",
|
|
26
|
-
"pretest:e2e": "npm run build",
|
|
27
|
-
"test:e2e": "playwright test --config=playwright.config.cjs",
|
|
28
|
-
"test:ci": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --coverage --runInBand",
|
|
29
|
-
"lint": "eslint \"src/**/*.{ts,js}\" --config .eslintrc.cjs",
|
|
30
|
-
"depcruise": "depcruise --config .dependency-cruiser.
|
|
31
|
-
"build": "tsc -p tsconfig.json && tsc -p tsconfig.e2e.json"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@playwright/test": "^1.40.0",
|
|
35
|
-
"@types/jest": "^29.5.2",
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
|
37
|
-
"@typescript-eslint/parser": "^6.10.0",
|
|
38
|
-
"dependency-cruiser": "^17.3.6",
|
|
39
|
-
"eslint": "^8.45.0",
|
|
40
|
-
"eslint-plugin-jsdoc": "^62.1.0",
|
|
41
|
-
"eslint-plugin-sonarjs": "^0.16.0",
|
|
42
|
-
"jest": "^29.6.1",
|
|
43
|
-
"ts-jest": "^29.1.0",
|
|
44
|
-
"typedoc": "^0.25.0",
|
|
45
|
-
"typescript": "5.3.3"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "browser-git-ops",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"description": "A browser-native Git operations library built with OPFS and Web APIs.",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/nojaja/browser-git-ops.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/nojaja/browser-git-ops/issues"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/nojaja/browser-git-ops#readme",
|
|
16
|
+
"keywords": ["virtualfs", "git", "github", "vfs", "apigit"],
|
|
17
|
+
"author": "nojaja <free.riccia@gmail.com> (https://github.com/nojaja)",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --runInBand",
|
|
26
|
+
"pretest:e2e": "npm run build",
|
|
27
|
+
"test:e2e": "playwright test --config=playwright.config.cjs",
|
|
28
|
+
"test:ci": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --coverage --runInBand",
|
|
29
|
+
"lint": "eslint \"src/**/*.{ts,js}\" --config .eslintrc.cjs",
|
|
30
|
+
"depcruise": "depcruise --config .dependency-cruiser.cjs src || exit 0",
|
|
31
|
+
"build": "tsc -p tsconfig.json && tsc -p tsconfig.e2e.json"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@playwright/test": "^1.40.0",
|
|
35
|
+
"@types/jest": "^29.5.2",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
|
37
|
+
"@typescript-eslint/parser": "^6.10.0",
|
|
38
|
+
"dependency-cruiser": "^17.3.6",
|
|
39
|
+
"eslint": "^8.45.0",
|
|
40
|
+
"eslint-plugin-jsdoc": "^62.1.0",
|
|
41
|
+
"eslint-plugin-sonarjs": "^0.16.0",
|
|
42
|
+
"jest": "^29.6.1",
|
|
43
|
+
"ts-jest": "^29.1.0",
|
|
44
|
+
"typedoc": "^0.25.0",
|
|
45
|
+
"typescript": "5.3.3"
|
|
46
|
+
}
|
|
47
|
+
}
|