@theia/plugin-ext 1.34.2 → 1.36.0-next.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/lib/common/plugin-api-rpc-model.d.ts +18 -1
  2. package/lib/common/plugin-api-rpc-model.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc-model.js.map +1 -1
  4. package/lib/common/plugin-api-rpc.d.ts +10 -5
  5. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  6. package/lib/common/plugin-api-rpc.js.map +1 -1
  7. package/lib/common/plugin-protocol.d.ts +44 -10
  8. package/lib/common/plugin-protocol.d.ts.map +1 -1
  9. package/lib/common/plugin-protocol.js.map +1 -1
  10. package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
  11. package/lib/hosted/browser/hosted-plugin.js +16 -21
  12. package/lib/hosted/browser/hosted-plugin.js.map +1 -1
  13. package/lib/hosted/node/hosted-plugin-deployer-handler.js +1 -1
  14. package/lib/hosted/node/hosted-plugin-deployer-handler.js.map +1 -1
  15. package/lib/hosted/node/hosted-plugin-process.js.map +1 -1
  16. package/lib/hosted/node/plugin-activation-events.d.ts +7 -0
  17. package/lib/hosted/node/plugin-activation-events.d.ts.map +1 -0
  18. package/lib/hosted/node/plugin-activation-events.js +96 -0
  19. package/lib/hosted/node/plugin-activation-events.js.map +1 -0
  20. package/lib/hosted/node/plugin-host-rpc.js +2 -2
  21. package/lib/hosted/node/plugin-host-rpc.js.map +1 -1
  22. package/lib/hosted/node/plugin-manifest-loader.d.ts +2 -1
  23. package/lib/hosted/node/plugin-manifest-loader.d.ts.map +1 -1
  24. package/lib/hosted/node/plugin-manifest-loader.js +2 -1
  25. package/lib/hosted/node/plugin-manifest-loader.js.map +1 -1
  26. package/lib/hosted/node/scanners/scanner-theia.d.ts.map +1 -1
  27. package/lib/hosted/node/scanners/scanner-theia.js +27 -36
  28. package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
  29. package/lib/main/browser/data-transfer/data-transfer-type-converters.d.ts +9 -0
  30. package/lib/main/browser/data-transfer/data-transfer-type-converters.d.ts.map +1 -0
  31. package/lib/main/browser/data-transfer/data-transfer-type-converters.js +65 -0
  32. package/lib/main/browser/data-transfer/data-transfer-type-converters.js.map +1 -0
  33. package/lib/main/browser/dialogs/modal-notification.d.ts.map +1 -1
  34. package/lib/main/browser/dialogs/modal-notification.js +4 -2
  35. package/lib/main/browser/dialogs/modal-notification.js.map +1 -1
  36. package/lib/main/browser/languages-main.d.ts +8 -1
  37. package/lib/main/browser/languages-main.d.ts.map +1 -1
  38. package/lib/main/browser/languages-main.js +26 -2
  39. package/lib/main/browser/languages-main.js.map +1 -1
  40. package/lib/main/browser/main-file-system-event-service.d.ts.map +1 -1
  41. package/lib/main/browser/main-file-system-event-service.js +6 -9
  42. package/lib/main/browser/main-file-system-event-service.js.map +1 -1
  43. package/lib/main/browser/plugin-contribution-handler.d.ts.map +1 -1
  44. package/lib/main/browser/plugin-contribution-handler.js +4 -1
  45. package/lib/main/browser/plugin-contribution-handler.js.map +1 -1
  46. package/lib/main/browser/plugin-ext-frontend-module.d.ts.map +1 -1
  47. package/lib/main/browser/plugin-ext-frontend-module.js +3 -0
  48. package/lib/main/browser/plugin-ext-frontend-module.js.map +1 -1
  49. package/lib/main/browser/text-editors-main.d.ts +2 -2
  50. package/lib/main/browser/text-editors-main.d.ts.map +1 -1
  51. package/lib/main/browser/text-editors-main.js +2 -2
  52. package/lib/main/browser/text-editors-main.js.map +1 -1
  53. package/lib/main/browser/webview/webview-context-keys.d.ts +13 -0
  54. package/lib/main/browser/webview/webview-context-keys.d.ts.map +1 -0
  55. package/lib/main/browser/webview/webview-context-keys.js +64 -0
  56. package/lib/main/browser/webview/webview-context-keys.js.map +1 -0
  57. package/lib/main/node/handlers/plugin-theia-directory-handler.js +1 -1
  58. package/lib/main/node/handlers/plugin-theia-directory-handler.js.map +1 -1
  59. package/lib/plugin/dialogs.js +2 -2
  60. package/lib/plugin/dialogs.js.map +1 -1
  61. package/lib/plugin/file-system-ext-impl.d.ts +11 -5
  62. package/lib/plugin/file-system-ext-impl.d.ts.map +1 -1
  63. package/lib/plugin/file-system-ext-impl.js +8 -16
  64. package/lib/plugin/file-system-ext-impl.js.map +1 -1
  65. package/lib/plugin/known-commands.d.ts.map +1 -1
  66. package/lib/plugin/known-commands.js +13 -0
  67. package/lib/plugin/known-commands.js.map +1 -1
  68. package/lib/plugin/languages/document-drop-edit.d.ts +16 -0
  69. package/lib/plugin/languages/document-drop-edit.d.ts.map +1 -0
  70. package/lib/plugin/languages/document-drop-edit.js +23 -0
  71. package/lib/plugin/languages/document-drop-edit.js.map +1 -0
  72. package/lib/plugin/languages.d.ts +9 -2
  73. package/lib/plugin/languages.d.ts.map +1 -1
  74. package/lib/plugin/languages.js +27 -1
  75. package/lib/plugin/languages.js.map +1 -1
  76. package/lib/plugin/plugin-context.d.ts +2 -1
  77. package/lib/plugin/plugin-context.d.ts.map +1 -1
  78. package/lib/plugin/plugin-context.js +16 -6
  79. package/lib/plugin/plugin-context.js.map +1 -1
  80. package/lib/plugin/preference-registry.d.ts +5 -3
  81. package/lib/plugin/preference-registry.d.ts.map +1 -1
  82. package/lib/plugin/preference-registry.js +31 -42
  83. package/lib/plugin/preference-registry.js.map +1 -1
  84. package/lib/plugin/preference-registry.spec.js +29 -41
  85. package/lib/plugin/preference-registry.spec.js.map +1 -1
  86. package/lib/plugin/text-editors.d.ts +1 -1
  87. package/lib/plugin/text-editors.d.ts.map +1 -1
  88. package/lib/plugin/text-editors.js +2 -2
  89. package/lib/plugin/text-editors.js.map +1 -1
  90. package/lib/plugin/type-converters.d.ts +6 -0
  91. package/lib/plugin/type-converters.d.ts.map +1 -1
  92. package/lib/plugin/type-converters.js +37 -1
  93. package/lib/plugin/type-converters.js.map +1 -1
  94. package/lib/plugin/types-impl.d.ts +6 -1
  95. package/lib/plugin/types-impl.d.ts.map +1 -1
  96. package/lib/plugin/types-impl.js +16 -3
  97. package/lib/plugin/types-impl.js.map +1 -1
  98. package/lib/plugin/webview-views.js +2 -2
  99. package/lib/plugin/webview-views.js.map +1 -1
  100. package/package.json +27 -27
  101. package/src/common/plugin-api-rpc-model.ts +22 -1
  102. package/src/common/plugin-api-rpc.ts +18 -5
  103. package/src/common/plugin-protocol.ts +47 -14
  104. package/src/hosted/browser/hosted-plugin.ts +15 -20
  105. package/src/hosted/node/hosted-plugin-deployer-handler.ts +1 -1
  106. package/src/hosted/node/hosted-plugin-process.ts +2 -2
  107. package/src/hosted/node/plugin-activation-events.ts +111 -0
  108. package/src/hosted/node/plugin-host-rpc.ts +2 -2
  109. package/src/hosted/node/plugin-manifest-loader.ts +4 -3
  110. package/src/hosted/node/scanners/scanner-theia.ts +59 -75
  111. package/src/main/browser/data-transfer/data-transfer-type-converters.ts +70 -0
  112. package/src/main/browser/dialogs/modal-notification.ts +4 -2
  113. package/src/main/browser/languages-main.ts +34 -4
  114. package/src/main/browser/main-file-system-event-service.ts +6 -9
  115. package/src/main/browser/plugin-contribution-handler.ts +6 -3
  116. package/src/main/browser/plugin-ext-frontend-module.ts +3 -0
  117. package/src/main/browser/text-editors-main.ts +3 -2
  118. package/src/main/browser/webview/webview-context-keys.ts +49 -0
  119. package/src/main/node/handlers/plugin-theia-directory-handler.ts +1 -1
  120. package/src/plugin/dialogs.ts +2 -2
  121. package/src/plugin/file-system-ext-impl.ts +8 -18
  122. package/src/plugin/known-commands.ts +16 -1
  123. package/src/plugin/languages/document-drop-edit.ts +44 -0
  124. package/src/plugin/languages.ts +41 -3
  125. package/src/plugin/plugin-context.ts +18 -6
  126. package/src/plugin/preference-registry.spec.ts +29 -45
  127. package/src/plugin/preference-registry.ts +33 -45
  128. package/src/plugin/text-editors.ts +2 -2
  129. package/src/plugin/type-converters.ts +37 -0
  130. package/src/plugin/types-impl.ts +15 -1
  131. package/src/plugin/webview-views.ts +2 -2
