@lvce-editor/source-control-worker 1.0.0 → 1.1.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.
@@ -54,6 +54,47 @@ class VError extends Error {
54
54
  }
55
55
  }
56
56
 
57
+ class AssertionError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = 'AssertionError';
61
+ }
62
+ }
63
+ const getType = value => {
64
+ switch (typeof value) {
65
+ case 'number':
66
+ return 'number';
67
+ case 'function':
68
+ return 'function';
69
+ case 'string':
70
+ return 'string';
71
+ case 'object':
72
+ if (value === null) {
73
+ return 'null';
74
+ }
75
+ if (Array.isArray(value)) {
76
+ return 'array';
77
+ }
78
+ return 'object';
79
+ case 'boolean':
80
+ return 'boolean';
81
+ default:
82
+ return 'unknown';
83
+ }
84
+ };
85
+ const number = value => {
86
+ const type = getType(value);
87
+ if (type !== 'number') {
88
+ throw new AssertionError('expected value to be of type number');
89
+ }
90
+ };
91
+ const string = value => {
92
+ const type = getType(value);
93
+ if (type !== 'string') {
94
+ throw new AssertionError('expected value to be of type string');
95
+ }
96
+ };
97
+
57
98
  const isMessagePort = value => {
58
99
  return value && value instanceof MessagePort;
59
100
  };
@@ -379,6 +420,100 @@ const IpcChildWithModuleWorkerAndMessagePort$1 = {
379
420
  listen: listen$6,
380
421
  wrap: wrap$e
381
422
  };
423
+ const addListener = (emitter, type, callback) => {
424
+ if ('addEventListener' in emitter) {
425
+ emitter.addEventListener(type, callback);
426
+ } else {
427
+ emitter.on(type, callback);
428
+ }
429
+ };
430
+ const removeListener = (emitter, type, callback) => {
431
+ if ('removeEventListener' in emitter) {
432
+ emitter.removeEventListener(type, callback);
433
+ } else {
434
+ emitter.off(type, callback);
435
+ }
436
+ };
437
+ const getFirstEvent = (eventEmitter, eventMap) => {
438
+ const {
439
+ resolve,
440
+ promise
441
+ } = withResolvers();
442
+ const listenerMap = Object.create(null);
443
+ const cleanup = value => {
444
+ for (const event of Object.keys(eventMap)) {
445
+ removeListener(eventEmitter, event, listenerMap[event]);
446
+ }
447
+ resolve(value);
448
+ };
449
+ for (const [event, type] of Object.entries(eventMap)) {
450
+ const listener = event => {
451
+ cleanup({
452
+ type,
453
+ event
454
+ });
455
+ };
456
+ addListener(eventEmitter, event, listener);
457
+ listenerMap[event] = listener;
458
+ }
459
+ return promise;
460
+ };
461
+ const Message$1 = 3;
462
+ const create$5$1 = async ({
463
+ messagePort,
464
+ isMessagePortOpen
465
+ }) => {
466
+ if (!isMessagePort(messagePort)) {
467
+ throw new IpcError('port must be of type MessagePort');
468
+ }
469
+ if (isMessagePortOpen) {
470
+ return messagePort;
471
+ }
472
+ const eventPromise = getFirstEvent(messagePort, {
473
+ message: Message$1
474
+ });
475
+ messagePort.start();
476
+ const {
477
+ type,
478
+ event
479
+ } = await eventPromise;
480
+ if (type !== Message$1) {
481
+ throw new IpcError('Failed to wait for ipc message');
482
+ }
483
+ if (event.data !== readyMessage) {
484
+ throw new IpcError('unexpected first message');
485
+ }
486
+ return messagePort;
487
+ };
488
+ const signal$1 = messagePort => {
489
+ messagePort.start();
490
+ };
491
+ class IpcParentWithMessagePort extends Ipc {
492
+ getData = getData$2;
493
+ send(message) {
494
+ this._rawIpc.postMessage(message);
495
+ }
496
+ sendAndTransfer(message) {
497
+ const transfer = getTransferrables(message);
498
+ this._rawIpc.postMessage(message, transfer);
499
+ }
500
+ dispose() {
501
+ this._rawIpc.close();
502
+ }
503
+ onMessage(callback) {
504
+ this._rawIpc.addEventListener('message', callback);
505
+ }
506
+ onClose(callback) {}
507
+ }
508
+ const wrap$5 = messagePort => {
509
+ return new IpcParentWithMessagePort(messagePort);
510
+ };
511
+ const IpcParentWithMessagePort$1 = {
512
+ __proto__: null,
513
+ create: create$5$1,
514
+ signal: signal$1,
515
+ wrap: wrap$5
516
+ };
382
517
 
