@lvce-editor/extension-host-worker 8.43.1 → 8.45.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.
@@ -1556,11 +1556,11 @@ var createProviderRegistry = ({
1556
1556
  requiredMethods,
1557
1557
  requireLanguageId = false
1558
1558
  }) => {
1559
- const providers2 = /* @__PURE__ */ Object.create(null);
1559
+ const providers3 = /* @__PURE__ */ Object.create(null);
1560
1560
  const hasProvider = (id2) => {
1561
- return id2 in providers2;
1561
+ return id2 in providers3;
1562
1562
  };
1563
- const registerProvider = (provider) => {
1563
+ const registerProvider2 = (provider) => {
1564
1564
  if (!provider) {
1565
1565
  throw new ExtensionApiError(`${providerName} is not defined`);
1566
1566
  }
@@ -1582,14 +1582,14 @@ var createProviderRegistry = ({
1582
1582
  throw new ExtensionApiError(`${providerName} ${id2} is already registered`);
1583
1583
  }
1584
1584
  const registeredProvider = mapProvider(provider);
1585
- providers2[registeredProvider.id] = registeredProvider;
1585
+ providers3[registeredProvider.id] = registeredProvider;
1586
1586
  return registeredProvider;
1587
1587
  };
1588
1588
  const deleteProvider = (id2) => {
1589
- delete providers2[id2];
1589
+ delete providers3[id2];
1590
1590
  };
1591
1591
  const getProviders = () => {
1592
- return Object.values(providers2);
1592
+ return Object.values(providers3);
1593
1593
  };
1594
1594
  const getProviderByLanguageId = (languageId) => {
1595
1595
  return getProviders().find((provider) => {
@@ -1597,8 +1597,8 @@ var createProviderRegistry = ({
1597
1597
  });
1598
1598
  };
1599
1599
  const reset = () => {
1600
- for (const id2 of Object.keys(providers2)) {
1601
- delete providers2[id2];
1600
+ for (const id2 of Object.keys(providers3)) {
1601
+ delete providers3[id2];
1602
1602
  }
1603
1603
  };
1604
1604
  const executeProviderByLanguageId = async (languageId, methodName, args, validateResult) => {
@@ -1619,7 +1619,7 @@ var createProviderRegistry = ({
1619
1619
  getProviderByLanguageId,
1620
1620
  getProviders,
1621
1621
  hasProvider,
1622
- registerProvider,
1622
+ registerProvider: registerProvider2,
1623
1623
  reset
1624
1624
  };
1625
1625
  };
@@ -1929,6 +1929,84 @@ var getHoverProviderRegistrySnapshot = () => {
1929
1929
  };
1930
1930
  var resetHoverProviderRegistry = registry5.reset;
1931
1931
 
1932
+ // packages/extension-api/src/parts/LanguageProvider/LanguageProvider.ts
1933
+ var providers = /* @__PURE__ */ Object.create(null);
1934
+ var getProvider = (kind, languageId) => {
1935
+ return providers[kind]?.find((provider) => provider.languageId === languageId);
1936
+ };
1937
+ var registerProvider = (kind, provider, requiredMethods) => {
1938
+ if (!provider || typeof provider !== "object") {
1939
+ throw new ExtensionApiError(`${kind} provider is not defined`);
1940
+ }
1941
+ if (typeof provider.id !== "string" || provider.id.length === 0) {
1942
+ throw new ExtensionApiError(`${kind} provider is missing id`);
1943
+ }
1944
+ if (typeof provider.languageId !== "string" || provider.languageId.length === 0) {
1945
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is missing languageId`);
1946
+ }
1947
+ for (const methodName of requiredMethods) {
1948
+ if (typeof provider[methodName] !== "function") {
1949
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is missing ${methodName} function`);
1950
+ }
1951
+ }
1952
+ const kindProviders = providers[kind] ||= [];
1953
+ if (kindProviders.some((registeredProvider) => registeredProvider.id === provider.id)) {
1954
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is already registered`);
1955
+ }
1956
+ kindProviders.push(provider);
1957
+ return {
1958
+ dispose() {
1959
+ const index = kindProviders.indexOf(provider);
1960
+ if (index !== -1) {
1961
+ kindProviders.splice(index, 1);
1962
+ }
1963
+ }
1964
+ };
1965
+ };
1966
+ var executeLanguageProvider = async (kind, methodName, textDocument, ...args) => {
1967
+ const provider = getProvider(kind, textDocument.languageId);
1968
+ if (!provider) {
1969
+ throw new ExtensionApiError(`No ${kind} provider found for ${textDocument.languageId}`);
1970
+ }
1971
+ const method = provider[methodName];
1972
+ if (typeof method !== "function") {
1973
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is missing ${methodName} function`);
1974
+ }
1975
+ return method(textDocument, ...args);
1976
+ };
1977
+ var executeOrganizeImportsProvider = async (textDocument) => {
1978
+ const provider = getProvider("code action", textDocument.languageId);
1979
+ if (!provider) {
1980
+ throw new ExtensionApiError(`No code action provider found for ${textDocument.languageId}`);
1981
+ }
1982
+ const provideCodeActions = provider.provideCodeActions;
1983
+ const actions = await provideCodeActions(textDocument);
1984
+ if (!Array.isArray(actions)) {
1985
+ throw new ExtensionApiError("invalid code action result: code actions must be of type array");
1986
+ }
1987
+ const action = actions.find((candidate) => candidate && typeof candidate === "object" && candidate.kind === "source.organizeImports");
1988
+ if (!action || typeof action.execute !== "function") {
1989
+ return [];
1990
+ }
1991
+ return action.execute(textDocument);
1992
+ };
1993
+ var registerBraceCompletionProvider = (provider) => registerProvider("brace completion", provider, ["provideBraceCompletion"]);
1994
+ var registerClosingTagProvider = (provider) => registerProvider("closing tag", provider, ["provideClosingTag"]);
1995
+ var registerCodeActionsProvider = (provider) => registerProvider("code action", provider, ["provideCodeActions"]);
1996
+ var registerCommentProvider = (provider) => registerProvider("comment", provider, ["provideComment"]);
1997
+ var registerDefinitionProvider = (provider) => registerProvider("definition", provider, ["provideDefinition"]);
1998
+ var registerImplementationProvider = (provider) => registerProvider("implementation", provider, ["provideImplementations"]);
1999
+ var registerReferenceProvider = (provider) => registerProvider("reference", provider, ["provideReferences"]);
2000
+ var registerRenameProvider = (provider) => registerProvider("rename", provider, ["provideRename"]);
2001
+ var registerSelectionProvider = (provider) => registerProvider("selection", provider, ["provideSelections"]);
2002
+ var registerTabCompletionProvider = (provider) => registerProvider("tab completion", provider, ["provideTabCompletion"]);
2003
+ var registerTypeDefinitionProvider = (provider) => registerProvider("type definition", provider, ["provideTypeDefinition"]);
2004
+ var resetLanguageProviderRegistry = () => {
2005
+ for (const kind of Object.keys(providers)) {
2006
+ delete providers[kind];
2007
+ }
2008
+ };
2009
+
1932
2010
  // packages/extension-api/src/parts/OutputChannel/OutputChannel.ts
1933
2011
  var outputChannels = /* @__PURE__ */ Object.create(null);
1934
2012
  var outputChannelLogs = /* @__PURE__ */ Object.create(null);
@@ -2004,7 +2082,7 @@ var resetOutputChannelRegistry = () => {
2004
2082
  };
2005
2083
 
2006
2084
  // packages/extension-api/src/parts/SourceControlProviderRegistry/SourceControlProviderRegistry.ts
2007
- var providers = /* @__PURE__ */ Object.create(null);
2085
+ var providers2 = /* @__PURE__ */ Object.create(null);
2008
2086
  var optionalMethods = [
2009
2087
  "acceptInput",
2010
2088
  "add",
@@ -2037,12 +2115,12 @@ var assertSourceControlProvider = (provider) => {
2037
2115
  for (const methodName of optionalMethods) {
2038
2116
  assertOptionalProviderMethod2(providerRecord, id2, methodName);
2039
2117
  }
2040
- if (id2 in providers) {
2118
+ if (id2 in providers2) {
2041
2119
  throw new ExtensionApiError(`source control provider ${id2} is already registered`);
2042
2120
  }
2043
2121
  };
2044
- var getProvider = (id2) => {
2045
- const provider = providers[id2];
2122
+ var getProvider2 = (id2) => {
2123
+ const provider = providers2[id2];
2046
2124
  if (!provider) {
2047
2125
  throw new ExtensionApiError(`source control provider ${id2} not found`);
2048
2126
  }
@@ -2087,30 +2165,30 @@ var mapSourceControlProvider = (provider) => {
2087
2165
  };
2088
2166
  var registerSourceControlProvider = (provider) => {
2089
2167
  assertSourceControlProvider(provider);
2090
- providers[provider.id] = mapSourceControlProvider(provider);
2168
+ providers2[provider.id] = mapSourceControlProvider(provider);
2091
2169
  return {
2092
2170
  dispose() {
2093
- delete providers[provider.id];
2171
+ delete providers2[provider.id];
2094
2172
  }
2095
2173
  };
2096
2174
  };
2097
2175
  var executeSourceControlAcceptInput = async (id2, value) => {
2098
- return getProvider(id2).acceptInput?.(value);
2176
+ return getProvider2(id2).acceptInput?.(value);
2099
2177
  };
2100
2178
  var executeSourceControlAdd = async (id2, path) => {
2101
- return getProvider(id2).add?.(path);
2179
+ return getProvider2(id2).add?.(path);
2102
2180
  };
2103
2181
  var executeSourceControlDiscard = async (id2, path) => {
2104
- return getProvider(id2).discard?.(path);
2182
+ return getProvider2(id2).discard?.(path);
2105
2183
  };
2106
2184
  var executeSourceControlGenerateCommitMessage = async (id2) => {
2107
- return getProvider(id2).generateCommitMessage?.();
2185
+ return getProvider2(id2).generateCommitMessage?.();
2108
2186
  };
2109
2187
  var executeSourceControlGetChangedFiles = async (id2) => {
2110
- return getProvider(id2).getChangedFiles();
2188
+ return getProvider2(id2).getChangedFiles();
2111
2189
  };
2112
2190
  var executeSourceControlGetBadgeCount = async (id2) => {
2113
- const provider = getProvider(id2);
2191
+ const provider = getProvider2(id2);
2114
2192
  if (provider.getBadgeCount) {
2115
2193
  return provider.getBadgeCount();
2116
2194
  }
@@ -2118,16 +2196,16 @@ var executeSourceControlGetBadgeCount = async (id2) => {
2118
2196
  return files.length;
2119
2197
  };
2120
2198
  var executeSourceControlGetFeatures = async (id2) => {
2121
- return getProvider(id2).getFeatures?.() ?? {};
2199
+ return getProvider2(id2).getFeatures?.() ?? {};
2122
2200
  };
2123
2201
  var executeSourceControlGetFileBefore = async (id2, uri) => {
2124
- return getProvider(id2).getFileBefore?.(uri);
2202
+ return getProvider2(id2).getFileBefore?.(uri);
2125
2203
  };
2126
2204
  var executeSourceControlGetFileDecorations = async (id2, uris) => {
2127
- return getProvider(id2).getFileDecorations?.(uris) ?? [];
2205
+ return getProvider2(id2).getFileDecorations?.(uris) ?? [];
2128
2206
  };
2129
2207
  var executeSourceControlGetGroups = async (id2, cwd) => {
2130
- const provider = getProvider(id2);
2208
+ const provider = getProvider2(id2);
2131
2209
  if (provider.getGroups) {
2132
2210
  return provider.getGroups(cwd);
2133
2211
  }
@@ -2140,18 +2218,18 @@ var executeSourceControlGetGroups = async (id2, cwd) => {
2140
2218
  ];
2141
2219
  };
2142
2220
  var executeSourceControlIsActive = async (id2, scheme, root) => {
2143
- return Boolean(await getProvider(id2).isActive?.(scheme, root));
2221
+ return Boolean(await getProvider2(id2).isActive?.(scheme, root));
2144
2222
  };
2145
2223
  var getSourceControlProviderRegistrySnapshot = () => {
2146
2224
  return {
2147
- providers: Object.values(providers).map((provider) => ({
2225
+ providers: Object.values(providers2).map((provider) => ({
2148
2226
  id: provider.id
2149
2227
  }))
2150
2228
  };
2151
2229
  };
2152
2230
  var resetSourceControlProviderRegistry = () => {
2153
- for (const id2 of Object.keys(providers)) {
2154
- delete providers[id2];
2231
+ for (const id2 of Object.keys(providers2)) {
2232
+ delete providers2[id2];
2155
2233
  }
2156
2234
  };
2157
2235
 
@@ -2638,6 +2716,26 @@ var normalizeViewActions = (actions) => {
2638
2716
  }
2639
2717
  return actions.map(normalizeViewAction);
2640
2718
  };
2719
+ var normalizeViewSelection = (selection, index) => {
2720
+ if (!selection || typeof selection !== "object" || Array.isArray(selection)) {
2721
+ throw new ExtensionApiError(`view selection ${index} must be an object`);
2722
+ }
2723
+ const viewSelection = selection;
2724
+ assertString(viewSelection.name, `view selection ${index} is missing name`);
2725
+ assertNumber(viewSelection.start, `view selection ${index} is missing start`);
2726
+ assertNumber(viewSelection.end, `view selection ${index} is missing end`);
2727
+ return {
2728
+ end: viewSelection.end,
2729
+ name: viewSelection.name,
2730
+ start: viewSelection.start
2731
+ };
2732
+ };
2733
+ var normalizeViewSelections = (selections) => {
2734
+ if (!Array.isArray(selections)) {
2735
+ throw new ExtensionApiError("view selections must be an array");
2736
+ }
2737
+ return selections.map(normalizeViewSelection);
2738
+ };
2641
2739
  var renderPatches = async (uid, instance) => {
2642
2740
  const oldDom = renderedDoms[uid] || [];
2643
2741
  const newDom = await renderDom(instance);
@@ -2736,9 +2834,23 @@ var withTitle = async (result, instance) => {
2736
2834
  title
2737
2835
  };
2738
2836
  };
2837
+ var withSelections = async (result, instance) => {
2838
+ if (typeof instance.renderSelections !== "function") {
2839
+ return result;
2840
+ }
2841
+ const selections = normalizeViewSelections(await instance.renderSelections());
2842
+ if (selections.length === 0) {
2843
+ return result;
2844
+ }
2845
+ return {
2846
+ ...result,
2847
+ selections
2848
+ };
2849
+ };
2739
2850
  var withRenderMetadata = async (result, instance, contextChange) => {
2740
2851
  const resultWithFocus = await withFocusSelector(result, instance, contextChange);
2741
- return withTitle(resultWithFocus, instance);
2852
+ const resultWithSelections = await withSelections(resultWithFocus, instance);
2853
+ return withTitle(resultWithSelections, instance);
2742
2854
  };
2743
2855
  var maybeClearContext = async (uid, viewId) => {
2744
2856
  if (!contexts[uid]) {
@@ -2880,6 +2992,8 @@ var commandMap = {
2880
2992
  "ExtensionApi.executeDiagnosticProvider": executeDiagnosticProvider,
2881
2993
  "ExtensionApi.executeFormattingProvider": executeFormattingProvider,
2882
2994
  "ExtensionApi.executeHoverProvider": executeHoverProvider,
2995
+ "ExtensionApi.executeLanguageProvider": executeLanguageProvider,
2996
+ "ExtensionApi.executeOrganizeImportsProvider": executeOrganizeImportsProvider,
2883
2997
  "ExtensionApi.executeResolveCompletionItemProvider": executeResolveCompletionItemProvider,
2884
2998
  "ExtensionApi.executeSourceControlAcceptInput": executeSourceControlAcceptInput,
2885
2999
  "ExtensionApi.executeSourceControlAdd": executeSourceControlAdd,
@@ -3136,13 +3250,24 @@ export {
3136
3250
  openUri,
3137
3251
  readDirWithFileTypes2 as readDirWithFileTypes,
3138
3252
  readFile2 as readFile,
3253
+ registerBraceCompletionProvider,
3254
+ registerClosingTagProvider,
3255
+ registerCodeActionsProvider,
3139
3256
  registerCommand,
3257
+ registerCommentProvider,
3140
3258
  registerCompletionProvider,
3259
+ registerDefinitionProvider,
3141
3260
  registerDiagnosticProvider,
3142
3261
  registerFormattingProvider,
3143
3262
  registerHoverProvider,
3263
+ registerImplementationProvider,
3264
+ registerReferenceProvider,
3265
+ registerRenameProvider,
3266
+ registerSelectionProvider,
3144
3267
  registerSourceControlProvider,
3145
3268
  registerStatusBarItemProvider,
3269
+ registerTabCompletionProvider,
3270
+ registerTypeDefinitionProvider,
3146
3271
  registerView,
3147
3272
  remove4 as remove,
3148
3273
  renderViewInstance,
@@ -3150,6 +3275,7 @@ export {
3150
3275
  resetDiagnosticProviderRegistry,
3151
3276
  resetFormattingProviderRegistry,
3152
3277
  resetHoverProviderRegistry,
3278
+ resetLanguageProviderRegistry,
3153
3279
  resetOutputChannelRegistry,
3154
3280
  resetSourceControlProviderRegistry,
3155
3281
  resetStatusBarItemProviderRegistry,
@@ -4,6 +4,7 @@ import { executeDiagnosticProvider, getDiagnosticProviderRegistrySnapshot } from
4
4
  import { executeFormattingProvider, getFormattingProviderRegistrySnapshot } from "../Formatting/Formatting.js";
5
5
  import { getStatusBarItems } from "../GetStatusBarItems/GetStatusBarItems.js";
6
6
  import { executeHoverProvider, getHoverProviderRegistrySnapshot } from "../Hover/Hover.js";
7
+ import { executeLanguageProvider, executeOrganizeImportsProvider } from "../LanguageProvider/LanguageProvider.js";
7
8
  import { getOutputChannelRegistrySnapshot } from "../OutputChannel/OutputChannel.js";
8
9
  import {
9
10
  executeSourceControlAcceptInput,
@@ -39,6 +40,8 @@ const commandMap = {
39
40
  "ExtensionApi.executeDiagnosticProvider": executeDiagnosticProvider,
40
41
  "ExtensionApi.executeFormattingProvider": executeFormattingProvider,
41
42
  "ExtensionApi.executeHoverProvider": executeHoverProvider,
43
+ "ExtensionApi.executeLanguageProvider": executeLanguageProvider,
44
+ "ExtensionApi.executeOrganizeImportsProvider": executeOrganizeImportsProvider,
42
45
  "ExtensionApi.executeResolveCompletionItemProvider": executeResolveCompletionItemProvider,
43
46
  "ExtensionApi.executeSourceControlAcceptInput": executeSourceControlAcceptInput,
44
47
  "ExtensionApi.executeSourceControlAdd": executeSourceControlAdd,
@@ -0,0 +1,93 @@
1
+ import { ExtensionApiError } from "../ExtensionApiError/ExtensionApiError.js";
2
+ const providers = /* @__PURE__ */ Object.create(null);
3
+ const getProvider = (kind, languageId) => {
4
+ return providers[kind]?.find((provider) => provider.languageId === languageId);
5
+ };
6
+ const registerProvider = (kind, provider, requiredMethods) => {
7
+ if (!provider || typeof provider !== "object") {
8
+ throw new ExtensionApiError(`${kind} provider is not defined`);
9
+ }
10
+ if (typeof provider.id !== "string" || provider.id.length === 0) {
11
+ throw new ExtensionApiError(`${kind} provider is missing id`);
12
+ }
13
+ if (typeof provider.languageId !== "string" || provider.languageId.length === 0) {
14
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is missing languageId`);
15
+ }
16
+ for (const methodName of requiredMethods) {
17
+ if (typeof provider[methodName] !== "function") {
18
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is missing ${methodName} function`);
19
+ }
20
+ }
21
+ const kindProviders = providers[kind] ||= [];
22
+ if (kindProviders.some((registeredProvider) => registeredProvider.id === provider.id)) {
23
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is already registered`);
24
+ }
25
+ kindProviders.push(provider);
26
+ return {
27
+ dispose() {
28
+ const index = kindProviders.indexOf(provider);
29
+ if (index !== -1) {
30
+ kindProviders.splice(index, 1);
31
+ }
32
+ }
33
+ };
34
+ };
35
+ const executeLanguageProvider = async (kind, methodName, textDocument, ...args) => {
36
+ const provider = getProvider(kind, textDocument.languageId);
37
+ if (!provider) {
38
+ throw new ExtensionApiError(`No ${kind} provider found for ${textDocument.languageId}`);
39
+ }
40
+ const method = provider[methodName];
41
+ if (typeof method !== "function") {
42
+ throw new ExtensionApiError(`${kind} provider ${provider.id} is missing ${methodName} function`);
43
+ }
44
+ return method(textDocument, ...args);
45
+ };
46
+ const executeOrganizeImportsProvider = async (textDocument) => {
47
+ const provider = getProvider("code action", textDocument.languageId);
48
+ if (!provider) {
49
+ throw new ExtensionApiError(`No code action provider found for ${textDocument.languageId}`);
50
+ }
51
+ const provideCodeActions = provider.provideCodeActions;
52
+ const actions = await provideCodeActions(textDocument);
53
+ if (!Array.isArray(actions)) {
54
+ throw new ExtensionApiError("invalid code action result: code actions must be of type array");
55
+ }
56
+ const action = actions.find((candidate) => candidate && typeof candidate === "object" && candidate.kind === "source.organizeImports");
57
+ if (!action || typeof action.execute !== "function") {
58
+ return [];
59
+ }
60
+ return action.execute(textDocument);
61
+ };
62
+ const registerBraceCompletionProvider = (provider) => registerProvider("brace completion", provider, ["provideBraceCompletion"]);
63
+ const registerClosingTagProvider = (provider) => registerProvider("closing tag", provider, ["provideClosingTag"]);
64
+ const registerCodeActionsProvider = (provider) => registerProvider("code action", provider, ["provideCodeActions"]);
65
+ const registerCommentProvider = (provider) => registerProvider("comment", provider, ["provideComment"]);
66
+ const registerDefinitionProvider = (provider) => registerProvider("definition", provider, ["provideDefinition"]);
67
+ const registerImplementationProvider = (provider) => registerProvider("implementation", provider, ["provideImplementations"]);
68
+ const registerReferenceProvider = (provider) => registerProvider("reference", provider, ["provideReferences"]);
69
+ const registerRenameProvider = (provider) => registerProvider("rename", provider, ["provideRename"]);
70
+ const registerSelectionProvider = (provider) => registerProvider("selection", provider, ["provideSelections"]);
71
+ const registerTabCompletionProvider = (provider) => registerProvider("tab completion", provider, ["provideTabCompletion"]);
72
+ const registerTypeDefinitionProvider = (provider) => registerProvider("type definition", provider, ["provideTypeDefinition"]);
73
+ const resetLanguageProviderRegistry = () => {
74
+ for (const kind of Object.keys(providers)) {
75
+ delete providers[kind];
76
+ }
77
+ };
78
+ export {
79
+ executeLanguageProvider,
80
+ executeOrganizeImportsProvider,
81
+ registerBraceCompletionProvider,
82
+ registerClosingTagProvider,
83
+ registerCodeActionsProvider,
84
+ registerCommentProvider,
85
+ registerDefinitionProvider,
86
+ registerImplementationProvider,
87
+ registerReferenceProvider,
88
+ registerRenameProvider,
89
+ registerSelectionProvider,
90
+ registerTabCompletionProvider,
91
+ registerTypeDefinitionProvider,
92
+ resetLanguageProviderRegistry
93
+ };
@@ -238,6 +238,26 @@ const normalizeViewActions = (actions) => {
238
238
  }
239
239
  return actions.map(normalizeViewAction);
240
240
  };
241
+ const normalizeViewSelection = (selection, index) => {
242
+ if (!selection || typeof selection !== "object" || Array.isArray(selection)) {
243
+ throw new ExtensionApiError(`view selection ${index} must be an object`);
244
+ }
245
+ const viewSelection = selection;
246
+ assertString(viewSelection.name, `view selection ${index} is missing name`);
247
+ assertNumber(viewSelection.start, `view selection ${index} is missing start`);
248
+ assertNumber(viewSelection.end, `view selection ${index} is missing end`);
249
+ return {
250
+ end: viewSelection.end,
251
+ name: viewSelection.name,
252
+ start: viewSelection.start
253
+ };
254
+ };
255
+ const normalizeViewSelections = (selections) => {
256
+ if (!Array.isArray(selections)) {
257
+ throw new ExtensionApiError("view selections must be an array");
258
+ }
259
+ return selections.map(normalizeViewSelection);
260
+ };
241
261
  const renderPatches = async (uid, instance) => {
242
262
  const oldDom = renderedDoms[uid] || [];
243
263
  const newDom = await renderDom(instance);
@@ -336,9 +356,23 @@ const withTitle = async (result, instance) => {
336
356
  title
337
357
  };
338
358
  };
359
+ const withSelections = async (result, instance) => {
360
+ if (typeof instance.renderSelections !== "function") {
361
+ return result;
362
+ }
363
+ const selections = normalizeViewSelections(await instance.renderSelections());
364
+ if (selections.length === 0) {
365
+ return result;
366
+ }
367
+ return {
368
+ ...result,
369
+ selections
370
+ };
371
+ };
339
372
  const withRenderMetadata = async (result, instance, contextChange) => {
340
373
  const resultWithFocus = await withFocusSelector(result, instance, contextChange);
341
- return withTitle(resultWithFocus, instance);
374
+ const resultWithSelections = await withSelections(resultWithFocus, instance);
375
+ return withTitle(resultWithSelections, instance);
342
376
  };
343
377
  const maybeClearContext = async (uid, viewId) => {
344
378
  if (!contexts[uid]) {