@kubohiroya/turbowarp-plus-editor-git 0.0.0-stage → 0.8.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 (63) hide show
  1. package/LICENSE +373 -0
  2. package/README.ja.md +121 -0
  3. package/README.md +43 -2
  4. package/THIRD_PARTY_NOTICES.md +5 -0
  5. package/dist/THIRD_PARTY_NOTICES.md +1186 -0
  6. package/dist/block-diff-location.d.ts +22 -0
  7. package/dist/block-diff-preview.d.ts +33 -0
  8. package/dist/browser.d.ts +4 -0
  9. package/dist/connection-settings.d.ts +35 -0
  10. package/dist/file-diff-view.d.ts +18 -0
  11. package/dist/filesystem.d.ts +89 -0
  12. package/dist/github-pull-requests.d.ts +38 -0
  13. package/dist/index.d.ts +29 -0
  14. package/dist/index.js +3563 -0
  15. package/dist/messages.d.ts +112 -0
  16. package/dist/mutation-fs.d.ts +58 -0
  17. package/dist/objectSpread2-Dkd68nJH.js +101 -0
  18. package/dist/project-asset-paths-KV715791.js +761 -0
  19. package/dist/project-asset-paths.d.ts +12 -0
  20. package/dist/project-assets.d.ts +19 -0
  21. package/dist/project-source-diff.d.ts +26 -0
  22. package/dist/project-source-diff.js +172 -0
  23. package/dist/project-source-patch.d.ts +39 -0
  24. package/dist/project-source-review-model.d.ts +23 -0
  25. package/dist/project-source-review.d.ts +38 -0
  26. package/dist/pull-request-panel.d.ts +8 -0
  27. package/dist/remote-operations.d.ts +5 -0
  28. package/dist/repository-BQkADJmK.js +17280 -0
  29. package/dist/repository.d.ts +71 -0
  30. package/dist/repository.js +1 -0
  31. package/dist/scratch-block-diff-renderer-xS8OYsRl.js +1830 -0
  32. package/dist/scratch-block-diff-renderer.d.ts +128 -0
  33. package/dist/smart-http-BmHEkE7K.js +303 -0
  34. package/dist/smart-http.d.ts +60 -0
  35. package/dist/smart-http.js +1 -0
  36. package/dist/style.css +138 -0
  37. package/package.json +65 -4
  38. package/src/block-diff-location.ts +63 -0
  39. package/src/block-diff-preview.tsx +117 -0
  40. package/src/browser.ts +5 -0
  41. package/src/connection-settings.tsx +103 -0
  42. package/src/file-diff-view.tsx +44 -0
  43. package/src/filesystem.ts +125 -0
  44. package/src/github-pull-requests.ts +229 -0
  45. package/src/index.tsx +352 -0
  46. package/src/messages.ts +64 -0
  47. package/src/mutation-fs.ts +204 -0
  48. package/src/project-asset-paths.ts +33 -0
  49. package/src/project-assets.ts +66 -0
  50. package/src/project-source-diff.css +108 -0
  51. package/src/project-source-diff.tsx +139 -0
  52. package/src/project-source-patch.ts +126 -0
  53. package/src/project-source-review-model.ts +116 -0
  54. package/src/project-source-review.tsx +250 -0
  55. package/src/pull-request-panel.tsx +134 -0
  56. package/src/remote-operations.ts +90 -0
  57. package/src/repository.ts +364 -0
  58. package/src/scratch-block-diff-renderer.ts +331 -0
  59. package/src/smart-http.ts +190 -0
  60. package/src/style.css +29 -0
  61. package/src/styles.d.ts +1 -0
  62. package/tsconfig.json +18 -0
  63. package/vite.config.ts +26 -0
