@kubohiroya/turbowarp-plus-editor-git 0.10.0 → 0.12.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/dist/editor-block-locator.d.ts +27 -0
- package/dist/file-diff-view.d.ts +3 -1
- package/dist/index.d.ts +25 -0
- package/dist/index.js +126 -32
- package/dist/project-change-list.d.ts +3 -1
- 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/project-source-review.d.ts +6 -1
- package/dist/pull-request-panel.d.ts +4 -1
- package/dist/review-words.d.ts +6 -0
- package/dist/{scratch-block-diff-renderer-DZR8ep-T.js → scratch-block-diff-renderer-e_drVlHE.js} +598 -263
- package/dist/style.css +16 -0
- package/package.json +1 -1
- package/src/editor-block-locator.ts +55 -0
- package/src/file-diff-view.tsx +4 -3
- package/src/index.tsx +74 -16
- package/src/project-change-list.tsx +4 -3
- 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 +136 -24
- package/src/pull-request-panel.tsx +9 -4
- package/src/review-words.ts +66 -0
- package/src/style.css +2 -0
package/dist/{scratch-block-diff-renderer-DZR8ep-T.js → scratch-block-diff-renderer-e_drVlHE.js}
RENAMED
|
@@ -912,7 +912,9 @@ function groupScripts(before, after, changes) {
|
|
|
912
912
|
const group = (_groups$get = groups.get(id)) !== null && _groups$get !== void 0 ? _groups$get : {
|
|
913
913
|
id,
|
|
914
914
|
before: [],
|
|
915
|
-
after: []
|
|
915
|
+
after: [],
|
|
916
|
+
kind: "updated",
|
|
917
|
+
summary: []
|
|
916
918
|
};
|
|
917
919
|
const side = {
|
|
918
920
|
target,
|
|
@@ -924,20 +926,151 @@ function groupScripts(before, after, changes) {
|
|
|
924
926
|
sides.set(key, side);
|
|
925
927
|
}
|
|
926
928
|
}
|
|
927
|
-
const affected = /* @__PURE__ */ new
|
|
929
|
+
const affected = /* @__PURE__ */ new Map();
|
|
928
930
|
for (const change of changes) for (const version of ["before", "after"]) {
|
|
929
|
-
var _sides$get;
|
|
931
|
+
var _sides$get, _affected$get;
|
|
930
932
|
const block = change[version];
|
|
931
933
|
if (!block) continue;
|
|
932
934
|
const key = version + ":" + roots[version].get(block.id);
|
|
933
|
-
(_sides$get = sides.get(key)) === null || _sides$get === void 0 || _sides$get.marks.push({
|
|
935
|
+
if (!isLayoutOnly(change)) (_sides$get = sides.get(key)) === null || _sides$get === void 0 || _sides$get.marks.push({
|
|
934
936
|
id: block.id,
|
|
935
937
|
kind: change.kind,
|
|
936
938
|
parts: change.parts
|
|
937
939
|
});
|
|
938
|
-
|
|
940
|
+
const id = groupOf(key);
|
|
941
|
+
const list = (_affected$get = affected.get(id)) !== null && _affected$get !== void 0 ? _affected$get : [];
|
|
942
|
+
if (!list.includes(change)) list.push(change);
|
|
943
|
+
affected.set(id, list);
|
|
939
944
|
}
|
|
940
|
-
return [...affected].map((id) =>
|
|
945
|
+
return [...affected].map(([id, list]) => {
|
|
946
|
+
const group = groups.get(id);
|
|
947
|
+
group.kind = scriptKind(group, list);
|
|
948
|
+
group.summary = summarize(group, list, before, after);
|
|
949
|
+
return group;
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
var connectionFields = /* @__PURE__ */ new Set([
|
|
953
|
+
"next",
|
|
954
|
+
"parent",
|
|
955
|
+
"topLevel"
|
|
956
|
+
]);
|
|
957
|
+
var positionFields = /* @__PURE__ */ new Set(["x", "y"]);
|
|
958
|
+
var compactPositionOnly = (a, b) => Array.isArray(a) && Array.isArray(b) && equal(a.slice(0, 3), b.slice(0, 3)) && !equal(a, b);
|
|
959
|
+
function blockOf(side) {
|
|
960
|
+
return side ? side.target.blocks[side.id] : void 0;
|
|
961
|
+
}
|
|
962
|
+
/** True for an updated block whose content is the same: only its connections or its position changed. */
|
|
963
|
+
function isLayoutOnly(change) {
|
|
964
|
+
if (change.kind !== "updated") return false;
|
|
965
|
+
if (compactPositionOnly(blockOf(change.before), blockOf(change.after))) return true;
|
|
966
|
+
return change.fields.length > 0 && change.fields.every((field) => connectionFields.has(field) || positionFields.has(field));
|
|
967
|
+
}
|
|
968
|
+
function isPositionOnly(change) {
|
|
969
|
+
if (change.kind !== "updated") return false;
|
|
970
|
+
if (compactPositionOnly(blockOf(change.before), blockOf(change.after))) return true;
|
|
971
|
+
return change.fields.length > 0 && change.fields.every((field) => positionFields.has(field));
|
|
972
|
+
}
|
|
973
|
+
function scriptKind(group, changes) {
|
|
974
|
+
if (!group.before.length) return "added";
|
|
975
|
+
if (!group.after.length) return "removed";
|
|
976
|
+
if (group.before.length !== 1 || group.after.length !== 1) return "reorganized";
|
|
977
|
+
if (changes.every(isPositionOnly)) return "moved";
|
|
978
|
+
if (changes.every(isLayoutOnly)) return "reordered";
|
|
979
|
+
return "updated";
|
|
980
|
+
}
|
|
981
|
+
var opcodeOf = (block) => isRecord(block) && typeof block.opcode === "string" ? block.opcode : void 0;
|
|
982
|
+
var isShadow = (block) => !isRecord(block) || block.shadow === true;
|
|
983
|
+
var isHat = (opcode) => opcode !== void 0 && (opcode === "control_start_as_clone" || opcode === "procedures_definition" || /^[a-z0-9]+_when/i.test(opcode));
|
|
984
|
+
var substackInputs = ["SUBSTACK", "SUBSTACK2"];
|
|
985
|
+
function inputBlock(block, name) {
|
|
986
|
+
if (!isRecord(block) || !isRecord(block.inputs)) return void 0;
|
|
987
|
+
const input = block.inputs[name];
|
|
988
|
+
return Array.isArray(input) && typeof input[1] === "string" ? input[1] : void 0;
|
|
989
|
+
}
|
|
990
|
+
function summarize(group, changes, before, after) {
|
|
991
|
+
const items = [];
|
|
992
|
+
const seen = /* @__PURE__ */ new Set();
|
|
993
|
+
const add = (item) => {
|
|
994
|
+
const key = JSON.stringify(item);
|
|
995
|
+
if (seen.has(key)) return;
|
|
996
|
+
seen.add(key);
|
|
997
|
+
items.push(item);
|
|
998
|
+
};
|
|
999
|
+
if (group.kind === "moved" || group.kind === "reordered") {
|
|
1000
|
+
add({ kind: group.kind });
|
|
1001
|
+
return items;
|
|
1002
|
+
}
|
|
1003
|
+
const explained = /* @__PURE__ */ new Set();
|
|
1004
|
+
if (group.before.length === 1 && group.after.length === 1) {
|
|
1005
|
+
const oldRoot = group.before[0].id, newRoot = group.after[0].id;
|
|
1006
|
+
const a = opcodeOf(before === null || before === void 0 ? void 0 : before.blocks[oldRoot]), b = opcodeOf(after === null || after === void 0 ? void 0 : after.blocks[newRoot]);
|
|
1007
|
+
if (a !== b && isHat(a) && isHat(b)) {
|
|
1008
|
+
add({
|
|
1009
|
+
kind: "hatReplaced",
|
|
1010
|
+
before: a,
|
|
1011
|
+
after: b
|
|
1012
|
+
});
|
|
1013
|
+
for (const change of changes) {
|
|
1014
|
+
var _change$after, _change$before;
|
|
1015
|
+
if (change.kind === "added" && ((_change$after = change.after) === null || _change$after === void 0 ? void 0 : _change$after.id) === newRoot || change.kind === "removed" && ((_change$before = change.before) === null || _change$before === void 0 ? void 0 : _change$before.id) === oldRoot) explained.add(change);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
const branches = [];
|
|
1020
|
+
for (const change of changes) {
|
|
1021
|
+
if (change.kind !== "added" || !after) continue;
|
|
1022
|
+
const block = after.blocks[change.after.id];
|
|
1023
|
+
const opcode = opcodeOf(block);
|
|
1024
|
+
if (!opcode) continue;
|
|
1025
|
+
if (substackInputs.some((name) => {
|
|
1026
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1027
|
+
for (let id = inputBlock(block, name); id !== void 0 && !visited.has(id);) {
|
|
1028
|
+
visited.add(id);
|
|
1029
|
+
if (before && Object.hasOwn(before.blocks, id)) return true;
|
|
1030
|
+
const next = after.blocks[id];
|
|
1031
|
+
id = isRecord(next) && typeof next.next === "string" ? next.next : void 0;
|
|
1032
|
+
}
|
|
1033
|
+
return false;
|
|
1034
|
+
})) {
|
|
1035
|
+
add({
|
|
1036
|
+
kind: "wrapped",
|
|
1037
|
+
opcode
|
|
1038
|
+
});
|
|
1039
|
+
explained.add(change);
|
|
1040
|
+
} else if (opcode === "control_if" || opcode === "control_if_else") branches.push(change);
|
|
1041
|
+
}
|
|
1042
|
+
for (const change of branches) {
|
|
1043
|
+
add({
|
|
1044
|
+
kind: "branchAdded",
|
|
1045
|
+
opcode: opcodeOf(after.blocks[change.after.id])
|
|
1046
|
+
});
|
|
1047
|
+
explained.add(change);
|
|
1048
|
+
}
|
|
1049
|
+
for (const change of changes) {
|
|
1050
|
+
var _opcodeOf;
|
|
1051
|
+
if (change.kind !== "updated") continue;
|
|
1052
|
+
const opcode = (_opcodeOf = opcodeOf(blockOf(change.after))) !== null && _opcodeOf !== void 0 ? _opcodeOf : opcodeOf(blockOf(change.before));
|
|
1053
|
+
if (!opcode) continue;
|
|
1054
|
+
for (const part of change.parts) {
|
|
1055
|
+
if (part.kind === "input" && substackInputs.includes(part.name)) continue;
|
|
1056
|
+
add({
|
|
1057
|
+
kind: "valueChanged",
|
|
1058
|
+
opcode,
|
|
1059
|
+
name: part.name
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
const count = (kind) => changes.filter((change) => change.kind === kind && !explained.has(change) && !isShadow(blockOf(kind === "added" ? change.after : change.before))).length;
|
|
1064
|
+
const added = count("added"), removed = count("removed");
|
|
1065
|
+
if (added) add({
|
|
1066
|
+
kind: "blocksAdded",
|
|
1067
|
+
count: added
|
|
1068
|
+
});
|
|
1069
|
+
if (removed) add({
|
|
1070
|
+
kind: "blocksRemoved",
|
|
1071
|
+
count: removed
|
|
1072
|
+
});
|
|
1073
|
+
return items;
|
|
941
1074
|
}
|
|
942
1075
|
function changedProperties(before, after, except) {
|
|
943
1076
|
return [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])].filter((key) => key !== except && !equal(before[key], after[key]));
|
|
@@ -946,8 +1079,8 @@ function compareProjectForReview(before, after) {
|
|
|
946
1079
|
const { changes } = compareProjectBlocks(before, after);
|
|
947
1080
|
const byTarget = /* @__PURE__ */ new Map();
|
|
948
1081
|
for (const change of changes) {
|
|
949
|
-
var _change$
|
|
950
|
-
const key = targetKey(((_change$
|
|
1082
|
+
var _change$after2;
|
|
1083
|
+
const key = targetKey(((_change$after2 = change.after) !== null && _change$after2 !== void 0 ? _change$after2 : change.before).target);
|
|
951
1084
|
const existing = byTarget.get(key);
|
|
952
1085
|
if (existing) existing.push(change);
|
|
953
1086
|
else byTarget.set(key, [change]);
|
|
@@ -959,12 +1092,14 @@ function compareProjectForReview(before, after) {
|
|
|
959
1092
|
const a = oldTargets.get(key), b = newTargets.get(key);
|
|
960
1093
|
const edits = byTarget.get(key);
|
|
961
1094
|
const scripts = edits ? groupScripts(a, b, edits) : [];
|
|
962
|
-
const
|
|
963
|
-
|
|
1095
|
+
const status = !a ? "added" : !b ? "removed" : "updated";
|
|
1096
|
+
const properties = status === "updated" ? changedProperties(_objectSpread2({}, a), _objectSpread2({}, b), "blocks") : [];
|
|
1097
|
+
if (scripts.length || properties.length || status !== "updated") {
|
|
964
1098
|
const { name, isStage } = b !== null && b !== void 0 ? b : a;
|
|
965
1099
|
targets.push({
|
|
966
1100
|
name,
|
|
967
1101
|
isStage,
|
|
1102
|
+
status,
|
|
968
1103
|
scripts,
|
|
969
1104
|
properties,
|
|
970
1105
|
before: a,
|
|
@@ -977,6 +1112,308 @@ function compareProjectForReview(before, after) {
|
|
|
977
1112
|
properties: changedProperties(before, after, "targets")
|
|
978
1113
|
};
|
|
979
1114
|
}
|
|
1115
|
+
// src/project-change-model.ts
|
|
1116
|
+
init_objectSpread2();
|
|
1117
|
+
var targetDataKeys = [
|
|
1118
|
+
"variables",
|
|
1119
|
+
"lists",
|
|
1120
|
+
"broadcasts"
|
|
1121
|
+
];
|
|
1122
|
+
var nonSettingKeys = /* @__PURE__ */ new Set([
|
|
1123
|
+
"blocks",
|
|
1124
|
+
"costumes",
|
|
1125
|
+
"sounds",
|
|
1126
|
+
...targetDataKeys
|
|
1127
|
+
]);
|
|
1128
|
+
var propertyLabels = /* @__PURE__ */ new Map([
|
|
1129
|
+
["variables", ["変数", "Variables"]],
|
|
1130
|
+
["lists", ["リスト", "Lists"]],
|
|
1131
|
+
["broadcasts", ["メッセージ", "Broadcast messages"]],
|
|
1132
|
+
["costumes", ["コスチューム・背景", "Costumes and backdrops"]],
|
|
1133
|
+
["sounds", ["音", "Sounds"]],
|
|
1134
|
+
["blocks", ["コード", "Code"]],
|
|
1135
|
+
["x", ["X 座標", "X position"]],
|
|
1136
|
+
["y", ["Y 座標", "Y position"]],
|
|
1137
|
+
["size", ["大きさ", "Size"]],
|
|
1138
|
+
["direction", ["向き", "Direction"]],
|
|
1139
|
+
["visible", ["表示状態", "Visibility"]],
|
|
1140
|
+
["currentCostume", ["表示するコスチューム", "Selected costume"]],
|
|
1141
|
+
["layerOrder", ["重なり順", "Layer order"]],
|
|
1142
|
+
["volume", ["音量", "Volume"]],
|
|
1143
|
+
["comments", ["コメント", "Comments"]],
|
|
1144
|
+
["draggable", ["ドラッグ可否", "Draggable"]],
|
|
1145
|
+
["rotationStyle", ["回転方法", "Rotation style"]],
|
|
1146
|
+
["tempo", ["テンポ", "Tempo"]],
|
|
1147
|
+
["videoTransparency", ["ビデオの透明度", "Video transparency"]],
|
|
1148
|
+
["videoState", ["ビデオの状態", "Video state"]],
|
|
1149
|
+
["textToSpeechLanguage", ["音声合成の言語", "Text to speech language"]],
|
|
1150
|
+
["monitors", ["モニター", "Monitors"]],
|
|
1151
|
+
["extensions", ["拡張機能", "Extensions"]],
|
|
1152
|
+
["meta", ["作品の情報", "Project metadata"]]
|
|
1153
|
+
]);
|
|
1154
|
+
/** The Japanese or English name of a project or target property key; unknown keys are returned as they are. */
|
|
1155
|
+
function projectPropertyLabel(key, locale = "en") {
|
|
1156
|
+
var _propertyLabels$get, _propertyLabels$get2;
|
|
1157
|
+
return (_propertyLabels$get = (_propertyLabels$get2 = propertyLabels.get(key)) === null || _propertyLabels$get2 === void 0 ? void 0 : _propertyLabels$get2[locale.startsWith("ja") ? 0 : 1]) !== null && _propertyLabels$get !== void 0 ? _propertyLabels$get : key;
|
|
1158
|
+
}
|
|
1159
|
+
/** The asset file name of a costume or sound entry: `md5ext`, or `assetId.dataFormat`; `''` when it has neither. */
|
|
1160
|
+
function assetFileName(entry) {
|
|
1161
|
+
if (typeof entry.md5ext === "string") return entry.md5ext;
|
|
1162
|
+
return typeof entry.assetId === "string" && typeof entry.dataFormat === "string" ? entry.assetId + "." + entry.dataFormat : "";
|
|
1163
|
+
}
|
|
1164
|
+
function joinPath(...parts) {
|
|
1165
|
+
return parts.flatMap((part) => part.split("/")).filter((part) => part !== "" && part !== ".").join("/");
|
|
1166
|
+
}
|
|
1167
|
+
function statusOf(before, after) {
|
|
1168
|
+
return before === void 0 ? "added" : after === void 0 ? "removed" : "updated";
|
|
1169
|
+
}
|
|
1170
|
+
function entriesOf(target, kind) {
|
|
1171
|
+
const list = target === null || target === void 0 ? void 0 : target[kind];
|
|
1172
|
+
return Array.isArray(list) ? list.filter(isRecord) : [];
|
|
1173
|
+
}
|
|
1174
|
+
function nameOf(entry) {
|
|
1175
|
+
return typeof entry.name === "string" ? entry.name : "";
|
|
1176
|
+
}
|
|
1177
|
+
/** Pairs the entries of two versions by name (repeated names pair in order): after's order first, then removed ones. */
|
|
1178
|
+
function pairEntries(before, after) {
|
|
1179
|
+
var _remaining$get;
|
|
1180
|
+
const remaining = /* @__PURE__ */ new Map();
|
|
1181
|
+
for (const entry of before) {
|
|
1182
|
+
const queue = remaining.get(nameOf(entry));
|
|
1183
|
+
if (queue) queue.push(entry);
|
|
1184
|
+
else remaining.set(nameOf(entry), [entry]);
|
|
1185
|
+
}
|
|
1186
|
+
const pairs = [];
|
|
1187
|
+
for (const entry of after) pairs.push({
|
|
1188
|
+
name: nameOf(entry),
|
|
1189
|
+
before: (_remaining$get = remaining.get(nameOf(entry))) === null || _remaining$get === void 0 ? void 0 : _remaining$get.shift(),
|
|
1190
|
+
after: entry
|
|
1191
|
+
});
|
|
1192
|
+
for (const entry of before) {
|
|
1193
|
+
const queue = remaining.get(nameOf(entry));
|
|
1194
|
+
if ((queue === null || queue === void 0 ? void 0 : queue[0]) === entry) pairs.push({
|
|
1195
|
+
name: nameOf(entry),
|
|
1196
|
+
before: queue.shift()
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
return pairs;
|
|
1200
|
+
}
|
|
1201
|
+
function changedKeys(before, after, skip) {
|
|
1202
|
+
return [.../* @__PURE__ */ new Set([...Object.keys(after), ...Object.keys(before)])].filter((key) => !skip(key) && !equal(before[key], after[key]));
|
|
1203
|
+
}
|
|
1204
|
+
/** Arranges the changed files of one project folder by stage, sprite and element. Pure; reads nothing. */
|
|
1205
|
+
function organizeProjectChanges(input) {
|
|
1206
|
+
const { folder, files, assetsDirectory } = input;
|
|
1207
|
+
const normalize = (project) => project === null ? { targets: [] } : _objectSpread2(_objectSpread2({}, project), {}, { targets: project.targets.map((target) => {
|
|
1208
|
+
var _target$blocks;
|
|
1209
|
+
return _objectSpread2(_objectSpread2({}, target), {}, { blocks: (_target$blocks = target.blocks) !== null && _target$blocks !== void 0 ? _target$blocks : {} });
|
|
1210
|
+
}) });
|
|
1211
|
+
const before = normalize(input.before), after = normalize(input.after);
|
|
1212
|
+
const projectPath = joinPath(folder, "project.source.json");
|
|
1213
|
+
const projectFiles = files.filter((file) => file.path === projectPath);
|
|
1214
|
+
const explained = /* @__PURE__ */ new Set();
|
|
1215
|
+
let projectUsed = false;
|
|
1216
|
+
const useProject = () => {
|
|
1217
|
+
projectUsed = true;
|
|
1218
|
+
return [...projectFiles];
|
|
1219
|
+
};
|
|
1220
|
+
const filesAt = (paths) => {
|
|
1221
|
+
const wanted = new Set(paths.filter((path) => path !== void 0));
|
|
1222
|
+
const found = files.filter((file) => wanted.has(file.path));
|
|
1223
|
+
for (const file of found) explained.add(file.path);
|
|
1224
|
+
return found;
|
|
1225
|
+
};
|
|
1226
|
+
const review = compareProjectForReview(before, after);
|
|
1227
|
+
const scripts = new Map(review.targets.map((target) => {
|
|
1228
|
+
var _target$after;
|
|
1229
|
+
return [targetKey((_target$after = target.after) !== null && _target$after !== void 0 ? _target$after : target.before), target.scripts.length];
|
|
1230
|
+
}));
|
|
1231
|
+
const oldTargets = new Map(before.targets.map((target) => [targetKey(target), target]));
|
|
1232
|
+
const newTargets = new Map(after.targets.map((target) => [targetKey(target), target]));
|
|
1233
|
+
const keys = [...new Set([...after.targets, ...before.targets].map(targetKey))];
|
|
1234
|
+
keys.sort((a, b) => Number(b === "stage") - Number(a === "stage"));
|
|
1235
|
+
const targets = [];
|
|
1236
|
+
for (const key of keys) {
|
|
1237
|
+
var _scripts$get;
|
|
1238
|
+
const a = oldTargets.get(key), b = newTargets.get(key);
|
|
1239
|
+
const status = statusOf(a, b);
|
|
1240
|
+
const elements = [];
|
|
1241
|
+
const count = (_scripts$get = scripts.get(key)) !== null && _scripts$get !== void 0 ? _scripts$get : 0;
|
|
1242
|
+
if (count) elements.push({
|
|
1243
|
+
key: JSON.stringify([
|
|
1244
|
+
key,
|
|
1245
|
+
"code",
|
|
1246
|
+
""
|
|
1247
|
+
]),
|
|
1248
|
+
kind: "code",
|
|
1249
|
+
status,
|
|
1250
|
+
scripts: count,
|
|
1251
|
+
files: useProject()
|
|
1252
|
+
});
|
|
1253
|
+
for (const kind of ["costumes", "sounds"]) {
|
|
1254
|
+
const seen = /* @__PURE__ */ new Map();
|
|
1255
|
+
for (const pair of pairEntries(entriesOf(a, kind), entriesOf(b, kind))) {
|
|
1256
|
+
var _seen$get;
|
|
1257
|
+
const md5ext = {
|
|
1258
|
+
before: pair.before && assetFileName(pair.before) || void 0,
|
|
1259
|
+
after: pair.after && assetFileName(pair.after) || void 0
|
|
1260
|
+
};
|
|
1261
|
+
const differs = !equal(pair.before, pair.after);
|
|
1262
|
+
const assets = filesAt([md5ext.before && joinPath(folder, assetsDirectory.before, md5ext.before), md5ext.after && joinPath(folder, assetsDirectory.after, md5ext.after)]);
|
|
1263
|
+
if (!differs && !assets.length) continue;
|
|
1264
|
+
const repeat = (_seen$get = seen.get(pair.name)) !== null && _seen$get !== void 0 ? _seen$get : 0;
|
|
1265
|
+
seen.set(pair.name, repeat + 1);
|
|
1266
|
+
elements.push({
|
|
1267
|
+
key: JSON.stringify(repeat ? [
|
|
1268
|
+
key,
|
|
1269
|
+
kind,
|
|
1270
|
+
pair.name,
|
|
1271
|
+
repeat
|
|
1272
|
+
] : [
|
|
1273
|
+
key,
|
|
1274
|
+
kind,
|
|
1275
|
+
pair.name
|
|
1276
|
+
]),
|
|
1277
|
+
kind,
|
|
1278
|
+
status: statusOf(pair.before, pair.after),
|
|
1279
|
+
name: pair.name,
|
|
1280
|
+
before: pair.before,
|
|
1281
|
+
after: pair.after,
|
|
1282
|
+
md5ext,
|
|
1283
|
+
files: [...differs ? useProject() : [], ...assets]
|
|
1284
|
+
});
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if (a && b) {
|
|
1288
|
+
const oldFields = a, newFields = b;
|
|
1289
|
+
const data = changedKeys(oldFields, newFields, (property) => !targetDataKeys.includes(property));
|
|
1290
|
+
if (data.length) elements.push({
|
|
1291
|
+
key: JSON.stringify([
|
|
1292
|
+
key,
|
|
1293
|
+
"data",
|
|
1294
|
+
""
|
|
1295
|
+
]),
|
|
1296
|
+
kind: "data",
|
|
1297
|
+
status,
|
|
1298
|
+
properties: data,
|
|
1299
|
+
files: useProject()
|
|
1300
|
+
});
|
|
1301
|
+
const settings = changedKeys(oldFields, newFields, (property) => nonSettingKeys.has(property));
|
|
1302
|
+
if (settings.length) elements.push({
|
|
1303
|
+
key: JSON.stringify([
|
|
1304
|
+
key,
|
|
1305
|
+
"settings",
|
|
1306
|
+
""
|
|
1307
|
+
]),
|
|
1308
|
+
kind: "settings",
|
|
1309
|
+
status,
|
|
1310
|
+
properties: settings,
|
|
1311
|
+
files: useProject()
|
|
1312
|
+
});
|
|
1313
|
+
} else projectUsed = true;
|
|
1314
|
+
if (status !== "updated" || elements.length) {
|
|
1315
|
+
const { name, isStage } = b !== null && b !== void 0 ? b : a;
|
|
1316
|
+
targets.push({
|
|
1317
|
+
key,
|
|
1318
|
+
name,
|
|
1319
|
+
isStage,
|
|
1320
|
+
status,
|
|
1321
|
+
before: a,
|
|
1322
|
+
after: b,
|
|
1323
|
+
elements
|
|
1324
|
+
});
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
const project = changedKeys(before, after, (key) => key === "targets").map((property) => ({
|
|
1328
|
+
key: JSON.stringify([
|
|
1329
|
+
"project",
|
|
1330
|
+
"settings",
|
|
1331
|
+
property
|
|
1332
|
+
]),
|
|
1333
|
+
kind: "settings",
|
|
1334
|
+
status: statusOf(before[property], after[property]),
|
|
1335
|
+
properties: [property],
|
|
1336
|
+
files: useProject()
|
|
1337
|
+
}));
|
|
1338
|
+
if (projectUsed) explained.add(projectPath);
|
|
1339
|
+
return {
|
|
1340
|
+
targets,
|
|
1341
|
+
project,
|
|
1342
|
+
other: files.filter((file) => !explained.has(file.path))
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
// src/review-words.ts
|
|
1346
|
+
var pick = ([ja, en], locale) => locale.startsWith("ja") ? ja : en;
|
|
1347
|
+
var hats = /* @__PURE__ */ new Map([
|
|
1348
|
+
["event_whenflagclicked", ["緑の旗が押されたとき", "When green flag clicked"]],
|
|
1349
|
+
["event_whenthisspriteclicked", ["このスプライトが押されたとき", "When this sprite clicked"]],
|
|
1350
|
+
["event_whenstageclicked", ["ステージが押されたとき", "When stage clicked"]],
|
|
1351
|
+
["event_whenkeypressed", ["キーが押されたとき", "When key pressed"]],
|
|
1352
|
+
["event_whenbackdropswitchesto", ["背景が切り替わったとき", "When backdrop switches"]],
|
|
1353
|
+
["event_whengreaterthan", ["値が超えたとき", "When value exceeds"]],
|
|
1354
|
+
["event_whenbroadcastreceived", ["メッセージを受け取ったとき", "When message received"]],
|
|
1355
|
+
["control_start_as_clone", ["クローンされたとき", "When I start as a clone"]],
|
|
1356
|
+
["procedures_definition", ["定義", "Define"]]
|
|
1357
|
+
]);
|
|
1358
|
+
var blocks = /* @__PURE__ */ new Map([
|
|
1359
|
+
["control_repeat", ["〜回繰り返す", "repeat"]],
|
|
1360
|
+
["control_forever", ["ずっと", "forever"]],
|
|
1361
|
+
["control_repeat_until", ["〜まで繰り返す", "repeat until"]],
|
|
1362
|
+
["control_while", ["〜の間繰り返す", "while"]],
|
|
1363
|
+
["control_if", ["もし〜なら", "if"]],
|
|
1364
|
+
["control_if_else", ["もし〜なら、でなければ", "if else"]],
|
|
1365
|
+
["control_wait", ["〜秒待つ", "wait"]],
|
|
1366
|
+
["motion_movesteps", ["〜歩動かす", "move steps"]],
|
|
1367
|
+
["motion_turnright", ["〜度回す", "turn"]],
|
|
1368
|
+
["motion_turnleft", ["〜度回す", "turn"]],
|
|
1369
|
+
["motion_gotoxy", ["x座標を〜、y座標を〜にする", "go to x y"]],
|
|
1370
|
+
["motion_changeyby", ["y座標を〜ずつ変える", "change y by"]],
|
|
1371
|
+
["motion_changexby", ["x座標を〜ずつ変える", "change x by"]],
|
|
1372
|
+
["motion_glidesecstoxy", ["〜秒でx座標を〜に、y座標を〜に変える", "glide"]],
|
|
1373
|
+
["looks_sayforsecs", ["〜と〜秒言う", "say for secs"]],
|
|
1374
|
+
["looks_say", ["〜と言う", "say"]],
|
|
1375
|
+
["looks_switchcostumeto", ["コスチュームを〜にする", "switch costume"]],
|
|
1376
|
+
["looks_nextcostume", ["次のコスチュームにする", "next costume"]],
|
|
1377
|
+
["data_setvariableto", ["〜を〜にする", "set variable"]],
|
|
1378
|
+
["data_changevariableby", ["〜を〜ずつ変える", "change variable"]],
|
|
1379
|
+
["event_broadcast", ["〜を送る", "broadcast"]],
|
|
1380
|
+
["sound_play", ["〜の音を鳴らす", "play sound"]]
|
|
1381
|
+
]);
|
|
1382
|
+
function hatName(opcode, locale) {
|
|
1383
|
+
const pair = hats.get(opcode);
|
|
1384
|
+
return pair && pick(pair, locale);
|
|
1385
|
+
}
|
|
1386
|
+
var blockName = (opcode, locale) => {
|
|
1387
|
+
var _blocks$get;
|
|
1388
|
+
const pair = (_blocks$get = blocks.get(opcode)) !== null && _blocks$get !== void 0 ? _blocks$get : hats.get(opcode);
|
|
1389
|
+
return pair ? pick(pair, locale) : locale.startsWith("ja") ? "ブロック" : "a block";
|
|
1390
|
+
};
|
|
1391
|
+
/** One phrase per summary item, in the reader's language. */
|
|
1392
|
+
function summaryPhrase(item, locale) {
|
|
1393
|
+
const ja = locale.startsWith("ja");
|
|
1394
|
+
switch (item.kind) {
|
|
1395
|
+
case "hatReplaced": return ja ? `「${blockName(item.before, locale)}」を「${blockName(item.after, locale)}」に替えた` : `replaced “${blockName(item.before, locale)}” with “${blockName(item.after, locale)}”`;
|
|
1396
|
+
case "wrapped": return ja ? `「${blockName(item.opcode, locale)}」で包んだ` : `wrapped in “${blockName(item.opcode, locale)}”`;
|
|
1397
|
+
case "branchAdded": return ja ? `分岐「${blockName(item.opcode, locale)}」を追加` : `added “${blockName(item.opcode, locale)}”`;
|
|
1398
|
+
case "valueChanged": return ja ? `「${blockName(item.opcode, locale)}」の ${item.name} を変更` : `changed ${item.name} of “${blockName(item.opcode, locale)}”`;
|
|
1399
|
+
case "blocksAdded": return ja ? `ブロックを ${item.count} 個追加` : `added ${item.count} ${item.count === 1 ? "block" : "blocks"}`;
|
|
1400
|
+
case "blocksRemoved": return ja ? `ブロックを ${item.count} 個削除` : `removed ${item.count} ${item.count === 1 ? "block" : "blocks"}`;
|
|
1401
|
+
case "reordered": return ja ? "つなぎ方だけを変更" : "only reconnected";
|
|
1402
|
+
case "moved": return ja ? "位置だけを変更" : "only moved";
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
/** The colours of the previews, said once at the top of a review. */
|
|
1406
|
+
var legend = (locale) => locale.startsWith("ja") ? [
|
|
1407
|
+
["added", "緑の縁: 追加したブロック"],
|
|
1408
|
+
["removed", "赤の縁: 削除したブロック"],
|
|
1409
|
+
["updated", "紫の縁: 中身を変えたブロック"],
|
|
1410
|
+
["part", "オレンジの枠: 値を変えた欄"]
|
|
1411
|
+
] : [
|
|
1412
|
+
["added", "Green outline: added block"],
|
|
1413
|
+
["removed", "Red outline: removed block"],
|
|
1414
|
+
["updated", "Purple outline: block with changed contents"],
|
|
1415
|
+
["part", "Orange frame: changed value"]
|
|
1416
|
+
];
|
|
980
1417
|
// src/project-source-review.tsx
|
|
981
1418
|
init_objectSpread2();
|
|
982
1419
|
var ja = {
|
|
@@ -994,6 +1431,14 @@ var ja = {
|
|
|
994
1431
|
added: "追加",
|
|
995
1432
|
removed: "削除",
|
|
996
1433
|
reorganized: "再編",
|
|
1434
|
+
moved: "位置だけ",
|
|
1435
|
+
reordered: "並べ替え",
|
|
1436
|
+
stage: "ステージ",
|
|
1437
|
+
otherSettings: "そのほかの設定",
|
|
1438
|
+
legend: "色の見方",
|
|
1439
|
+
targetAdded: (name, stage) => stage ? "ステージを追加" : `スプライト『${name}』を追加`,
|
|
1440
|
+
targetRemoved: (name, stage) => stage ? "ステージを削除" : `スプライト『${name}』を削除`,
|
|
1441
|
+
assetOwner: (owner, kind, name) => `${owner} の${kind === "sound" ? "音" : kind === "backdrop" ? "背景" : "コスチューム"}『${name}』`,
|
|
997
1442
|
absent: "この版にはこのコードがありません",
|
|
998
1443
|
loading: "コードを描画中…",
|
|
999
1444
|
unavailable: "このコードを描画できません。",
|
|
@@ -1007,7 +1452,11 @@ var ja = {
|
|
|
1007
1452
|
script: "コード",
|
|
1008
1453
|
noChanges: "作品に内容の変更はありません。",
|
|
1009
1454
|
comparison: "作品の変更",
|
|
1010
|
-
unreadable: "作品データとして読み込めないため、テキストの差分を表示します。"
|
|
1455
|
+
unreadable: "作品データとして読み込めないため、テキストの差分を表示します。",
|
|
1456
|
+
locate: "編集画面で強調",
|
|
1457
|
+
locating: "編集画面でブロックを検索中…",
|
|
1458
|
+
located: "編集画面で強調しました。",
|
|
1459
|
+
missingLocation: "編集画面に該当する版またはブロックがありません。"
|
|
1011
1460
|
};
|
|
1012
1461
|
var en = {
|
|
1013
1462
|
review: "Change review",
|
|
@@ -1024,6 +1473,14 @@ var en = {
|
|
|
1024
1473
|
added: "Added",
|
|
1025
1474
|
removed: "Removed",
|
|
1026
1475
|
reorganized: "Reorganized",
|
|
1476
|
+
moved: "Moved only",
|
|
1477
|
+
reordered: "Reconnected",
|
|
1478
|
+
stage: "Stage",
|
|
1479
|
+
otherSettings: "Other settings",
|
|
1480
|
+
legend: "Colours",
|
|
1481
|
+
targetAdded: (name, stage) => stage ? "Added the stage" : `Added the sprite “${name}”`,
|
|
1482
|
+
targetRemoved: (name, stage) => stage ? "Removed the stage" : `Removed the sprite “${name}”`,
|
|
1483
|
+
assetOwner: (owner, kind, name) => `${kind === "sound" ? "Sound" : kind === "backdrop" ? "Backdrop" : "Costume"} “${name}” of ${owner}`,
|
|
1027
1484
|
absent: "No code in this version",
|
|
1028
1485
|
loading: "Rendering code…",
|
|
1029
1486
|
unavailable: "This code could not be rendered.",
|
|
@@ -1037,7 +1494,11 @@ var en = {
|
|
|
1037
1494
|
script: "Code",
|
|
1038
1495
|
noChanges: "No changes to the project contents.",
|
|
1039
1496
|
comparison: "Project changes",
|
|
1040
|
-
unreadable: "This file could not be read as project data, so its text diff is shown."
|
|
1497
|
+
unreadable: "This file could not be read as project data, so its text diff is shown.",
|
|
1498
|
+
locate: "Highlight in Editor",
|
|
1499
|
+
locating: "Finding the block in the Editor…",
|
|
1500
|
+
located: "Highlighted in the Editor.",
|
|
1501
|
+
missingLocation: "This version or block is unavailable in the Editor."
|
|
1041
1502
|
};
|
|
1042
1503
|
var properties = /* @__PURE__ */ new Map([
|
|
1043
1504
|
["variables", ["変数", "Variables"]],
|
|
@@ -1058,27 +1519,68 @@ var properties = /* @__PURE__ */ new Map([
|
|
|
1058
1519
|
function scriptTitle(side, labels) {
|
|
1059
1520
|
const block = side.target.blocks[side.id];
|
|
1060
1521
|
if (!isRecord(block)) return labels.script;
|
|
1061
|
-
if (block.opcode === "event_whenflagclicked") return labels.flag;
|
|
1062
|
-
if (block.opcode === "event_whenthisspriteclicked") return labels.click;
|
|
1063
|
-
if (block.opcode === "event_whenkeypressed") return labels.key;
|
|
1064
1522
|
if (block.opcode === "event_whenbroadcastreceived") {
|
|
1065
1523
|
const field = isRecord(block.fields) ? block.fields.BROADCAST_OPTION : void 0;
|
|
1066
1524
|
const message = Array.isArray(field) && typeof field[0] === "string" ? field[0] : "";
|
|
1067
1525
|
if (message) return labels === ja ? `「${message}」${labels.broadcast}` : `“${message}” ${labels.broadcast}`;
|
|
1068
1526
|
}
|
|
1069
|
-
return typeof block.opcode === "string"
|
|
1527
|
+
return typeof block.opcode === "string" && hatName(block.opcode, labels === ja ? "ja" : "en") || labels.script;
|
|
1528
|
+
}
|
|
1529
|
+
var sideKey = (side) => JSON.stringify([
|
|
1530
|
+
side.target.isStage,
|
|
1531
|
+
side.target.name,
|
|
1532
|
+
side.id
|
|
1533
|
+
]);
|
|
1534
|
+
/** Highlights the after version of a script in the Editor, one request per comparison, and cancels it on unmount. */
|
|
1535
|
+
function useBlockLocation(comparison, locateBlock) {
|
|
1536
|
+
const request = useRef();
|
|
1537
|
+
const [location, setLocation] = useState();
|
|
1538
|
+
useEffect(() => () => {
|
|
1539
|
+
var _request$current;
|
|
1540
|
+
return (_request$current = request.current) === null || _request$current === void 0 ? void 0 : _request$current.abort();
|
|
1541
|
+
}, [comparison, locateBlock]);
|
|
1542
|
+
const locate = async (side) => {
|
|
1543
|
+
var _request$current2;
|
|
1544
|
+
if (!locateBlock) return;
|
|
1545
|
+
(_request$current2 = request.current) === null || _request$current2 === void 0 || _request$current2.abort();
|
|
1546
|
+
const controller = new AbortController();
|
|
1547
|
+
request.current = controller;
|
|
1548
|
+
const selected = {
|
|
1549
|
+
comparison,
|
|
1550
|
+
key: sideKey(side),
|
|
1551
|
+
locator: locateBlock
|
|
1552
|
+
};
|
|
1553
|
+
setLocation(_objectSpread2(_objectSpread2({}, selected), {}, { status: "locating" }));
|
|
1554
|
+
let found = false;
|
|
1555
|
+
try {
|
|
1556
|
+
found = await locateBlock({
|
|
1557
|
+
target: side.target,
|
|
1558
|
+
id: side.id,
|
|
1559
|
+
version: "after",
|
|
1560
|
+
parts: [],
|
|
1561
|
+
signal: controller.signal
|
|
1562
|
+
});
|
|
1563
|
+
} catch (_unused) {}
|
|
1564
|
+
if (!controller.signal.aborted) setLocation(_objectSpread2(_objectSpread2({}, selected), {}, { status: found ? "located" : "missingLocation" }));
|
|
1565
|
+
};
|
|
1566
|
+
return {
|
|
1567
|
+
locate: locateBlock && ((side) => void locate(side)),
|
|
1568
|
+
status: (side) => (location === null || location === void 0 ? void 0 : location.comparison) === comparison && location.locator === locateBlock && location.key === sideKey(side) ? location.status : void 0
|
|
1569
|
+
};
|
|
1070
1570
|
}
|
|
1071
|
-
function ScriptComparison({ script, labels, reviewed = false, setReviewed, renderBlock, loadAsset }) {
|
|
1571
|
+
function ScriptComparison({ script, labels, reviewed = false, setReviewed, renderBlock, loadAsset, location }) {
|
|
1072
1572
|
const [open, setOpen] = useState(false);
|
|
1073
1573
|
const { sync, toggle } = usePreviewSync(labels === ja ? "ja" : "en");
|
|
1074
|
-
const status =
|
|
1574
|
+
const status = script.kind;
|
|
1575
|
+
const locale = labels === ja ? "ja" : "en";
|
|
1576
|
+
const summary = script.summary.map((item) => summaryPhrase(item, locale)).join(labels === ja ? "、" : ", ");
|
|
1075
1577
|
const beforeTitle = script.before[0] && scriptTitle(script.before[0], labels);
|
|
1076
1578
|
const afterTitle = script.after[0] && scriptTitle(script.after[0], labels);
|
|
1077
1579
|
const title = beforeTitle && afterTitle && beforeTitle !== afterTitle ? beforeTitle + " → " + afterTitle : afterTitle !== null && afterTitle !== void 0 ? afterTitle : beforeTitle;
|
|
1078
1580
|
return /* @__PURE__ */ React.createElement("details", {
|
|
1079
1581
|
className: "twgit-review-script",
|
|
1080
1582
|
onToggle: (event) => setOpen(event.currentTarget.open)
|
|
1081
|
-
}, /* @__PURE__ */ React.createElement("summary", null, /* @__PURE__ */ React.createElement("span", { className: "twgit-review-status" }, labels[status]), /* @__PURE__ */ React.createElement("strong", null, title), status === "reorganized" && /* @__PURE__ */ React.createElement("small", null, script.before.length, " → ", script.after.length), reviewed && /* @__PURE__ */ React.createElement("small", null, labels.reviewed)), open && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "twgit-block-diff-sides" }, ["before", "after"].map((version) => /* @__PURE__ */ React.createElement("div", { key: version }, script[version].length ? script[version].map((side, index, sides) => /* @__PURE__ */ React.createElement(BlockPreview, {
|
|
1583
|
+
}, /* @__PURE__ */ React.createElement("summary", null, /* @__PURE__ */ React.createElement("span", { className: "twgit-review-status" }, labels[status]), /* @__PURE__ */ React.createElement("strong", null, title), status === "reorganized" && /* @__PURE__ */ React.createElement("small", null, script.before.length, " → ", script.after.length), summary && /* @__PURE__ */ React.createElement("small", { className: "twgit-review-summary" }, summary), reviewed && /* @__PURE__ */ React.createElement("small", null, labels.reviewed)), open && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "twgit-block-diff-sides" }, ["before", "after"].map((version) => /* @__PURE__ */ React.createElement("div", { key: version }, script[version].length ? script[version].map((side, index, sides) => /* @__PURE__ */ React.createElement(BlockPreview, {
|
|
1082
1584
|
key: side.id,
|
|
1083
1585
|
side,
|
|
1084
1586
|
title: sides.length > 1 ? `${labels[version]} ${index + 1}` : labels[version],
|
|
@@ -1088,7 +1590,9 @@ function ScriptComparison({ script, labels, reviewed = false, setReviewed, rende
|
|
|
1088
1590
|
labels,
|
|
1089
1591
|
version,
|
|
1090
1592
|
loadAsset,
|
|
1091
|
-
sync
|
|
1593
|
+
sync,
|
|
1594
|
+
onLocate: version === "after" && (location === null || location === void 0 ? void 0 : location.locate) ? () => location.locate(side) : void 0,
|
|
1595
|
+
locationStatus: version === "after" ? location === null || location === void 0 ? void 0 : location.status(side) : void 0
|
|
1092
1596
|
})) : /* @__PURE__ */ React.createElement(BlockPreview, {
|
|
1093
1597
|
title: labels[version],
|
|
1094
1598
|
renderBlock,
|
|
@@ -1101,10 +1605,15 @@ function ScriptComparison({ script, labels, reviewed = false, setReviewed, rende
|
|
|
1101
1605
|
}), " ", labels.reviewed)));
|
|
1102
1606
|
}
|
|
1103
1607
|
function propertyNames(keys, labels) {
|
|
1104
|
-
|
|
1608
|
+
const locale = labels === ja ? "ja" : "en";
|
|
1609
|
+
const named = /* @__PURE__ */ new Set(), other = [];
|
|
1610
|
+
for (const key of keys) {
|
|
1105
1611
|
var _properties$get, _properties$get2;
|
|
1106
|
-
|
|
1107
|
-
|
|
1612
|
+
const label = (_properties$get = (_properties$get2 = properties.get(key)) === null || _properties$get2 === void 0 ? void 0 : _properties$get2[labels === ja ? 0 : 1]) !== null && _properties$get !== void 0 ? _properties$get : projectPropertyLabel(key, locale);
|
|
1613
|
+
if (label === key) other.push(key);
|
|
1614
|
+
else named.add(label);
|
|
1615
|
+
}
|
|
1616
|
+
return /* @__PURE__ */ React.createElement("span", { title: keys.join(", ") }, [...named, ...other.length ? [labels.otherSettings] : []].join(" · "));
|
|
1108
1617
|
}
|
|
1109
1618
|
/**
|
|
1110
1619
|
* The current costume (the backdrop for the stage) of each version of a target that has one. A changed costume shows
|
|
@@ -1132,7 +1641,8 @@ function TargetThumbnails({ target, labels, loadAsset }) {
|
|
|
1132
1641
|
}));
|
|
1133
1642
|
}
|
|
1134
1643
|
/** Lists the changed stages and sprites of one project file, each with its code comparisons. */
|
|
1135
|
-
function ComparisonTargets({ comparison, labels, renderBlock, loadAsset, review }) {
|
|
1644
|
+
function ComparisonTargets({ comparison, labels, renderBlock, loadAsset, locateBlock, review }) {
|
|
1645
|
+
const location = useBlockLocation(comparison, locateBlock);
|
|
1136
1646
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, comparison.properties.length > 0 && /* @__PURE__ */ React.createElement("p", null, labels.properties, " · ", propertyNames(comparison.properties, labels)), !comparison.targets.length && !comparison.properties.length && /* @__PURE__ */ React.createElement("p", null, labels.noChanges), comparison.targets.map((target) => /* @__PURE__ */ React.createElement("section", {
|
|
1137
1647
|
className: "twgit-review-target",
|
|
1138
1648
|
key: JSON.stringify([target.isStage, target.name])
|
|
@@ -1140,7 +1650,7 @@ function ComparisonTargets({ comparison, labels, renderBlock, loadAsset, review
|
|
|
1140
1650
|
target,
|
|
1141
1651
|
labels,
|
|
1142
1652
|
loadAsset
|
|
1143
|
-
}), target.name, target.scripts.length > 0 && /* @__PURE__ */ React.createElement("small", null, labels.scriptCount(target.scripts.length))), target.properties.length > 0 && /* @__PURE__ */ React.createElement("p", null, labels.properties, " · ", propertyNames(target.properties, labels)), target.scripts.map((script) => {
|
|
1653
|
+
}), target.isStage ? labels.stage : target.name, target.scripts.length > 0 && /* @__PURE__ */ React.createElement("small", null, labels.scriptCount(target.scripts.length))), target.status !== "updated" && /* @__PURE__ */ React.createElement("p", { className: "twgit-review-target-status" }, (target.status === "added" ? labels.targetAdded : labels.targetRemoved)(target.name, target.isStage)), target.status === "updated" && target.properties.length > 0 && /* @__PURE__ */ React.createElement("p", null, labels.properties, " · ", propertyNames(target.properties, labels)), target.scripts.map((script) => {
|
|
1144
1654
|
const key = JSON.stringify([
|
|
1145
1655
|
review === null || review === void 0 ? void 0 : review.file,
|
|
1146
1656
|
target.isStage,
|
|
@@ -1153,21 +1663,70 @@ function ComparisonTargets({ comparison, labels, renderBlock, loadAsset, review
|
|
|
1153
1663
|
labels,
|
|
1154
1664
|
renderBlock,
|
|
1155
1665
|
loadAsset,
|
|
1666
|
+
location,
|
|
1156
1667
|
reviewed: review === null || review === void 0 ? void 0 : review.keys.has(key),
|
|
1157
1668
|
setReviewed: review && ((value) => review.set(key, value))
|
|
1158
1669
|
});
|
|
1159
1670
|
}))));
|
|
1160
1671
|
}
|
|
1672
|
+
function Legend({ labels }) {
|
|
1673
|
+
return /* @__PURE__ */ React.createElement("p", {
|
|
1674
|
+
className: "twgit-review-legend",
|
|
1675
|
+
"aria-label": labels.legend
|
|
1676
|
+
}, legend(labels === ja ? "ja" : "en").map(([kind, text]) => /* @__PURE__ */ React.createElement("span", {
|
|
1677
|
+
key: kind,
|
|
1678
|
+
"data-legend": kind
|
|
1679
|
+
}, text)));
|
|
1680
|
+
}
|
|
1681
|
+
/** Finds who uses an asset file of the review: the costume or sound whose file name it is, in the project beside it. */
|
|
1682
|
+
function assetOwner(path, status, entries) {
|
|
1683
|
+
const parts = path.split("/");
|
|
1684
|
+
const name = parts.pop();
|
|
1685
|
+
const folder = parts.slice(0, -1).join("/");
|
|
1686
|
+
const version = status === "removed" ? "before" : "after";
|
|
1687
|
+
for (const { file, comparison } of entries) {
|
|
1688
|
+
if (!comparison || !("patch" in file) || file.path.split("/").slice(0, -1).join("/") !== folder) continue;
|
|
1689
|
+
for (const target of comparison.targets) {
|
|
1690
|
+
const owner = target[version];
|
|
1691
|
+
if (!owner) continue;
|
|
1692
|
+
for (const kind of ["costumes", "sounds"]) {
|
|
1693
|
+
const list = owner[kind];
|
|
1694
|
+
if (!Array.isArray(list)) continue;
|
|
1695
|
+
const entry = list.find((item) => isRecord(item) && assetFileName(item) === name);
|
|
1696
|
+
if (isRecord(entry)) return {
|
|
1697
|
+
target,
|
|
1698
|
+
version,
|
|
1699
|
+
md5ext: name,
|
|
1700
|
+
loadAsset: file.loadAsset,
|
|
1701
|
+
kind: kind === "sounds" ? "sound" : target.isStage ? "backdrop" : "costume",
|
|
1702
|
+
name: typeof entry.name === "string" ? entry.name : name
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
return null;
|
|
1708
|
+
}
|
|
1709
|
+
function RelatedFile({ file, entries, labels }) {
|
|
1710
|
+
var _owner$version;
|
|
1711
|
+
const owner = assetOwner(file.path, file.status, entries);
|
|
1712
|
+
const image = useAssetImage(owner && owner.kind !== "sound" ? owner.md5ext : void 0, (_owner$version = owner === null || owner === void 0 ? void 0 : owner.version) !== null && _owner$version !== void 0 ? _owner$version : "after", owner === null || owner === void 0 ? void 0 : owner.loadAsset);
|
|
1713
|
+
if (!owner) return /* @__PURE__ */ React.createElement("p", null, labels.related, " · ", labels[file.status]);
|
|
1714
|
+
const ownerName = owner.target.isStage ? labels.stage : owner.target.name;
|
|
1715
|
+
return /* @__PURE__ */ React.createElement("p", { className: "twgit-review-asset" }, image && /* @__PURE__ */ React.createElement("img", {
|
|
1716
|
+
src: image,
|
|
1717
|
+
alt: ""
|
|
1718
|
+
}), /* @__PURE__ */ React.createElement("span", null, labels.assetOwner(ownerName, owner.kind, owner.name), " · ", labels[file.status]));
|
|
1719
|
+
}
|
|
1161
1720
|
var countScripts = (comparison) => comparison.targets.reduce((count, target) => count + target.scripts.length, 0);
|
|
1162
1721
|
/** Compares two versions of a project.source.json by stage, sprite and code, as the pull request review does. */
|
|
1163
|
-
function ProjectSourceComparison({ before, after, renderBlock, locale = "en", fallback, loadAsset, target }) {
|
|
1722
|
+
function ProjectSourceComparison({ before, after, renderBlock, locale = "en", fallback, loadAsset, locateBlock, target }) {
|
|
1164
1723
|
const labels = locale.startsWith("ja") ? ja : en;
|
|
1165
1724
|
const only = target && JSON.stringify([target.isStage, target.isStage || target.name]);
|
|
1166
1725
|
const comparison = useMemo(() => {
|
|
1167
1726
|
let result;
|
|
1168
1727
|
try {
|
|
1169
1728
|
result = compareProjectForReview(parseProjectSource(before), parseProjectSource(after));
|
|
1170
|
-
} catch (
|
|
1729
|
+
} catch (_unused2) {
|
|
1171
1730
|
return null;
|
|
1172
1731
|
}
|
|
1173
1732
|
if (!only) return result;
|
|
@@ -1187,11 +1746,12 @@ function ProjectSourceComparison({ before, after, renderBlock, locale = "en", fa
|
|
|
1187
1746
|
return /* @__PURE__ */ React.createElement("section", {
|
|
1188
1747
|
className: "twgit-block-diff twgit-review twgit-review-comparison",
|
|
1189
1748
|
"aria-label": labels.comparison
|
|
1190
|
-
}, !only && /* @__PURE__ */ React.createElement("header", { className: "twgit-review-overview" }, /* @__PURE__ */ React.createElement("dl", null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.targets), /* @__PURE__ */ React.createElement("dd", null, comparison.targets.length)), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.scripts), /* @__PURE__ */ React.createElement("dd", null, countScripts(comparison))))), /* @__PURE__ */ React.createElement(ComparisonTargets, {
|
|
1749
|
+
}, !only && /* @__PURE__ */ React.createElement(Legend, { labels }), !only && /* @__PURE__ */ React.createElement("header", { className: "twgit-review-overview" }, /* @__PURE__ */ React.createElement("dl", null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.targets), /* @__PURE__ */ React.createElement("dd", null, comparison.targets.length)), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.scripts), /* @__PURE__ */ React.createElement("dd", null, countScripts(comparison))))), /* @__PURE__ */ React.createElement(ComparisonTargets, {
|
|
1191
1750
|
comparison,
|
|
1192
1751
|
labels,
|
|
1193
1752
|
renderBlock,
|
|
1194
|
-
loadAsset
|
|
1753
|
+
loadAsset,
|
|
1754
|
+
locateBlock
|
|
1195
1755
|
}));
|
|
1196
1756
|
}
|
|
1197
1757
|
function ProjectSourceReview({ title, description, verification, files, renderBlock, locale = "en" }) {
|
|
@@ -1207,7 +1767,7 @@ function ProjectSourceReview({ title, description, verification, files, renderBl
|
|
|
1207
1767
|
properties: []
|
|
1208
1768
|
}
|
|
1209
1769
|
};
|
|
1210
|
-
} catch (
|
|
1770
|
+
} catch (_unused3) {
|
|
1211
1771
|
return {
|
|
1212
1772
|
file,
|
|
1213
1773
|
invalid: true
|
|
@@ -1236,14 +1796,19 @@ function ProjectSourceReview({ title, description, verification, files, renderBl
|
|
|
1236
1796
|
return /* @__PURE__ */ React.createElement("section", {
|
|
1237
1797
|
className: "twgit-block-diff twgit-review",
|
|
1238
1798
|
"aria-label": labels.review
|
|
1239
|
-
}, /* @__PURE__ */ React.createElement("header", { className: "twgit-review-overview" }, /* @__PURE__ */ React.createElement("p", null, labels.review), /* @__PURE__ */ React.createElement("h2", null, title), excerpt && /* @__PURE__ */ React.createElement("p", { className: "twgit-review-description" }, excerpt), /* @__PURE__ */ React.createElement("dl", null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.files), /* @__PURE__ */ React.createElement("dd", null, entries.length)), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.targets), /* @__PURE__ */ React.createElement("dd", null, targets)), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.scripts), /* @__PURE__ */ React.createElement("dd", null, scripts)), scripts > 0 && /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.reviewed), /* @__PURE__ */ React.createElement("dd", null, reviewed.size, " / ", scripts))), longBody && /* @__PURE__ */ React.createElement("details", { className: "twgit-review-body" }, /* @__PURE__ */ React.createElement("summary", null, labels.fullDescription), /* @__PURE__ */ React.createElement("p", { className: "twgit-review-description" }, body)), !!(verification === null || verification === void 0 ? void 0 : verification.length) && /* @__PURE__ */ React.createElement("div", { className: "twgit-review-checklist" }, /* @__PURE__ */ React.createElement("h3", null, labels.checks), /* @__PURE__ */ React.createElement("ul", null, verification.map((item, index) => /* @__PURE__ */ React.createElement("li", { key: index }, item))))), /* @__PURE__ */ React.createElement("h3", { className: "twgit-review-files-title" }, labels.files), entries.map(({ file, comparison, invalid }) => /* @__PURE__ */ React.createElement("section", {
|
|
1799
|
+
}, /* @__PURE__ */ React.createElement("header", { className: "twgit-review-overview" }, /* @__PURE__ */ React.createElement("p", null, labels.review), /* @__PURE__ */ React.createElement("h2", null, title), excerpt && /* @__PURE__ */ React.createElement("p", { className: "twgit-review-description" }, excerpt), /* @__PURE__ */ React.createElement("dl", null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.files), /* @__PURE__ */ React.createElement("dd", null, entries.length)), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.targets), /* @__PURE__ */ React.createElement("dd", null, targets)), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.scripts), /* @__PURE__ */ React.createElement("dd", null, scripts)), scripts > 0 && /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", null, labels.reviewed), /* @__PURE__ */ React.createElement("dd", null, reviewed.size, " / ", scripts))), longBody && /* @__PURE__ */ React.createElement("details", { className: "twgit-review-body" }, /* @__PURE__ */ React.createElement("summary", null, labels.fullDescription), /* @__PURE__ */ React.createElement("p", { className: "twgit-review-description" }, body)), !!(verification === null || verification === void 0 ? void 0 : verification.length) && /* @__PURE__ */ React.createElement("div", { className: "twgit-review-checklist" }, /* @__PURE__ */ React.createElement("h3", null, labels.checks), /* @__PURE__ */ React.createElement("ul", null, verification.map((item, index) => /* @__PURE__ */ React.createElement("li", { key: index }, item))))), /* @__PURE__ */ React.createElement(Legend, { labels }), /* @__PURE__ */ React.createElement("h3", { className: "twgit-review-files-title" }, labels.files), entries.map(({ file, comparison, invalid }) => /* @__PURE__ */ React.createElement("section", {
|
|
1240
1800
|
key: file.path,
|
|
1241
1801
|
className: "twgit-review-file"
|
|
1242
|
-
}, /* @__PURE__ */ React.createElement("header", null, /* @__PURE__ */ React.createElement("h4", null, file.previousPath ? file.previousPath + " → " + file.path : file.path), file.summary && /* @__PURE__ */ React.createElement("p", null, file.summary)), "status" in file && /* @__PURE__ */ React.createElement(
|
|
1802
|
+
}, /* @__PURE__ */ React.createElement("header", null, /* @__PURE__ */ React.createElement("h4", null, file.previousPath ? file.previousPath + " → " + file.path : file.path), file.summary && /* @__PURE__ */ React.createElement("p", null, file.summary)), "status" in file && /* @__PURE__ */ React.createElement(RelatedFile, {
|
|
1803
|
+
file,
|
|
1804
|
+
entries,
|
|
1805
|
+
labels
|
|
1806
|
+
}), (invalid || file.unavailable) && /* @__PURE__ */ React.createElement("p", { role: "alert" }, labels.invalid), comparison && /* @__PURE__ */ React.createElement(ComparisonTargets, {
|
|
1243
1807
|
comparison,
|
|
1244
1808
|
labels,
|
|
1245
1809
|
renderBlock,
|
|
1246
1810
|
loadAsset: "loadAsset" in file ? file.loadAsset : void 0,
|
|
1811
|
+
locateBlock: "locateBlock" in file ? file.locateBlock : void 0,
|
|
1247
1812
|
review: {
|
|
1248
1813
|
file: file.path,
|
|
1249
1814
|
keys: reviewed,
|
|
@@ -1251,236 +1816,6 @@ function ProjectSourceReview({ title, description, verification, files, renderBl
|
|
|
1251
1816
|
}
|
|
1252
1817
|
}))));
|
|
1253
1818
|
}
|
|
1254
|
-
// src/project-change-model.ts
|
|
1255
|
-
init_objectSpread2();
|
|
1256
|
-
var targetDataKeys = [
|
|
1257
|
-
"variables",
|
|
1258
|
-
"lists",
|
|
1259
|
-
"broadcasts"
|
|
1260
|
-
];
|
|
1261
|
-
var nonSettingKeys = /* @__PURE__ */ new Set([
|
|
1262
|
-
"blocks",
|
|
1263
|
-
"costumes",
|
|
1264
|
-
"sounds",
|
|
1265
|
-
...targetDataKeys
|
|
1266
|
-
]);
|
|
1267
|
-
var propertyLabels = /* @__PURE__ */ new Map([
|
|
1268
|
-
["variables", ["変数", "Variables"]],
|
|
1269
|
-
["lists", ["リスト", "Lists"]],
|
|
1270
|
-
["broadcasts", ["メッセージ", "Broadcast messages"]],
|
|
1271
|
-
["costumes", ["コスチューム・背景", "Costumes and backdrops"]],
|
|
1272
|
-
["sounds", ["音", "Sounds"]],
|
|
1273
|
-
["blocks", ["コード", "Code"]],
|
|
1274
|
-
["x", ["X 座標", "X position"]],
|
|
1275
|
-
["y", ["Y 座標", "Y position"]],
|
|
1276
|
-
["size", ["大きさ", "Size"]],
|
|
1277
|
-
["direction", ["向き", "Direction"]],
|
|
1278
|
-
["visible", ["表示状態", "Visibility"]],
|
|
1279
|
-
["currentCostume", ["表示するコスチューム", "Selected costume"]],
|
|
1280
|
-
["layerOrder", ["重なり順", "Layer order"]],
|
|
1281
|
-
["volume", ["音量", "Volume"]],
|
|
1282
|
-
["comments", ["コメント", "Comments"]],
|
|
1283
|
-
["draggable", ["ドラッグ可否", "Draggable"]],
|
|
1284
|
-
["rotationStyle", ["回転方法", "Rotation style"]],
|
|
1285
|
-
["tempo", ["テンポ", "Tempo"]],
|
|
1286
|
-
["videoTransparency", ["ビデオの透明度", "Video transparency"]],
|
|
1287
|
-
["videoState", ["ビデオの状態", "Video state"]],
|
|
1288
|
-
["textToSpeechLanguage", ["音声合成の言語", "Text to speech language"]],
|
|
1289
|
-
["monitors", ["モニター", "Monitors"]],
|
|
1290
|
-
["extensions", ["拡張機能", "Extensions"]],
|
|
1291
|
-
["meta", ["作品の情報", "Project metadata"]]
|
|
1292
|
-
]);
|
|
1293
|
-
/** The Japanese or English name of a project or target property key; unknown keys are returned as they are. */
|
|
1294
|
-
function projectPropertyLabel(key, locale = "en") {
|
|
1295
|
-
var _propertyLabels$get, _propertyLabels$get2;
|
|
1296
|
-
return (_propertyLabels$get = (_propertyLabels$get2 = propertyLabels.get(key)) === null || _propertyLabels$get2 === void 0 ? void 0 : _propertyLabels$get2[locale.startsWith("ja") ? 0 : 1]) !== null && _propertyLabels$get !== void 0 ? _propertyLabels$get : key;
|
|
1297
|
-
}
|
|
1298
|
-
/** The asset file name of a costume or sound entry: `md5ext`, or `assetId.dataFormat`; `''` when it has neither. */
|
|
1299
|
-
function assetFileName(entry) {
|
|
1300
|
-
if (typeof entry.md5ext === "string") return entry.md5ext;
|
|
1301
|
-
return typeof entry.assetId === "string" && typeof entry.dataFormat === "string" ? entry.assetId + "." + entry.dataFormat : "";
|
|
1302
|
-
}
|
|
1303
|
-
function joinPath(...parts) {
|
|
1304
|
-
return parts.flatMap((part) => part.split("/")).filter((part) => part !== "" && part !== ".").join("/");
|
|
1305
|
-
}
|
|
1306
|
-
function statusOf(before, after) {
|
|
1307
|
-
return before === void 0 ? "added" : after === void 0 ? "removed" : "updated";
|
|
1308
|
-
}
|
|
1309
|
-
function entriesOf(target, kind) {
|
|
1310
|
-
const list = target === null || target === void 0 ? void 0 : target[kind];
|
|
1311
|
-
return Array.isArray(list) ? list.filter(isRecord) : [];
|
|
1312
|
-
}
|
|
1313
|
-
function nameOf(entry) {
|
|
1314
|
-
return typeof entry.name === "string" ? entry.name : "";
|
|
1315
|
-
}
|
|
1316
|
-
/** Pairs the entries of two versions by name (repeated names pair in order): after's order first, then removed ones. */
|
|
1317
|
-
function pairEntries(before, after) {
|
|
1318
|
-
var _remaining$get;
|
|
1319
|
-
const remaining = /* @__PURE__ */ new Map();
|
|
1320
|
-
for (const entry of before) {
|
|
1321
|
-
const queue = remaining.get(nameOf(entry));
|
|
1322
|
-
if (queue) queue.push(entry);
|
|
1323
|
-
else remaining.set(nameOf(entry), [entry]);
|
|
1324
|
-
}
|
|
1325
|
-
const pairs = [];
|
|
1326
|
-
for (const entry of after) pairs.push({
|
|
1327
|
-
name: nameOf(entry),
|
|
1328
|
-
before: (_remaining$get = remaining.get(nameOf(entry))) === null || _remaining$get === void 0 ? void 0 : _remaining$get.shift(),
|
|
1329
|
-
after: entry
|
|
1330
|
-
});
|
|
1331
|
-
for (const entry of before) {
|
|
1332
|
-
const queue = remaining.get(nameOf(entry));
|
|
1333
|
-
if ((queue === null || queue === void 0 ? void 0 : queue[0]) === entry) pairs.push({
|
|
1334
|
-
name: nameOf(entry),
|
|
1335
|
-
before: queue.shift()
|
|
1336
|
-
});
|
|
1337
|
-
}
|
|
1338
|
-
return pairs;
|
|
1339
|
-
}
|
|
1340
|
-
function changedKeys(before, after, skip) {
|
|
1341
|
-
return [.../* @__PURE__ */ new Set([...Object.keys(after), ...Object.keys(before)])].filter((key) => !skip(key) && !equal(before[key], after[key]));
|
|
1342
|
-
}
|
|
1343
|
-
/** Arranges the changed files of one project folder by stage, sprite and element. Pure; reads nothing. */
|
|
1344
|
-
function organizeProjectChanges(input) {
|
|
1345
|
-
const { folder, files, assetsDirectory } = input;
|
|
1346
|
-
const normalize = (project) => project === null ? { targets: [] } : _objectSpread2(_objectSpread2({}, project), {}, { targets: project.targets.map((target) => {
|
|
1347
|
-
var _target$blocks;
|
|
1348
|
-
return _objectSpread2(_objectSpread2({}, target), {}, { blocks: (_target$blocks = target.blocks) !== null && _target$blocks !== void 0 ? _target$blocks : {} });
|
|
1349
|
-
}) });
|
|
1350
|
-
const before = normalize(input.before), after = normalize(input.after);
|
|
1351
|
-
const projectPath = joinPath(folder, "project.source.json");
|
|
1352
|
-
const projectFiles = files.filter((file) => file.path === projectPath);
|
|
1353
|
-
const explained = /* @__PURE__ */ new Set();
|
|
1354
|
-
let projectUsed = false;
|
|
1355
|
-
const useProject = () => {
|
|
1356
|
-
projectUsed = true;
|
|
1357
|
-
return [...projectFiles];
|
|
1358
|
-
};
|
|
1359
|
-
const filesAt = (paths) => {
|
|
1360
|
-
const wanted = new Set(paths.filter((path) => path !== void 0));
|
|
1361
|
-
const found = files.filter((file) => wanted.has(file.path));
|
|
1362
|
-
for (const file of found) explained.add(file.path);
|
|
1363
|
-
return found;
|
|
1364
|
-
};
|
|
1365
|
-
const review = compareProjectForReview(before, after);
|
|
1366
|
-
const scripts = new Map(review.targets.map((target) => {
|
|
1367
|
-
var _target$after;
|
|
1368
|
-
return [targetKey((_target$after = target.after) !== null && _target$after !== void 0 ? _target$after : target.before), target.scripts.length];
|
|
1369
|
-
}));
|
|
1370
|
-
const oldTargets = new Map(before.targets.map((target) => [targetKey(target), target]));
|
|
1371
|
-
const newTargets = new Map(after.targets.map((target) => [targetKey(target), target]));
|
|
1372
|
-
const keys = [...new Set([...after.targets, ...before.targets].map(targetKey))];
|
|
1373
|
-
keys.sort((a, b) => Number(b === "stage") - Number(a === "stage"));
|
|
1374
|
-
const targets = [];
|
|
1375
|
-
for (const key of keys) {
|
|
1376
|
-
var _scripts$get;
|
|
1377
|
-
const a = oldTargets.get(key), b = newTargets.get(key);
|
|
1378
|
-
const status = statusOf(a, b);
|
|
1379
|
-
const elements = [];
|
|
1380
|
-
const count = (_scripts$get = scripts.get(key)) !== null && _scripts$get !== void 0 ? _scripts$get : 0;
|
|
1381
|
-
if (count) elements.push({
|
|
1382
|
-
key: JSON.stringify([
|
|
1383
|
-
key,
|
|
1384
|
-
"code",
|
|
1385
|
-
""
|
|
1386
|
-
]),
|
|
1387
|
-
kind: "code",
|
|
1388
|
-
status,
|
|
1389
|
-
scripts: count,
|
|
1390
|
-
files: useProject()
|
|
1391
|
-
});
|
|
1392
|
-
for (const kind of ["costumes", "sounds"]) {
|
|
1393
|
-
const seen = /* @__PURE__ */ new Map();
|
|
1394
|
-
for (const pair of pairEntries(entriesOf(a, kind), entriesOf(b, kind))) {
|
|
1395
|
-
var _seen$get;
|
|
1396
|
-
const md5ext = {
|
|
1397
|
-
before: pair.before && assetFileName(pair.before) || void 0,
|
|
1398
|
-
after: pair.after && assetFileName(pair.after) || void 0
|
|
1399
|
-
};
|
|
1400
|
-
const differs = !equal(pair.before, pair.after);
|
|
1401
|
-
const assets = filesAt([md5ext.before && joinPath(folder, assetsDirectory.before, md5ext.before), md5ext.after && joinPath(folder, assetsDirectory.after, md5ext.after)]);
|
|
1402
|
-
if (!differs && !assets.length) continue;
|
|
1403
|
-
const repeat = (_seen$get = seen.get(pair.name)) !== null && _seen$get !== void 0 ? _seen$get : 0;
|
|
1404
|
-
seen.set(pair.name, repeat + 1);
|
|
1405
|
-
elements.push({
|
|
1406
|
-
key: JSON.stringify(repeat ? [
|
|
1407
|
-
key,
|
|
1408
|
-
kind,
|
|
1409
|
-
pair.name,
|
|
1410
|
-
repeat
|
|
1411
|
-
] : [
|
|
1412
|
-
key,
|
|
1413
|
-
kind,
|
|
1414
|
-
pair.name
|
|
1415
|
-
]),
|
|
1416
|
-
kind,
|
|
1417
|
-
status: statusOf(pair.before, pair.after),
|
|
1418
|
-
name: pair.name,
|
|
1419
|
-
before: pair.before,
|
|
1420
|
-
after: pair.after,
|
|
1421
|
-
md5ext,
|
|
1422
|
-
files: [...differs ? useProject() : [], ...assets]
|
|
1423
|
-
});
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
if (a && b) {
|
|
1427
|
-
const oldFields = a, newFields = b;
|
|
1428
|
-
const data = changedKeys(oldFields, newFields, (property) => !targetDataKeys.includes(property));
|
|
1429
|
-
if (data.length) elements.push({
|
|
1430
|
-
key: JSON.stringify([
|
|
1431
|
-
key,
|
|
1432
|
-
"data",
|
|
1433
|
-
""
|
|
1434
|
-
]),
|
|
1435
|
-
kind: "data",
|
|
1436
|
-
status,
|
|
1437
|
-
properties: data,
|
|
1438
|
-
files: useProject()
|
|
1439
|
-
});
|
|
1440
|
-
const settings = changedKeys(oldFields, newFields, (property) => nonSettingKeys.has(property));
|
|
1441
|
-
if (settings.length) elements.push({
|
|
1442
|
-
key: JSON.stringify([
|
|
1443
|
-
key,
|
|
1444
|
-
"settings",
|
|
1445
|
-
""
|
|
1446
|
-
]),
|
|
1447
|
-
kind: "settings",
|
|
1448
|
-
status,
|
|
1449
|
-
properties: settings,
|
|
1450
|
-
files: useProject()
|
|
1451
|
-
});
|
|
1452
|
-
} else projectUsed = true;
|
|
1453
|
-
if (status !== "updated" || elements.length) {
|
|
1454
|
-
const { name, isStage } = b !== null && b !== void 0 ? b : a;
|
|
1455
|
-
targets.push({
|
|
1456
|
-
key,
|
|
1457
|
-
name,
|
|
1458
|
-
isStage,
|
|
1459
|
-
status,
|
|
1460
|
-
before: a,
|
|
1461
|
-
after: b,
|
|
1462
|
-
elements
|
|
1463
|
-
});
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
const project = changedKeys(before, after, (key) => key === "targets").map((property) => ({
|
|
1467
|
-
key: JSON.stringify([
|
|
1468
|
-
"project",
|
|
1469
|
-
"settings",
|
|
1470
|
-
property
|
|
1471
|
-
]),
|
|
1472
|
-
kind: "settings",
|
|
1473
|
-
status: statusOf(before[property], after[property]),
|
|
1474
|
-
properties: [property],
|
|
1475
|
-
files: useProject()
|
|
1476
|
-
}));
|
|
1477
|
-
if (projectUsed) explained.add(projectPath);
|
|
1478
|
-
return {
|
|
1479
|
-
targets,
|
|
1480
|
-
project,
|
|
1481
|
-
other: files.filter((file) => !explained.has(file.path))
|
|
1482
|
-
};
|
|
1483
|
-
}
|
|
1484
1819
|
// src/github-pull-requests.ts
|
|
1485
1820
|
init_objectSpread2();
|
|
1486
1821
|
var PullRequestError = class extends Error {
|
|
@@ -2079,4 +2414,4 @@ function createScratchBlocksDiffRenderer(options) {
|
|
|
2079
2414
|
};
|
|
2080
2415
|
};
|
|
2081
2416
|
}
|
|
2082
|
-
export {
|
|
2417
|
+
export { useCostumeImage as _, gitHubRepositoryFromOrigin as a, parseProjectSource as b, assetFileName as c, compareProjectForReview as d, BlockPreview as f, useAssetImage as g, currentCostume as h, createGitHubPullRequests as i, organizeProjectChanges as l, usePreviewSync as m, createScratchBlocksDiffLocator as n, ProjectSourceComparison as o, createPreviewSync as p, PullRequestError as r, ProjectSourceReview as s, createScratchBlocksDiffRenderer as t, projectPropertyLabel as u, compareProjectBlocks as v, readProjectSourceDiff as x, createProjectSourceDiff as y };
|