@@ -87,6 +87,7 @@ import {
87
87
  DocumentHighlightKind,
88
88
  DocumentHighlight,
89
89
  DocumentLink,
90
+ DocumentDropEdit,
90
91
  CodeLens,
91
92
  CodeActionKind,
92
93
  CodeActionTrigger,
@@ -257,11 +258,11 @@ export function createAPIFactory(
257
258
  const statusBarMessageRegistryExt = new StatusBarMessageRegistryExt(rpc);
258
259
  const terminalExt = rpc.set(MAIN_RPC_CONTEXT.TERMINAL_EXT, new TerminalServiceExtImpl(rpc));
259
260
  const outputChannelRegistryExt = rpc.set(MAIN_RPC_CONTEXT.OUTPUT_CHANNEL_REGISTRY_EXT, new OutputChannelRegistryExtImpl(rpc));
260
- const languagesExt = rpc.set(MAIN_RPC_CONTEXT.LANGUAGES_EXT, new LanguagesExtImpl(rpc, documents, commandRegistry));
261
261
  const treeViewsExt = rpc.set(MAIN_RPC_CONTEXT.TREE_VIEWS_EXT, new TreeViewsExtImpl(rpc, commandRegistry));
262
262
  const tasksExt = rpc.set(MAIN_RPC_CONTEXT.TASKS_EXT, new TasksExtImpl(rpc, terminalExt));
263
263
  const connectionExt = rpc.set(MAIN_RPC_CONTEXT.CONNECTION_EXT, new ConnectionImpl(rpc.getProxy(PLUGIN_RPC_CONTEXT.CONNECTION_MAIN)));
264
- const fileSystemExt = rpc.set(MAIN_RPC_CONTEXT.FILE_SYSTEM_EXT, new FileSystemExtImpl(rpc, languagesExt));
264
+ const fileSystemExt = rpc.set(MAIN_RPC_CONTEXT.FILE_SYSTEM_EXT, new FileSystemExtImpl(rpc));
265
+ const languagesExt = rpc.set(MAIN_RPC_CONTEXT.LANGUAGES_EXT, new LanguagesExtImpl(rpc, documents, commandRegistry, fileSystemExt));
265
266
  const extHostFileSystemEvent = rpc.set(MAIN_RPC_CONTEXT.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpc, editorsAndDocumentsExt));
266
267
  const scmExt = rpc.set(MAIN_RPC_CONTEXT.SCM_EXT, new ScmExtImpl(rpc, commandRegistry));
267
268
  const decorationsExt = rpc.set(MAIN_RPC_CONTEXT.DECORATIONS_EXT, new DecorationsExtImpl(rpc));
@@ -669,8 +670,8 @@ export function createAPIFactory(
669
670
  saveAll(includeUntitled?: boolean): PromiseLike<boolean> {
670
671
  return editors.saveAll(includeUntitled);
671
672
  },
672
- applyEdit(edit: theia.WorkspaceEdit): PromiseLike<boolean> {
673
- return editors.applyWorkspaceEdit(edit);
673
+ applyEdit(edit: theia.WorkspaceEdit, metadata?: theia.WorkspaceEditMetadata): PromiseLike<boolean> {
674
+ return editors.applyWorkspaceEdit(edit, metadata);
674
675
  },
675
676
  registerTextDocumentContentProvider(scheme: string, provider: theia.TextDocumentContentProvider): theia.Disposable {
676
677
  return workspaceExt.registerTextDocumentContentProvider(scheme, provider);
@@ -752,7 +753,8 @@ export function createAPIFactory(
752
753
 
753
754
  const extensions: typeof theia.extensions = Object.freeze({
754
755
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
755
- getExtension<T = any>(extensionId: string): theia.Extension<T> | undefined {
756
+ getExtension<T = any>(extensionId: string, includeFromDifferentExtensionHosts: boolean = false): theia.Extension<T> | undefined {
757
+ includeFromDifferentExtensionHosts = false;
756
758
  const plg = pluginManager.getPluginById(extensionId.toLowerCase());
757
759
  if (plg) {
758
760
  return new PluginExt(pluginManager, plg);
@@ -763,6 +765,10 @@ export function createAPIFactory(
763
765
  get all(): readonly theia.Extension<any>[] {
764
766
  return pluginManager.getAllPlugins().map(plg => new PluginExt(pluginManager, plg));
765
767
  },
768
+ get allAcrossExtensionHosts(): readonly theia.Extension<any>[] {
769
+ // we only support one extension host ATM so equivalent to calling "all()"
770
+ return this.all;
771
+ },
766
772
  get onDidChange(): theia.Event<void> {
767
773
  return pluginManager.onDidChange;
768
774
  }
@@ -853,6 +859,9 @@ export function createAPIFactory(
853
859
  ): theia.Disposable {
854
860
  return languagesExt.registerOnTypeFormattingEditProvider(selector, provider, [firstTriggerCharacter].concat(moreTriggerCharacters), pluginToPluginInfo(plugin));
855
861
  },
862
+ registerDocumentDropEditProvider(selector: theia.DocumentSelector, provider: theia.DocumentDropEditProvider) {
863
+ return languagesExt.registerDocumentDropEditProvider(selector, provider);
864
+ },
856
865
  registerDocumentLinkProvider(selector: theia.DocumentSelector, provider: theia.DocumentLinkProvider): theia.Disposable {
857
866
  return languagesExt.registerDocumentLinkProvider(selector, provider, pluginToPluginInfo(plugin));
858
867
  },
@@ -1195,6 +1204,7 @@ export function createAPIFactory(
1195
1204
  DocumentHighlightKind,
1196
1205
  DocumentHighlight,
1197
1206
  DocumentLink,
1207
+ DocumentDropEdit,
1198
1208
  CodeLens,
1199
1209
  CodeActionKind,
1200
1210
  CodeActionTrigger,
@@ -1364,13 +1374,15 @@ export class PluginExt<T> extends Plugin<T> implements ExtensionPlugin<T> {
1364
1374
  extensionPath: string;
1365
1375
  extensionUri: theia.Uri;
1366
1376
  extensionKind: ExtensionKind;
1377
+ isFromDifferentExtensionHost: boolean;
1367
1378
 
1368
- constructor(protected override readonly pluginManager: PluginManager, plugin: InternalPlugin) {
1379
+ constructor(protected override readonly pluginManager: PluginManager, plugin: InternalPlugin, isFromDifferentExtensionHost = false) {
1369
1380
  super(pluginManager, plugin);
1370
1381
 
1371
1382
  this.extensionPath = this.pluginPath;
1372
1383
  this.extensionUri = this.pluginUri;
1373
1384
  this.extensionKind = ExtensionKind.UI; // stub as a local extension (not running on a remote workspace)
1385
+ this.isFromDifferentExtensionHost = isFromDifferentExtensionHost;
1374
1386
  }
1375
1387
 
1376
1388
  override get isActive(): boolean {
@@ -41,36 +41,6 @@ describe('PreferenceRegistryExtImpl:', () => {
41
41
  preferenceRegistryExtImpl = new PreferenceRegistryExtImpl(mockRPC, mockWorkspace);
42
42
  });
43
43
 
44
- it('should parse configuration data without overrides', () => {
45
- const value: Record<string, any> = {
46
- 'my.key1.foo': 'value1',
47
- 'my.key1.bar': 'value2',
48
- };
49
- const result = preferenceRegistryExtImpl['parseConfigurationData'](value);
50
- expect(result.contents.my).to.be.an('object');
51
- expect(result.contents.my.key1).to.be.an('object');
52
-
53
- expect(result.contents.my.key1.foo).to.be.an('string');
54
- expect(result.contents.my.key1.foo).to.equal('value1');
55
-
56
- expect(result.contents.my.key1.bar).to.be.an('string');
57
- expect(result.contents.my.key1.bar).to.equal('value2');
58
- expect(result.keys).deep.equal(['my.key1.foo', 'my.key1.bar']);
59
- });
60
-
61
- it('should parse configuration with overrides', () => {
62
- const value: Record<string, any> = {
63
- 'editor.tabSize': 2,
64
- '[typescript].editor.tabSize': 4,
65
- };
66
- const result = preferenceRegistryExtImpl['parseConfigurationData'](value);
67
- expect(result.contents.editor.tabSize).to.equal(2);
68
- const tsOverride = result.overrides[0];
69
- expect(tsOverride.contents.editor.tabSize).to.equal(4);
70
- expect(tsOverride.identifiers).deep.equal(['typescript']);
71
- expect(tsOverride.keys).deep.equal(['editor.tabSize']);
72
- });
73
-
74
44
  describe('Prototype pollution', () => {
75
45
  it('Ignores key `__proto__`', () => {
76
46
  const value: Record<string, any> = {
@@ -80,16 +50,18 @@ describe('PreferenceRegistryExtImpl:', () => {
80
50
  '__proto__': {},
81
51
  '[typescript].someKey.foo': 'value',
82
52
  '[typescript].__proto__.injectedParsedPrototype': true,
53
+ 'b': { '__proto__.injectedParsedPrototype': true },
54
+ 'c': { '__proto__': { 'injectedParsedPrototype': true } }
83
55
  };
84
- const result = preferenceRegistryExtImpl['parseConfigurationData'](value);
85
- expect(result.contents.my).to.be.an('object');
86
- expect(result.contents.__proto__).to.be.an('undefined');
87
- expect(result.contents.my.key1.foo).to.equal('value1');
88
- expect(result.overrides[0].contents.__proto__).to.be.an('undefined');
56
+ const configuration = preferenceRegistryExtImpl['getConfigurationModel']('test', value);
57
+ const result = configuration['_contents'];
58
+ expect(result.my, 'Safe keys are preserved.').to.be.an('object');
59
+ expect(result.__proto__, 'Keys containing __proto__ are ignored').to.be.an('undefined');
60
+ expect(result.my.key1.foo, 'Safe keys are dendrified.').to.equal('value1');
89
61
  const prototypeObject = Object.prototype as any;
90
- expect(prototypeObject.injectedParsedPrototype).to.be.an('undefined');
62
+ expect(prototypeObject.injectedParsedPrototype, 'Object.prototype is unaffected').to.be.an('undefined');
91
63
  const rawObject = {} as any;
92
- expect(rawObject.injectedParsedPrototype).to.be.an('undefined');
64
+ expect(rawObject.injectedParsedPrototype, 'Instantiated objects are unaffected.').to.be.an('undefined');
93
65
  });
94
66
 
95
67
  it('Ignores key `constructor.prototype`', () => {
@@ -98,17 +70,19 @@ describe('PreferenceRegistryExtImpl:', () => {
98
70
  'a.constructor.prototype.injectedParsedConstructorPrototype': true,
99
71
  'constructor.prototype.injectedParsedConstructorPrototype': true,
100
72
  '[python].some.key.foo': 'value',
101
- '[python].a.constructor.prototype.injectedParsedConstructorPrototype': true
73
+ '[python].a.constructor.prototype.injectedParsedConstructorPrototype': true,
74
+ 'constructor': { 'prototype.injectedParsedConstructorPrototype': true },
75
+ 'b': { 'constructor': { 'prototype': { 'injectedParsedConstructorPrototype': true } } }
102
76
  };
103
- const result = preferenceRegistryExtImpl['parseConfigurationData'](value);
104
- expect(result.contents.my).to.be.an('object');
105
- expect(result.contents.__proto__).to.be.an('undefined');
106
- expect(result.contents.my.key1.foo).to.equal('value1');
77
+ const configuration = preferenceRegistryExtImpl['getConfigurationModel']('test', value);
78
+ const result = configuration['_contents'];
79
+ expect(result.my, 'Safe keys are preserved').to.be.an('object');
80
+ expect(result.__proto__, 'Keys containing __proto__ are ignored').to.be.an('undefined');
81
+ expect(result.my.key1.foo, 'Safe keys are dendrified.').to.equal('value1');
107
82
  const prototypeObject = Object.prototype as any;
108
- expect(prototypeObject.injectedParsedConstructorPrototype).to.be.an('undefined');
109
- expect(result.overrides[0].contents.__proto__).to.be.an('undefined');
83
+ expect(prototypeObject.injectedParsedConstructorPrototype, 'Object.prototype is unaffected').to.be.an('undefined');
110
84
  const rawObject = {} as any;
111
- expect(rawObject.injectedParsedConstructorPrototype).to.be.an('undefined');
85
+ expect(rawObject.injectedParsedConstructorPrototype, 'Instantiated objects are unaffected.').to.be.an('undefined');
112
86
  });
113
87
  });
114
88
 
@@ -250,6 +224,16 @@ describe('PreferenceRegistryExtImpl:', () => {
250
224
  const valuesRetrieved = preferenceRegistryExtImpl.getConfiguration(undefined, { uri: workspaceRoot, languageId: 'python' }).get('editor') as Record<string, unknown>;
251
225
  expect(valuesRetrieved.tabSize).equal(4);
252
226
  });
227
+ it('Allows access to language overrides in bracket form', () => {
228
+ const pythonOverrides = preferenceRegistryExtImpl.getConfiguration().get<Record<string, any>>('[python]');
229
+ expect(pythonOverrides).not.to.be.undefined;
230
+ expect(pythonOverrides?.['editor.renderWhitespace']).equal('all');
231
+ });
232
+ // https://github.com/eclipse-theia/theia/issues/12043
233
+ it('Allows access to preferences without specifying the section', () => {
234
+ const inspection = preferenceRegistryExtImpl.getConfiguration().inspect('editor.fontSize');
235
+ expect(inspection?.defaultValue).equal(14);
236
+ });
253
237
  });
254
238
 
255
239
  describe('Proxy Behavior', () => {
@@ -20,8 +20,8 @@ import { Emitter, Event } from '@theia/core/lib/common/event';
20
20
  import { isOSX, isWindows } from '@theia/core/lib/common/os';
21
21
  import { URI } from '@theia/core/shared/vscode-uri';
22
22
  import { ResourceMap } from '@theia/monaco-editor-core/esm/vs/base/common/map';
23
- import { IConfigurationOverrides, IOverrides } from '@theia/monaco-editor-core/esm/vs/platform/configuration/common/configuration';
24
- import { Configuration, ConfigurationModel } from '@theia/monaco-editor-core/esm/vs/platform/configuration/common/configurationModels';
23
+ import { IConfigurationOverrides } from '@theia/monaco-editor-core/esm/vs/platform/configuration/common/configuration';
24
+ import { Configuration, ConfigurationModel, ConfigurationModelParser } from '@theia/monaco-editor-core/esm/vs/platform/configuration/common/configurationModels';
25
25
  import { Workspace, WorkspaceFolder } from '@theia/monaco-editor-core/esm/vs/platform/workspace/common/workspace';
26
26
  import * as theia from '@theia/plugin';
27
27
  import { v4 } from 'uuid';
@@ -234,12 +234,12 @@ export class PreferenceRegistryExtImpl implements PreferenceRegistryExt {
234
234
  }
235
235
 
236
236
  private parse(data: PreferenceData): Configuration {
237
- const defaultConfiguration = this.getConfigurationModel(data[PreferenceScope.Default]);
238
- const userConfiguration = this.getConfigurationModel(data[PreferenceScope.User]);
239
- const workspaceConfiguration = this.getConfigurationModel(data[PreferenceScope.Workspace]);
237
+ const defaultConfiguration = this.getConfigurationModel('Default', data[PreferenceScope.Default]);
238
+ const userConfiguration = this.getConfigurationModel('User', data[PreferenceScope.User]);
239
+ const workspaceConfiguration = this.getConfigurationModel('Workspace', data[PreferenceScope.Workspace]);
240
240
  const folderConfigurations = new ResourceMap<ConfigurationModel>();
241
241
  Object.keys(data[PreferenceScope.Folder]).forEach(resource => {
242
- folderConfigurations.set(URI.parse(resource), this.getConfigurationModel(data[PreferenceScope.Folder][resource]));
242
+ folderConfigurations.set(URI.parse(resource), this.getConfigurationModel(`Folder: ${resource}`, data[PreferenceScope.Folder][resource]));
243
243
  });
244
244
  return new Configuration(
245
245
  defaultConfiguration,
@@ -252,53 +252,41 @@ export class PreferenceRegistryExtImpl implements PreferenceRegistryExt {
252
252
  );
253
253
  }
254
254
 
255
- private getConfigurationModel(data: { [key: string]: any }): ConfigurationModel {
256
- if (!data) {
257
- return new ConfigurationModel();
258
- }
259
- const configData = this.parseConfigurationData(data);
260
- return new ConfigurationModel(configData.contents, configData.keys, configData.overrides);
255
+ private getConfigurationModel(label: string, data: { [key: string]: any }): ConfigurationModel {
256
+ const parser = new ConfigurationModelParser(label);
257
+ const sanitized = this.sanitize(data);
258
+ parser.parseRaw(sanitized);
259
+ return parser.configurationModel;
261
260
  }
262
261
 
263
- private readonly OVERRIDE_PROPERTY = '^\\[(.*)\\]$';
264
- private readonly OVERRIDE_PROPERTY_PATTERN = new RegExp(this.OVERRIDE_PROPERTY);
265
- private readonly OVERRIDE_KEY_TEST = /^\[([^\]]+)\]\./;
266
-
267
- private parseConfigurationData(data: { [key: string]: any }): Omit<IOverrides, 'identifiers'> & { overrides: IOverrides[] } {
268
- const keys = new Array<string>();
269
- const overrides: Record<string, IOverrides> = Object.create(null);
270
- const contents = Object.keys(data).reduce((result: any, key: string) => {
271
- if (injectionRe.test(key)) {
272
- return result;
273
- }
274
- const parts = key.split('.');
275
- let branch = result;
276
- const isOverride = this.OVERRIDE_KEY_TEST.test(key);
277
- if (!isOverride) {
278
- keys.push(key);
279
- }
280
- for (let i = 0; i < parts.length; i++) {
281
- if (i === 0 && isOverride) {
282
- const identifier = this.OVERRIDE_PROPERTY_PATTERN.exec(parts[i])![1];
283
- if (!overrides[identifier]) {
284
- overrides[identifier] = { keys: [], identifiers: [identifier], contents: Object.create(null) };
262
+ /**
263
+ * Creates a new object and assigns those keys of raw to it that are not likely to cause prototype polution.
264
+ * Also preprocesses override identifiers so that they take the form [identifier]: {...contents}.
265
+ */
266
+ private sanitize<T = unknown>(raw: T): T {
267
+ if (!isObject(raw)) { return raw; }
268
+ const asObject = raw as Record<string, unknown>;
269
+ const sanitized = Object.create(null);
270
+ for (const key of Object.keys(asObject)) {
271
+ if (!injectionRe.test(key)) {
272
+ const override = this.OVERRIDE_KEY_TEST.exec(key);
273
+ if (override) {
274
+ const overrideKey = `[${override[1]}]`;
275
+ const remainder = key.slice(override[0].length);
276
+ if (!isObject(sanitized[overrideKey])) {
277
+ sanitized[overrideKey] = Object.create(null);
285
278
  }
286
- branch = overrides[identifier].contents;
287
- overrides[identifier].keys.push(key.slice(parts[i].length + 1));
288
- } else if (i === parts.length - 1) {
289
- branch[parts[i]] = data[key];
279
+ sanitized[overrideKey][remainder] = this.sanitize(asObject[key]);
290
280
  } else {
291
- if (!branch[parts[i]]) {
292
- branch[parts[i]] = Object.create(null);
293
- }
294
- branch = branch[parts[i]];
281
+ sanitized[key] = this.sanitize(asObject[key]);
295
282
  }
296
283
  }
297
- return result;
298
- }, Object.create(null));
299
- return { contents, keys, overrides: Object.values(overrides) };
284
+ }
285
+ return sanitized;
300
286
  }
301
287
 
288
+ private readonly OVERRIDE_KEY_TEST = /^\[([^\]]+)\]\./;
289
+
302
290
  private toConfigurationChangeEvent(eventData: PreferenceChangeExt[]): theia.ConfigurationChangeEvent {
303
291
  return Object.freeze({
304
292
  affectsConfiguration: (section: string, scope?: theia.ConfigurationScope): boolean => {
@@ -119,9 +119,9 @@ export class TextEditorsExtImpl implements TextEditorsExt {
119
119
  return new TextEditorDecorationType(this.proxy, options);
120
120
  }
121
121
 
122
- applyWorkspaceEdit(edit: theia.WorkspaceEdit): Promise<boolean> {
122
+ applyWorkspaceEdit(edit: theia.WorkspaceEdit, metadata?: theia.WorkspaceEditMetadata): Promise<boolean> {
123
123
  const dto = Converters.fromWorkspaceEdit(edit, this.editorsAndDocuments);
124
- return this.proxy.$tryApplyWorkspaceEdit(dto);
124
+ return this.proxy.$tryApplyWorkspaceEdit(dto, metadata);
125
125
  }
126
126
 
127
127
  saveAll(includeUntitled?: boolean): PromiseLike<boolean> {
@@ -1348,3 +1348,40 @@ export namespace InlayHintKind {
1348
1348
  return kind;
1349
1349
  }
1350
1350
  }
1351
+
1352
+ export namespace DataTransferItem {
1353
+ export function to(mime: string, item: model.DataTransferItemDTO, resolveFileData: (itemId: string) => Promise<Uint8Array>): theia.DataTransferItem {
1354
+ const file = item.fileData;
1355
+ if (file) {
1356
+ return new class extends types.DataTransferItem {
1357
+ override asFile(): theia.DataTransferFile {
1358
+ return {
1359
+ name: file.name,
1360
+ uri: URI.revive(file.uri),
1361
+ data: () => resolveFileData(item.id),
1362
+ };
1363
+ }
1364
+ }('');
1365
+ }
1366
+
1367
+ if (mime === 'text/uri-list' && item.uriListData) {
1368
+ return new types.DataTransferItem(reviveUriList(item.uriListData));
1369
+ }
1370
+
1371
+ return new types.DataTransferItem(item.asString);
1372
+ }
1373
+
1374
+ function reviveUriList(parts: ReadonlyArray<string | UriComponents>): string {
1375
+ return parts.map(part => typeof part === 'string' ? part : URI.revive(part).toString()).join('\r\n');
1376
+ }
1377
+ }
1378
+
1379
+ export namespace DataTransfer {
1380
+ export function toDataTransfer(value: model.DataTransferDTO, resolveFileData: (itemId: string) => Promise<Uint8Array>): theia.DataTransfer {
1381
+ const dataTransfer = new types.DataTransfer();
1382
+ for (const [mimeType, item] of value.items) {
1383
+ dataTransfer.set(mimeType, DataTransferItem.to(mimeType, item, resolveFileData));
1384
+ }
1385
+ return dataTransfer;
1386
+ }
1387
+ }
@@ -404,10 +404,13 @@ export class Position {
404
404
  return result!;
405
405
  }
406
406
 
407
- static isPosition(other: {}): other is Position {
407
+ static isPosition(other: unknown): other is Position {
408
408
  if (!other) {
409
409
  return false;
410
410
  }
411
+ if (typeof other !== 'object' || Array.isArray(other)) {
412
+ return false;
413
+ }
411
414
  if (other instanceof Position) {
412
415
  return true;
413
416
  }
@@ -1530,6 +1533,17 @@ export class DocumentLink {
1530
1533
  }
1531
1534
  }
1532
1535
 
1536
+ @es5ClassCompat
1537
+ export class DocumentDropEdit {
1538
+ insertText: string | SnippetString;
1539
+
1540
+ additionalEdit?: WorkspaceEdit;
1541
+
1542
+ constructor(insertText: string | SnippetString) {
1543
+ this.insertText = insertText;
1544
+ }
1545
+ }
1546
+
1533
1547
  @es5ClassCompat
1534
1548
  export class CodeLens {
1535
1549
 
@@ -167,8 +167,8 @@ export class WebviewViewExtImpl implements theia.WebviewView {
167
167
 
168
168
  set title(value: string | undefined) {
169
169
  this.assertNotDisposed();
170
- if (this.title !== value) {
171
- this.title = value;
170
+ if (this._title !== value) {
171
+ this._title = value;
172
172
  this.proxy.$setWebviewViewTitle(this.handle, value);
173
173
  }
174
174
  }