383
518
  const Two = '2.0';
384
519
  const create$4 = (method, params) => {
@@ -392,7 +527,7 @@ const callbacks = Object.create(null);
392
527
  const set$1 = (id, fn) => {
393
528
  callbacks[id] = fn;
394
529
  };
395
- const get = id => {
530
+ const get$2 = id => {
396
531
  return callbacks[id];
397
532
  };
398
533
  const remove = id => {
@@ -565,7 +700,7 @@ const warn = (...args) => {
565
700
  console.warn(...args);
566
701
  };
567
702
  const resolve = (id, response) => {
568
- const fn = get(id);
703
+ const fn = get$2(id);
569
704
  if (!fn) {
570
705
  console.log(response);
571
706
  warn(`callback ${id} may already be disposed`);
@@ -719,10 +854,10 @@ const send = (transport, method, ...params) => {
719
854
  const message = create$4(method, params);
720
855
  transport.send(message);
721
856
  };
722
- const invoke = (ipc, method, ...params) => {
857
+ const invoke$2 = (ipc, method, ...params) => {
723
858
  return invokeHelper(ipc, method, params, false);
724
859
  };
725
- const invokeAndTransfer = (ipc, method, ...params) => {
860
+ const invokeAndTransfer$1 = (ipc, method, ...params) => {
726
861
  return invokeHelper(ipc, method, params, true);
727
862
  };
728
863
 
@@ -752,10 +887,10 @@ const createRpc = ipc => {
752
887
  send(ipc, method, ...params);
753
888
  },
754
889
  invoke(method, ...params) {
755
- return invoke(ipc, method, ...params);
890
+ return invoke$2(ipc, method, ...params);
756
891
  },
757
892
  invokeAndTransfer(method, ...params) {
758
- return invokeAndTransfer(ipc, method, ...params);
893
+ return invokeAndTransfer$1(ipc, method, ...params);
759
894
  },
760
895
  async dispose() {
761
896
  await ipc?.dispose();
@@ -793,6 +928,26 @@ const listen$1 = async (module, options) => {
793
928
  const ipc = module.wrap(rawIpc);
794
929
  return ipc;
795
930
  };
931
+ const create$8 = async ({
932
+ commandMap,
933
+ messagePort,
934
+ isMessagePortOpen
935
+ }) => {
936
+ // TODO create a commandMap per rpc instance
937
+ register(commandMap);
938
+ const rawIpc = await IpcParentWithMessagePort$1.create({
939
+ messagePort,
940
+ isMessagePortOpen
941
+ });
942
+ const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
943
+ handleIpc(ipc);
944
+ const rpc = createRpc(ipc);
945
+ return rpc;
946
+ };
947
+ const MessagePortRpcParent = {
948
+ __proto__: null,
949
+ create: create$8
950
+ };
796
951
  const create = async ({
797
952
  commandMap
798
953
  }) => {
@@ -808,20 +963,358 @@ const WebWorkerRpcClient = {
808
963
  create
809
964
  };
810
965
 
811
- const terminate = () => {
812
- globalThis.close();
813
- };
814
-
815
- const commandMap = {
816
- 'SourceControl.terminate': terminate
966
+ const getPortTuple = () => {
967
+ const {
968
+ port1,
969
+ port2
970
+ } = new MessageChannel();
971
+ return {
972
+ port1,
973
+ port2
974
+ };
817
975
  };
818
976
 
819
977
  const RendererWorker = 1;
978
+ const ExtensionHostWorker = 44;
979
+ const DebugWorker = 55;
980
+ const SourceControlWorker = 66;
820
981
 
821
982
  const rpcs = Object.create(null);
822
983
  const set = (id, rpc) => {
823
984
  rpcs[id] = rpc;
824
985
  };
986
+ const get$1 = id => {
987
+ return rpcs[id];
988
+ };
989
+
990
+ const invoke$1 = (method, ...params) => {
991
+ const rpc = get$1(RendererWorker);
992
+ // @ts-ignore
993
+ return rpc.invoke(method, ...params);
994
+ };
995
+ const invokeAndTransfer = (method, ...params) => {
996
+ const rpc = get$1(RendererWorker);
997
+ // @ts-ignore
998
+ return rpc.invokeAndTransfer(method, ...params);
999
+ };
1000
+
1001
+ const sendMessagePortToExtensionHostWorker = async port => {
1002
+ const command = 'HandleMessagePort.handleMessagePort';
1003
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, DebugWorker);
1004
+ };
1005
+
1006
+ const createExtensionHostRpc = async () => {
1007
+ try {
1008
+ const {
1009
+ port1,
1010
+ port2
1011
+ } = getPortTuple();
1012
+ await sendMessagePortToExtensionHostWorker(port2);
1013
+ port1.start();
1014
+ const rpc = await MessagePortRpcParent.create({
1015
+ commandMap: {},
1016
+ messagePort: port1,
1017
+ isMessagePortOpen: false
1018
+ });
1019
+ // TODO createMessageportRpcParent should call port start
1020
+ return rpc;
1021
+ } catch (error) {
1022
+ throw new VError(error, `Failed to create extension host rpc`);
1023
+ }
1024
+ };
1025
+
1026
+ const initialize = async () => {
1027
+ const extensionHostRpc = await createExtensionHostRpc();
1028
+ set(SourceControlWorker, extensionHostRpc);
1029
+ };
1030
+
1031
+ const DirectoryExpanded = 4;
1032
+ const File = 7;
1033
+
1034
+ const getFileIcon = ({
1035
+ name
1036
+ }) => {
1037
+ return '';
1038
+ };
1039
+
1040
+ // TODO this should be in FileSystem module
1041
+ const pathBaseName = path => {
1042
+ return path.slice(path.lastIndexOf('/') + 1);
1043
+ };
1044
+
1045
+ const getDisplayItemsGroup = (group, isExpanded) => {
1046
+ const displayItems = [];
1047
+ const {
1048
+ id,
1049
+ label,
1050
+ items
1051
+ } = group;
1052
+ if (!items) {
1053
+ throw new Error('Source control group is missing an items property');
1054
+ }
1055
+ const length = items.length;
1056
+ const type = DirectoryExpanded ;
1057
+ const icon = 'ChevronDown' ;
1058
+ if (length > 0) {
1059
+ displayItems.push({
1060
+ file: '',
1061
+ label,
1062
+ detail: '',
1063
+ posInSet: 1,
1064
+ setSize: 1,
1065
+ icon,
1066
+ decorationIcon: '',
1067
+ decorationIconTitle: '',
1068
+ decorationStrikeThrough: false,
1069
+ type,
1070
+ badgeCount: length,
1071
+ groupId: id
1072
+ });
1073
+ }
1074
+ {
1075
+ for (let i = 0; i < length; i++) {
1076
+ const item = items[i];
1077
+ const {
1078
+ file,
1079
+ icon,
1080
+ iconTitle,
1081
+ strikeThrough
1082
+ } = item;
1083
+ const baseName = pathBaseName(file);
1084
+ const folderName = file.slice(0, -baseName.length - 1);
1085
+ displayItems.push({
1086
+ file,
1087
+ label: baseName,
1088
+ detail: folderName,
1089
+ posInSet: i + 1,
1090
+ setSize: length,
1091
+ icon: getFileIcon({
1092
+ name: file
1093
+ }),
1094
+ decorationIcon: icon,
1095
+ decorationIconTitle: iconTitle,
1096
+ decorationStrikeThrough: strikeThrough,
1097
+ type: File,
1098
+ badgeCount: 0,
1099
+ groupId: id
1100
+ });
1101
+ }
1102
+ }
1103
+ return displayItems;
1104
+ };
1105
+ const getDisplayItems = (allGroups, isExpanded) => {
1106
+ const displayItems = [];
1107
+ for (const group of allGroups) {
1108
+ const groupDisplayItems = getDisplayItemsGroup(group);
1109
+ displayItems.push(...groupDisplayItems);
1110
+ }
1111
+ return displayItems;
1112
+ };
1113
+
1114
+ const getFinalDeltaY = (height, itemHeight, itemsLength) => {
1115
+ const contentHeight = itemsLength * itemHeight;
1116
+ const finalDeltaY = Math.max(contentHeight - height, 0);
1117
+ return finalDeltaY;
1118
+ };
1119
+
1120
+ const getListHeight = (itemsLength, itemHeight, maxHeight) => {
1121
+ number(itemsLength);
1122
+ number(itemHeight);
1123
+ number(maxHeight);
1124
+ if (itemsLength === 0) {
1125
+ return itemHeight;
1126
+ }
1127
+ const totalHeight = itemsLength * itemHeight;
1128
+ return Math.min(totalHeight, maxHeight);
1129
+ };
1130
+
1131
+ // TODO optimize this function to return the minimum number
1132
+ // of visible items needed, e.g. when not scrolled 5 items with
1133
+ // 20px fill 100px but when scrolled 6 items are needed
1134
+ const getNumberOfVisibleItems = (listHeight, itemHeight) => {
1135
+ return Math.ceil(listHeight / itemHeight) + 1;
1136
+ };
1137
+
1138
+ const Disk = 'file';
1139
+
1140
+ const RE_PROTOCOL = /^([a-z-]+):\/\//;
1141
+ const getProtocol = uri => {
1142
+ if (!uri) {
1143
+ return Disk;
1144
+ }
1145
+ const protocolMatch = uri.match(RE_PROTOCOL);
1146
+ if (protocolMatch) {
1147
+ return protocolMatch[1];
1148
+ }
1149
+ return Disk;
1150
+ };
1151
+
1152
+ const get = key => {
1153
+ return false;
1154
+ };
1155
+
1156
+ const getScrollBarSize = (size, contentSize, minimumSliderSize) => {
1157
+ if (size >= contentSize) {
1158
+ return 0;
1159
+ }
1160
+ return Math.max(Math.round(size ** 2 / contentSize), minimumSliderSize);
1161
+ };
1162
+
1163
+ const activateByEvent = event => {
1164
+ return invoke$1('ExtensionHostManagement.activateByEvent', event);
1165
+ };
1166
+
1167
+ const invoke = async (method, ...params) => {
1168
+ const rpc = get$1(ExtensionHostWorker);
1169
+ return rpc.invoke(method, ...params);
1170
+ };
1171
+
1172
+ const executeProvider = async ({
1173
+ event,
1174
+ method,
1175
+ params
1176
+ }) => {
1177
+ await activateByEvent(event);
1178
+ const result = await invoke(method, ...params);
1179
+ return result;
1180
+ };
1181
+
1182
+ const SourceControlGetEnabledProviderIds = 'ExtensionHostSourceControl.getEnabledProviderIds';
1183
+ const SourceControlGetGroups = 'ExtensionHostSourceControl.getGroups';
1184
+
1185
+ const getGroups$2 = (providerId, path) => {
1186
+ return executeProvider({
1187
+ event: 'none',
1188
+ method: SourceControlGetGroups,
1189
+ params: [providerId, path]
1190
+ // noProviderFoundMessage: 'No source control provider found',
1191
+ });
1192
+ };
1193
+ const getEnabledProviderIds$1 = (scheme, root) => {
1194
+ return executeProvider({
1195
+ event: `onSourceControl:${scheme}`,
1196
+ method: SourceControlGetEnabledProviderIds,
1197
+ params: [scheme, root]
1198
+ // noProviderFoundMessage: 'No source control provider found',
1199
+ });
1200
+ };
1201
+
1202
+ const getEnabledProviderIds = (scheme, root) => {
1203
+ string(scheme);
1204
+ string(root);
1205
+ return getEnabledProviderIds$1(scheme, root);
1206
+ };
1207
+ const getGroups$1 = (providerId, root) => {
1208
+ return getGroups$2(providerId, root);
1209
+ };
1210
+
1211
+ const getExtensions = async () => {
1212
+ return invoke('Extensions.getExtensions');
1213
+ };
1214
+
1215
+ const state = {
1216
+ cache: Object.create(null)
1217
+ };
1218
+ const getContextId = (groupId, type) => {
1219
+ if (type === File) {
1220
+ return `${groupId}-item`;
1221
+ }
1222
+ return groupId;
1223
+ };
1224
+ const ensureActions = async () => {
1225
+ if (Object.keys(state.cache).length > 0) {
1226
+ return;
1227
+ }
1228
+ const extensions = await getExtensions();
1229
+ for (const extension of extensions) {
1230
+ if (extension && extension['source-control-actions']) {
1231
+ for (const [key, value] of Object.entries(extension['source-control-actions'])) {
1232
+ state.cache[key] = value;
1233
+ }
1234
+ }
1235
+ }
1236
+ };
1237
+ const getSourceControlActions = async (providerId, groupId, type) => {
1238
+ string(groupId);
1239
+ await ensureActions();
1240
+ const contextId = getContextId(groupId, type);
1241
+ const value = state.cache[contextId] || [];
1242
+ return value;
1243
+ };
1244
+
1245
+ const getGroups = async enabledProviderIds => {
1246
+ const allGroups = [];
1247
+ for (const providerId of enabledProviderIds) {
1248
+ // @ts-ignore
1249
+ const groups = await getGroups$1(providerId);
1250
+ allGroups.push(...groups);
1251
+ }
1252
+ return {
1253
+ allGroups,
1254
+ gitRoot: ''
1255
+ };
1256
+ };
1257
+ const getNewButtons = async (displayItems, providerId, buttonIndex) => {
1258
+ if (buttonIndex === -1) {
1259
+ return [];
1260
+ }
1261
+ const item = displayItems[buttonIndex];
1262
+ if (!item) {
1263
+ return [];
1264
+ }
1265
+ const actions = await getSourceControlActions(providerId, item.groupId, item.type);
1266
+ return actions;
1267
+ };
1268
+ const loadContent = async state => {
1269
+ const {
1270
+ itemHeight,
1271
+ height,
1272
+ minimumSliderSize,
1273
+ workspacePath
1274
+ } = state;
1275
+ const root = workspacePath;
1276
+ const scheme = getProtocol(root);
1277
+ const enabledProviderIds = await getEnabledProviderIds(scheme, root);
1278
+ const {
1279
+ allGroups,
1280
+ gitRoot
1281
+ } = await getGroups(enabledProviderIds);
1282
+ const isExpanded = true;
1283
+ const items = getDisplayItems(allGroups);
1284
+ const buttons = await getNewButtons(items, state.providerId, state.buttonIndex);
1285
+ const splitButtonEnabled = get();
1286
+ const total = items.length;
1287
+ const contentHeight = total * itemHeight;
1288
+ const listHeight = getListHeight(total, itemHeight, height);
1289
+ const scrollBarHeight = getScrollBarSize(height, contentHeight, minimumSliderSize);
1290
+ const numberOfVisible = getNumberOfVisibleItems(listHeight, itemHeight);
1291
+ const maxLineY = Math.min(numberOfVisible, total);
1292
+ const finalDeltaY = getFinalDeltaY(listHeight, itemHeight, total);
1293
+ return {
1294
+ ...state,
1295
+ allGroups,
1296
+ gitRoot,
1297
+ items,
1298
+ enabledProviderIds,
1299
+ isExpanded,
1300
+ buttons,
1301
+ root,
1302
+ splitButtonEnabled,
1303
+ maxLineY,
1304
+ scrollBarHeight,
1305
+ finalDeltaY
1306
+ };
1307
+ };
1308
+
1309
+ const terminate = () => {
1310
+ globalThis.close();
1311
+ };
1312
+
1313
+ const commandMap = {
1314
+ 'Initialize.initialize': initialize,
1315
+ 'SourceControl.loadControl': loadContent,
1316
+ 'SourceControl.terminate': terminate
1317
+ };
825
1318
 
826
1319
  const listen = async () => {
827
1320
  const rpc = await WebWorkerRpcClient.create({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/source-control-worker",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Source Control Worker",
5
5
  "keywords": [
6
6
  "Lvce Editor"