@kubohiroya/turbowarp-plus-editor-git 0.11.0 → 0.12.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/README.ja.md +2 -0
- package/README.md +2 -0
- package/dist/index.js +37 -11
- package/dist/project-source-diff.d.ts +2 -0
- package/dist/project-source-diff.js +2 -2
- package/dist/project-source-review-model.d.ts +35 -0
- package/dist/review-words.d.ts +6 -0
- package/dist/{scratch-block-diff-renderer-CgAGfmAc.js → scratch-block-diff-renderer-e_drVlHE.js} +533 -254
- package/dist/style.css +14 -0
- package/package.json +2 -1
- package/src/index.tsx +40 -5
- package/src/project-source-diff.css +14 -0
- package/src/project-source-diff.tsx +2 -0
- package/src/project-source-review-model.ts +154 -8
- package/src/project-source-review.tsx +79 -13
- package/src/review-words.ts +66 -0
- package/test/smart-http-fixture.js +178 -0
package/README.ja.md
CHANGED
|
@@ -16,6 +16,8 @@ Node.js 26 で `npm ci` と `npm test` を実行します。Vite でライブラ
|
|
|
16
16
|
|
|
17
17
|
## Smart HTTP アダプター
|
|
18
18
|
|
|
19
|
+
`test/smart-http-fixture.js` は、`git-http-backend` を IPv4 のループバックで動かす検証用のフィクスチャです。Node.js の標準モジュールだけを使い、利用側のブラウザーテストが同じ版を使えるよう配布物に含めます。
|
|
20
|
+
|
|
19
21
|
`@kubohiroya/turbowarp-plus-editor-git/smart-http` の `createGitSmartHttp` に、Git 設定から選んだ GitHub の HTTPS リモート、信頼済みの接続先(`mode` と `proxyOrigin`)、現在のプロキシセッションか `null` を返す関数を渡します。auth パッケージの `GitAuthProvider` を使えます。Git パッケージは必要なセッションの型だけを構造的に参照するため、読み取り専用パネルとアダプターは auth パッケージと独立してインストールできます。
|
|
20
22
|
|
|
21
23
|
```ts
|
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ The panel structure and local Git approach were informed by [duff](https://githu
|
|
|
16
16
|
|
|
17
17
|
## Smart HTTP adapter
|
|
18
18
|
|
|
19
|
+
`test/smart-http-fixture.js` runs `git-http-backend` on the IPv4 loopback for tests. It uses only Node.js built-in modules and ships in the package so browser tests of a host use the fixture of the same version.
|
|
20
|
+
|
|
19
21
|
Import `createGitSmartHttp` from `@kubohiroya/turbowarp-plus-editor-git/smart-http`. Pass the selected GitHub HTTPS remote from Git config, a trusted connection (`mode` and `proxyOrigin`), and a function that returns the current proxy session or `null`. A `GitAuthProvider` from the auth package satisfies this contract. The Git package uses the session fields structurally, so the read-only panel and the adapter can be installed independently of the auth package.
|
|
20
22
|
|
|
21
23
|
```ts
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as useCostumeImage, a as gitHubRepositoryFromOrigin, b as parseProjectSource, g as useAssetImage, i as createGitHubPullRequests, l as organizeProjectChanges, n as createScratchBlocksDiffLocator, o as ProjectSourceComparison, r as PullRequestError, s as ProjectSourceReview, t as createScratchBlocksDiffRenderer, u as projectPropertyLabel } from "./scratch-block-diff-renderer-e_drVlHE.js";
|
|
2
2
|
import { n as init_objectSpread2, r as __commonJSMin, t as _objectSpread2$1 } from "./objectSpread2-Dkd68nJH.js";
|
|
3
3
|
import { i as createReadOnlyFs, r as GitPanelError, t as openRepository } from "./repository-CtvWYPQ8.js";
|
|
4
4
|
import * as m from "react";
|
|
@@ -3557,6 +3557,8 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3557
3557
|
const alive = useRef(true);
|
|
3558
3558
|
const opening = useRef(false);
|
|
3559
3559
|
const dialog = useRef(null);
|
|
3560
|
+
const shownRef = useRef(false);
|
|
3561
|
+
const deferred = useRef(false);
|
|
3560
3562
|
const reviewing = useRef(review);
|
|
3561
3563
|
reviewing.current = review;
|
|
3562
3564
|
const handled = useRef(null);
|
|
@@ -3582,6 +3584,11 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3582
3584
|
} catch (error) {
|
|
3583
3585
|
if (epoch.current !== ticket) return;
|
|
3584
3586
|
const code = error instanceof GitPanelError ? error.code : "failed";
|
|
3587
|
+
if (automatic && code === "changed") {
|
|
3588
|
+
handled.current = null;
|
|
3589
|
+
setState((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, { busy: false }));
|
|
3590
|
+
return;
|
|
3591
|
+
}
|
|
3585
3592
|
const message = labels[code] || labels.failed;
|
|
3586
3593
|
setState((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, {
|
|
3587
3594
|
error: automatic && previous.error ? previous.error : message,
|
|
@@ -3590,6 +3597,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3590
3597
|
}));
|
|
3591
3598
|
} finally {
|
|
3592
3599
|
running.current = false;
|
|
3600
|
+
if (epoch.current !== ticket && !refreshPending.current && alive.current) setState((previous) => _objectSpread2$1(_objectSpread2$1({}, previous), {}, { busy: false }));
|
|
3593
3601
|
if (automatic) {
|
|
3594
3602
|
background.current = null;
|
|
3595
3603
|
settle();
|
|
@@ -3632,20 +3640,29 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3632
3640
|
};
|
|
3633
3641
|
controller.refresh = async (automatic = false) => {
|
|
3634
3642
|
if (!alive.current || !current.current.repository) return;
|
|
3643
|
+
if (!shownRef.current) {
|
|
3644
|
+
deferred.current = true;
|
|
3645
|
+
return;
|
|
3646
|
+
}
|
|
3635
3647
|
if (running.current) {
|
|
3636
3648
|
if (!automatic) refreshPending.current = true;
|
|
3637
3649
|
return;
|
|
3638
3650
|
}
|
|
3639
3651
|
await run(async () => {
|
|
3640
3652
|
const { repository, project } = current.current;
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3653
|
+
for (let attempt = 1;; attempt++) try {
|
|
3654
|
+
const snapshot = await repository.read(project !== null && project !== void 0 ? project : "");
|
|
3655
|
+
return {
|
|
3656
|
+
snapshot,
|
|
3657
|
+
changes: snapshot.changes,
|
|
3658
|
+
selected: null,
|
|
3659
|
+
diff: null,
|
|
3660
|
+
commit: null
|
|
3661
|
+
};
|
|
3662
|
+
} catch (error) {
|
|
3663
|
+
if (!(error instanceof GitPanelError && error.code === "changed") || attempt >= 5) throw error;
|
|
3664
|
+
await new Promise((resolve) => setTimeout(resolve, 200 * attempt));
|
|
3665
|
+
}
|
|
3649
3666
|
}, automatic);
|
|
3650
3667
|
};
|
|
3651
3668
|
useEffect(() => {
|
|
@@ -3662,7 +3679,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3662
3679
|
selected: null,
|
|
3663
3680
|
diff: null,
|
|
3664
3681
|
commit: null,
|
|
3665
|
-
busy:
|
|
3682
|
+
busy: running.current
|
|
3666
3683
|
}));
|
|
3667
3684
|
queueMicrotask(() => void controller.refresh());
|
|
3668
3685
|
}
|
|
@@ -3675,6 +3692,13 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3675
3692
|
unsubscribe === null || unsubscribe === void 0 || unsubscribe();
|
|
3676
3693
|
};
|
|
3677
3694
|
}, [host]);
|
|
3695
|
+
useEffect(() => {
|
|
3696
|
+
shownRef.current = shown;
|
|
3697
|
+
if (shown && deferred.current) {
|
|
3698
|
+
deferred.current = false;
|
|
3699
|
+
controller.refresh();
|
|
3700
|
+
}
|
|
3701
|
+
}, [shown]);
|
|
3678
3702
|
useEffect(() => {
|
|
3679
3703
|
const repository = state.repository;
|
|
3680
3704
|
if (!shown || !repository) return;
|
|
@@ -3683,7 +3707,8 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3683
3707
|
let checking = false;
|
|
3684
3708
|
const check = async () => {
|
|
3685
3709
|
const { snapshot } = current.current;
|
|
3686
|
-
|
|
3710
|
+
const hidden = !dialog.current || !dialog.current.getClientRects().length;
|
|
3711
|
+
if (stopped || checking || running.current || document.visibilityState === "hidden" || hidden || !snapshot || current.current.repository !== repository) return;
|
|
3687
3712
|
checking = true;
|
|
3688
3713
|
try {
|
|
3689
3714
|
const probe = await repository.probe(snapshot.scope);
|
|
@@ -3978,6 +4003,7 @@ function GitPanel({ vm, document, host, controller }) {
|
|
|
3978
4003
|
}) : /* @__PURE__ */ React.createElement("p", null, labels.select))));
|
|
3979
4004
|
if (slot) return createPortal(/* @__PURE__ */ React.createElement("div", {
|
|
3980
4005
|
className: "twgit-panel twgit-panel-tab",
|
|
4006
|
+
ref: dialog,
|
|
3981
4007
|
role: "region",
|
|
3982
4008
|
"aria-label": labels.title
|
|
3983
4009
|
}, content), slot.element);
|
|
@@ -9,6 +9,8 @@ export { createScratchBlocksDiffLocator } from './block-diff-location.js';
|
|
|
9
9
|
export type { ProjectBlockLocation, ProjectBlockLocator, ScratchBlockLocationWorkspace } from './block-diff-location.js';
|
|
10
10
|
export type { BlockPart } from './project-source-patch.js';
|
|
11
11
|
export { createProjectSourceDiff } from './project-source-patch.js';
|
|
12
|
+
export { compareProjectForReview } from './project-source-review-model.js';
|
|
13
|
+
export type { ScriptChangeKind, ScriptReview, ScriptReviewSide, ScriptSummaryItem, TargetReview } from './project-source-review-model.js';
|
|
12
14
|
export { currentCostume } from './project-assets.js';
|
|
13
15
|
export { assetFileName, organizeProjectChanges, projectPropertyLabel } from './project-change-model.js';
|
|
14
16
|
export type { ChangedFile, OrganizeProjectChangesInput, ProjectChangeList, ProjectChangeStatus, ProjectElementChange, ProjectElementKind, ProjectTargetChanges } from './project-change-model.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as gitHubRepositoryFromOrigin, c as assetFileName, d as compareProjectForReview, f as BlockPreview, h as currentCostume, i as createGitHubPullRequests, l as organizeProjectChanges, m as usePreviewSync, n as createScratchBlocksDiffLocator, o as ProjectSourceComparison, p as createPreviewSync, s as ProjectSourceReview, t as createScratchBlocksDiffRenderer, u as projectPropertyLabel, v as compareProjectBlocks, x as readProjectSourceDiff, y as createProjectSourceDiff } from "./scratch-block-diff-renderer-e_drVlHE.js";
|
|
2
2
|
import { n as init_objectSpread2, t as _objectSpread2 } from "./objectSpread2-Dkd68nJH.js";
|
|
3
3
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
// src/project-source-diff.tsx
|
|
@@ -169,4 +169,4 @@ function ProjectSourceBlockDiff({ patch, beforeSource, renderBlock, locateBlock,
|
|
|
169
169
|
})
|
|
170
170
|
}, labels.more));
|
|
171
171
|
}
|
|
172
|
-
export { ProjectSourceBlockDiff, ProjectSourceComparison, ProjectSourceReview, assetFileName, createGitHubPullRequests, createPreviewSync, createProjectSourceDiff, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, currentCostume, gitHubRepositoryFromOrigin, organizeProjectChanges, projectPropertyLabel };
|
|
172
|
+
export { ProjectSourceBlockDiff, ProjectSourceComparison, ProjectSourceReview, assetFileName, compareProjectForReview, createGitHubPullRequests, createPreviewSync, createProjectSourceDiff, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, currentCostume, gitHubRepositoryFromOrigin, organizeProjectChanges, projectPropertyLabel };
|
|
@@ -3,14 +3,49 @@ import type { ScriptBlockMark } from './scratch-block-diff-renderer.js';
|
|
|
3
3
|
export interface ScriptReviewSide extends BlockSide {
|
|
4
4
|
marks: ScriptBlockMark[];
|
|
5
5
|
}
|
|
6
|
+
/**
|
|
7
|
+
* What happened to one script. `moved` means only positions changed, `reordered` only how blocks connect;
|
|
8
|
+
* neither changes what the script does.
|
|
9
|
+
*/
|
|
10
|
+
export type ScriptChangeKind = 'added' | 'removed' | 'updated' | 'reorganized' | 'moved' | 'reordered';
|
|
11
|
+
/** One phrase of a script's summary, in the order shown. The view words it in the reader's language. */
|
|
12
|
+
export type ScriptSummaryItem = {
|
|
13
|
+
kind: 'hatReplaced';
|
|
14
|
+
before: string;
|
|
15
|
+
after: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'wrapped';
|
|
18
|
+
opcode: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'branchAdded';
|
|
21
|
+
opcode: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'valueChanged';
|
|
24
|
+
opcode: string;
|
|
25
|
+
name: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'blocksAdded';
|
|
28
|
+
count: number;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'blocksRemoved';
|
|
31
|
+
count: number;
|
|
32
|
+
} | {
|
|
33
|
+
kind: 'reordered';
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'moved';
|
|
36
|
+
};
|
|
6
37
|
export interface ScriptReview {
|
|
7
38
|
id: string;
|
|
8
39
|
before: ScriptReviewSide[];
|
|
9
40
|
after: ScriptReviewSide[];
|
|
41
|
+
kind: ScriptChangeKind;
|
|
42
|
+
summary: ScriptSummaryItem[];
|
|
10
43
|
}
|
|
11
44
|
export interface TargetReview {
|
|
12
45
|
name: string;
|
|
13
46
|
isStage: boolean;
|
|
47
|
+
/** Added or removed as a whole, or changed. Added and removed targets list no properties. */
|
|
48
|
+
status: 'added' | 'removed' | 'updated';
|
|
14
49
|
/** The stage or sprite in each version, absent where it does not exist. */
|
|
15
50
|
before?: ProjectTarget;
|
|
16
51
|
after?: ProjectTarget;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ScriptSummaryItem } from './project-source-review-model.js';
|
|
2
|
+
export declare function hatName(opcode: string, locale: string): string | undefined;
|
|
3
|
+
/** One phrase per summary item, in the reader's language. */
|
|
4
|
+
export declare function summaryPhrase(item: ScriptSummaryItem, locale: string): string;
|
|
5
|
+
/** The colours of the previews, said once at the top of a review. */
|
|
6
|
+
export declare const legend: (locale: string) => readonly [readonly ["added", "緑の縁: 追加したブロック"], readonly ["removed", "赤の縁: 削除したブロック"], readonly ["updated", "紫の縁: 中身を変えたブロック"], readonly ["part", "オレンジの枠: 値を変えた欄"]] | readonly [readonly ["added", "Green outline: added block"], readonly ["removed", "Red outline: removed block"], readonly ["updated", "Purple outline: block with changed contents"], readonly ["part", "Orange frame: changed value"]];
|