@@ -0,0 +1,12 @@
1
+ /** The largest asset a thumbnail reads. */
2
+ export declare const assetLimit: number;
3
+ /** The largest sb3-source.json read to find the assets directory. */
4
+ export declare const folderSettingsLimit: number;
5
+ /** Asset names are plain `<md5>.<ext>` file names; anything else could address a path outside the assets directory. */
6
+ export declare const isAssetName: (name: unknown) => name is string;
7
+ /**
8
+ * The assets directory named by one version of a project folder's `sb3-source.json`, as path segments relative to the
9
+ * folder. `assets` when that file or its `assetsDirectory` field is missing or unreadable. `null` when the field names
10
+ * anything other than a plain relative path inside the folder.
11
+ */
12
+ export declare function assetsDirectoryParts(settings: string | null): string[] | null;
@@ -0,0 +1,19 @@
1
+ import type { ProjectTarget } from './project-source-patch.js';
2
+ export type ProjectVersion = 'before' | 'after';
3
+ /**
4
+ * Reads one asset of one version of a project file by its `md5ext` name (for example `0123…cdef.svg`), from the
5
+ * assets directory of that project. Resolves `null` when that version has no readable file of that name.
6
+ */
7
+ export type ProjectAssetLoader = (request: {
8
+ version: ProjectVersion;
9
+ md5ext: string;
10
+ signal: AbortSignal;
11
+ }) => Promise<Blob | null>;
12
+ /** The costume a sprite shows, or the backdrop the stage shows, when the project data names an image file for it. */
13
+ export declare function currentCostume(target: ProjectTarget): {
14
+ name: string;
15
+ md5ext: string;
16
+ type: string;
17
+ } | null;
18
+ /** Loads the current costume of one version of a target as an object URL for an image, or `null` while it is unavailable. */
19
+ export declare function useCostumeImage(target: ProjectTarget | undefined, version: ProjectVersion, loadAsset?: ProjectAssetLoader): string | null;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import type { ProjectBlockLocator } from './block-diff-location.js';
3
+ import type { ProjectBlockRenderer } from './scratch-block-diff-renderer.js';
4
+ import './project-source-diff.css';
5
+ export { createGitHubPullRequests, gitHubRepositoryFromOrigin } from './github-pull-requests.js';
6
+ export { ProjectSourceComparison, ProjectSourceReview } from './project-source-review.js';
7
+ export type { ProjectSourceComparisonProps, ProjectSourceReviewFile, ProjectSourceReviewProps } from './project-source-review.js';
8
+ export { createScratchBlocksDiffLocator } from './block-diff-location.js';
9
+ export type { ProjectBlockLocation, ProjectBlockLocator, ScratchBlockLocationWorkspace } from './block-diff-location.js';
10
+ export type { BlockPart } from './project-source-patch.js';
11
+ export { createProjectSourceDiff } from './project-source-patch.js';
12
+ export { currentCostume } from './project-assets.js';
13
+ export type { ProjectAssetLoader, ProjectVersion } from './project-assets.js';
14
+ export { createScratchBlocksDiffRenderer } from './scratch-block-diff-renderer.js';
15
+ export type { BlockPreviewView, BlockPreviewViewport, ProjectBlockRenderer, ProjectBlockRendering, ScratchBlockDiffRendererOptions, ScratchBlocksPort } from './scratch-block-diff-renderer.js';
16
+ export { createPreviewSync } from './block-diff-preview.js';
17
+ export type { PreviewSync } from './block-diff-preview.js';
18
+ export interface ProjectSourceBlockDiffProps {
19
+ patch: string;
20
+ /** Supply the original JSON if the unified patch omits context. */
21
+ beforeSource?: string;
22
+ renderBlock: ProjectBlockRenderer;
23
+ locateBlock?: ProjectBlockLocator;
24
+ locale?: string;
25
+ }
26
+ export declare function ProjectSourceBlockDiff({ patch, beforeSource, renderBlock, locateBlock, locale }: ProjectSourceBlockDiffProps): React.JSX.Element;
@@ -0,0 +1,172 @@
1
+ import { a as gitHubRepositoryFromOrigin, c as BlockPreview, d as currentCostume, f as compareProjectBlocks, i as createGitHubPullRequests, l as createPreviewSync, m as readProjectSourceDiff, n as createScratchBlocksDiffLocator, o as ProjectSourceComparison, p as createProjectSourceDiff, s as ProjectSourceReview, t as createScratchBlocksDiffRenderer, u as usePreviewSync } from "./scratch-block-diff-renderer-xS8OYsRl.js";
2
+ import { n as init_objectSpread2, t as _objectSpread2 } from "./objectSpread2-Dkd68nJH.js";
3
+ import React, { useEffect, useMemo, useRef, useState } from "react";
4
+ // src/project-source-diff.tsx
5
+ init_objectSpread2();
6
+ var en = {
7
+ title: "Block changes",
8
+ before: "Before",
9
+ after: "After",
10
+ added: "Added",
11
+ removed: "Removed",
12
+ updated: "Changed",
13
+ inputs: "Inputs",
14
+ fields: "Fields",
15
+ opcode: "Block type",
16
+ mutation: "Block shape",
17
+ position: "Position",
18
+ connection: "Connections",
19
+ properties: "Other block properties",
20
+ absent: "No block on this side",
21
+ omitted: (count) => `${count} unchanged blocks omitted from the change list`,
22
+ context: "Highlight in the surrounding code",
23
+ more: "Show more changes",
24
+ noChanges: "No block changes.",
25
+ locate: "Highlight in Editor",
26
+ locating: "Finding the block in the Editor…",
27
+ located: "Highlighted in the Editor.",
28
+ missingLocation: "This version or block is unavailable in the Editor. Open its surrounding code here.",
29
+ partLegend: "Orange outlines mark changed inputs and fields.",
30
+ otherChanges: "The project also has changes outside its block code.",
31
+ invalid: "This diff could not be read. Use a full-context project diff, or provide the original project.",
32
+ loading: "Rendering blocks…",
33
+ unavailable: "This block could not be rendered. Check the block definitions available in the host."
34
+ };
35
+ var ja = {
36
+ title: "ブロックの変更",
37
+ before: "変更前",
38
+ after: "変更後",
39
+ added: "追加",
40
+ removed: "削除",
41
+ updated: "変更",
42
+ inputs: "入力値",
43
+ fields: "フィールド",
44
+ opcode: "ブロックの種類",
45
+ mutation: "ブロックの形",
46
+ position: "位置",
47
+ connection: "つなぎ方",
48
+ properties: "その他のブロック属性",
49
+ absent: "この側にはブロックがありません",
50
+ omitted: (count) => `変更のないブロック ${count} 個を一覧から省略`,
51
+ context: "元のコード内で強調",
52
+ more: "続きを表示",
53
+ noChanges: "ブロックの変更はありません。",
54
+ locate: "編集画面で強調",
55
+ locating: "編集画面でブロックを検索中…",
56
+ located: "編集画面で強調しました。",
57
+ missingLocation: "編集画面に該当する版またはブロックがありません。元のコードをここで展開できます。",
58
+ partLegend: "オレンジの枠は、変更された入力欄やフィールドです。",
59
+ otherChanges: "ブロックのコード以外にも作品の変更があります。",
60
+ invalid: "差分を読み込めません。全体の文脈を含む差分を使うか、変更前の作品を指定してください。",
61
+ loading: "ブロックを描画中…",
62
+ unavailable: "ブロックを描画できません。ホストのブロック定義を確認してください。"
63
+ };
64
+ var propertyLabels = /* @__PURE__ */ new Map([
65
+ ["inputs", "inputs"],
66
+ ["fields", "fields"],
67
+ ["opcode", "opcode"],
68
+ ["mutation", "mutation"],
69
+ ["x", "position"],
70
+ ["y", "position"],
71
+ ["next", "connection"],
72
+ ["parent", "connection"],
73
+ ["topLevel", "connection"]
74
+ ]);
75
+ function ChangeCard({ change, renderBlock, labels, onLocate, location }) {
76
+ var _change$after;
77
+ const [withContext, setWithContext] = useState(false);
78
+ const { sync, toggle } = usePreviewSync(labels === en ? "en" : "ja");
79
+ const notes = [...new Set(change.fields.map((field) => {
80
+ var _propertyLabels$get;
81
+ return labels[(_propertyLabels$get = propertyLabels.get(field)) !== null && _propertyLabels$get !== void 0 ? _propertyLabels$get : "properties"];
82
+ }))];
83
+ const name = ((_change$after = change.after) !== null && _change$after !== void 0 ? _change$after : change.before).target.name;
84
+ return /* @__PURE__ */ React.createElement("article", { className: `twgit-block-diff-card twgit-block-diff-${change.kind}` }, /* @__PURE__ */ React.createElement("header", null, /* @__PURE__ */ React.createElement("h3", null, /* @__PURE__ */ React.createElement("span", null, labels[change.kind]), " ", name), !!notes.length && /* @__PURE__ */ React.createElement("p", null, notes.join(" · ")), !!change.parts.length && /* @__PURE__ */ React.createElement("p", { className: "twgit-block-diff-legend" }, labels.partLegend)), /* @__PURE__ */ React.createElement("div", { className: "twgit-block-diff-sides" }, ["before", "after"].map((version) => /* @__PURE__ */ React.createElement(BlockPreview, {
85
+ key: version,
86
+ side: change[version],
87
+ title: labels[version],
88
+ renderBlock,
89
+ withContext,
90
+ labels,
91
+ parts: change.parts,
92
+ onLocate: onLocate && (() => onLocate(version)),
93
+ version,
94
+ sync,
95
+ locationStatus: (location === null || location === void 0 ? void 0 : location.version) === version ? location.status : void 0
96
+ }))), toggle, /* @__PURE__ */ React.createElement("label", null, /* @__PURE__ */ React.createElement("input", {
97
+ type: "checkbox",
98
+ checked: withContext,
99
+ onChange: (event) => setWithContext(event.currentTarget.checked)
100
+ }), " ", labels.context));
101
+ }
102
+ var pageSize = 12;
103
+ var empty = {
104
+ changes: [],
105
+ unchanged: 0,
106
+ otherChanges: false
107
+ };
108
+ function ProjectSourceBlockDiff({ patch, beforeSource, renderBlock, locateBlock, locale = "en" }) {
109
+ const labels = locale.startsWith("ja") ? ja : en;
110
+ const result = useMemo(() => {
111
+ try {
112
+ const projects = readProjectSourceDiff(patch, beforeSource);
113
+ return projects ? compareProjectBlocks(...projects) : empty;
114
+ } catch (_unused) {
115
+ return null;
116
+ }
117
+ }, [patch, beforeSource]);
118
+ const [page, setPage] = useState({
119
+ result,
120
+ visible: pageSize
121
+ });
122
+ const request = useRef();
123
+ const [location, setLocation] = useState();
124
+ useEffect(() => () => {
125
+ var _request$current;
126
+ return (_request$current = request.current) === null || _request$current === void 0 ? void 0 : _request$current.abort();
127
+ }, [result, locateBlock]);
128
+ const locate = async (change, version) => {
129
+ var _request$current2;
130
+ const side = change[version];
131
+ if (!side || !locateBlock) return;
132
+ (_request$current2 = request.current) === null || _request$current2 === void 0 || _request$current2.abort();
133
+ const controller = new AbortController();
134
+ request.current = controller;
135
+ const selected = {
136
+ result,
137
+ key: change.key,
138
+ version,
139
+ locator: locateBlock
140
+ };
141
+ setLocation(_objectSpread2(_objectSpread2({}, selected), {}, { status: "locating" }));
142
+ let found = false;
143
+ try {
144
+ found = await locateBlock(_objectSpread2(_objectSpread2({}, side), {}, {
145
+ version,
146
+ parts: change.parts,
147
+ signal: controller.signal
148
+ }));
149
+ } catch (_unused2) {}
150
+ if (!controller.signal.aborted) setLocation(_objectSpread2(_objectSpread2({}, selected), {}, { status: found ? "located" : "missingLocation" }));
151
+ };
152
+ if (!result) return /* @__PURE__ */ React.createElement("p", { role: "alert" }, labels.invalid);
153
+ const visible = page.result === result ? page.visible : pageSize;
154
+ return /* @__PURE__ */ React.createElement("section", {
155
+ className: "twgit-block-diff",
156
+ "aria-label": labels.title
157
+ }, /* @__PURE__ */ React.createElement("h2", null, labels.title, " · ", result.changes.length), result.unchanged > 0 && /* @__PURE__ */ React.createElement("p", null, labels.omitted(result.unchanged)), result.otherChanges && /* @__PURE__ */ React.createElement("p", null, labels.otherChanges), !result.changes.length && /* @__PURE__ */ React.createElement("p", null, labels.noChanges), result.changes.slice(0, visible).map((change) => /* @__PURE__ */ React.createElement(ChangeCard, {
158
+ key: change.key,
159
+ change,
160
+ renderBlock,
161
+ labels,
162
+ onLocate: locateBlock && ((version) => void locate(change, version)),
163
+ location: (location === null || location === void 0 ? void 0 : location.result) === result && location.locator === locateBlock && location.key === change.key ? location : void 0
164
+ })), visible < result.changes.length && /* @__PURE__ */ React.createElement("button", {
165
+ type: "button",
166
+ onClick: () => setPage({
167
+ result,
168
+ visible: visible + pageSize
169
+ })
170
+ }, labels.more));
171
+ }
172
+ export { ProjectSourceBlockDiff, ProjectSourceComparison, ProjectSourceReview, createGitHubPullRequests, createPreviewSync, createProjectSourceDiff, createScratchBlocksDiffLocator, createScratchBlocksDiffRenderer, currentCostume, gitHubRepositoryFromOrigin };
@@ -0,0 +1,39 @@
1
+ export type BlockTable = Record<string, unknown>;
2
+ export interface ProjectTarget {
3
+ name: string;
4
+ isStage: boolean;
5
+ blocks: BlockTable;
6
+ }
7
+ export type ProjectSource = Record<string, unknown> & {
8
+ targets: ProjectTarget[];
9
+ };
10
+ export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
11
+ /** Reads one version of a project.source.json. `null` stands for a version in which the file does not exist. */
12
+ export declare function parseProjectSource(source: string | null): ProjectSource;
13
+ /** Keep the original lines and include enough context to render both sides from the patch alone. */
14
+ export declare function createProjectSourceDiff(before: string, after: string): string;
15
+ export declare function readProjectSourceDiff(patch: string, beforeSource?: string): [ProjectSource, ProjectSource] | null;
16
+ export declare function equal(a: unknown, b: unknown): boolean;
17
+ export declare const targetKey: (target: ProjectTarget) => string;
18
+ export interface BlockSide {
19
+ target: ProjectTarget;
20
+ id: string;
21
+ }
22
+ export interface BlockPart {
23
+ kind: 'input' | 'field';
24
+ name: string;
25
+ }
26
+ export type BlockChangeKind = 'added' | 'removed' | 'updated';
27
+ export interface BlockChange {
28
+ key: string;
29
+ before?: BlockSide;
30
+ after?: BlockSide;
31
+ kind: BlockChangeKind;
32
+ fields: string[];
33
+ parts: BlockPart[];
34
+ }
35
+ export declare function compareProjectBlocks(before: ProjectSource, after: ProjectSource): {
36
+ changes: BlockChange[];
37
+ unchanged: number;
38
+ otherChanges: boolean;
39
+ };
@@ -0,0 +1,23 @@
1
+ import type { BlockSide, ProjectSource, ProjectTarget } from './project-source-patch.js';
2
+ import type { ScriptBlockMark } from './scratch-block-diff-renderer.js';
3
+ export interface ScriptReviewSide extends BlockSide {
4
+ marks: ScriptBlockMark[];
5
+ }
6
+ export interface ScriptReview {
7
+ id: string;
8
+ before: ScriptReviewSide[];
9
+ after: ScriptReviewSide[];
10
+ }
11
+ export interface TargetReview {
12
+ name: string;
13
+ isStage: boolean;
14
+ /** The stage or sprite in each version, absent where it does not exist. */
15
+ before?: ProjectTarget;
16
+ after?: ProjectTarget;
17
+ scripts: ScriptReview[];
18
+ properties: string[];
19
+ }
20
+ export declare function compareProjectForReview(before: ProjectSource, after: ProjectSource): {
21
+ targets: TargetReview[];
22
+ properties: string[];
23
+ };
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import type { ProjectBlockRenderer } from './scratch-block-diff-renderer.js';
3
+ import type { ProjectAssetLoader } from './project-assets.js';
4
+ export type ProjectSourceReviewFile = {
5
+ path: string;
6
+ summary?: string;
7
+ previousPath?: string;
8
+ unavailable?: boolean;
9
+ } & ({
10
+ patch: string;
11
+ beforeSource?: string;
12
+ loadAsset?: ProjectAssetLoader;
13
+ } | {
14
+ status: 'added' | 'removed' | 'updated';
15
+ });
16
+ export interface ProjectSourceReviewProps {
17
+ title: string;
18
+ description?: string;
19
+ verification?: readonly string[];
20
+ files: readonly ProjectSourceReviewFile[];
21
+ renderBlock: ProjectBlockRenderer;
22
+ locale?: string;
23
+ }
24
+ export interface ProjectSourceComparisonProps {
25
+ /** The earlier project.source.json, or `null` when the file did not exist yet. */
26
+ before: string | null;
27
+ /** The later project.source.json, or `null` when the file was removed. */
28
+ after: string | null;
29
+ renderBlock: ProjectBlockRenderer;
30
+ locale?: string;
31
+ /** Shown after an explanation when either version cannot be read as a project. Without it, only an error is shown. */
32
+ fallback?: React.ReactNode;
33
+ /** Reads the images of both versions for thumbnails. Without it, stages and sprites are shown by name. */
34
+ loadAsset?: ProjectAssetLoader;
35
+ }
36
+ /** Compares two versions of a project.source.json by stage, sprite and code, as the pull request review does. */
37
+ export declare function ProjectSourceComparison({ before, after, renderBlock, locale, fallback, loadAsset }: ProjectSourceComparisonProps): React.JSX.Element;
38
+ export declare function ProjectSourceReview({ title, description, verification, files, renderBlock, locale }: ProjectSourceReviewProps): React.JSX.Element;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { ProjectBlockRenderer } from './scratch-block-diff-renderer.js';
3
+ import type { Repository } from './repository.js';
4
+ export declare function PullRequestReviewPanel({ repository, locale, renderBlock }: {
5
+ repository: Repository;
6
+ locale: string;
7
+ renderBlock: ProjectBlockRenderer;
8
+ }): React.JSX.Element;
@@ -0,0 +1,5 @@
1
+ import type { GitSmartHttpOptions } from './smart-http.js';
2
+ export type RemoteOperation = 'fetch' | 'pull' | 'push';
3
+ export type RemoteSession = NonNullable<Awaited<ReturnType<GitSmartHttpOptions['getSession']>>>;
4
+ export type GetRemoteSession = (remote: string, write: boolean) => Promise<RemoteSession | null>;
5
+ export declare function runRemoteOperation(root: FileSystemDirectoryHandle, operation: RemoteOperation, getSession: GetRemoteSession, guard: () => void, signal?: AbortSignal): Promise<void>;