7f9ea309571664d6bbbaf4146e79a988c51c2649707f8a2207052eb0f384dbddf2d78872ee0d1204cb24b6d797ca70e3d21d12263bc9a922f8b2430e65eb87 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import * as arrays from '../../../base/common/arrays.js';
  6. import { ResourceMap } from '../../../base/common/map.js';
  7. import * as objects from '../../../base/common/objects.js';
  8. import * as types from '../../../base/common/types.js';
  9. import { URI } from '../../../base/common/uri.js';
  10. import { addToValueTree, getConfigurationValue, removeFromValueTree, toValuesTree } from './configuration.js';
  11. export class ConfigurationModel {
  12. constructor(_contents = {}, _keys = [], _overrides = []) {
  13. this._contents = _contents;
  14. this._keys = _keys;
  15. this._overrides = _overrides;
  16. this.frozen = false;
  17. this.overrideConfigurations = new Map();
  18. }
  19. get contents() {
  20. return this.checkAndFreeze(this._contents);
  21. }
  22. get overrides() {
  23. return this.checkAndFreeze(this._overrides);
  24. }
  25. get keys() {
  26. return this.checkAndFreeze(this._keys);
  27. }
  28. isEmpty() {
  29. return this._keys.length === 0 && Object.keys(this._contents).length === 0 && this._overrides.length === 0;
  30. }
  31. getValue(section) {
  32. return section ? getConfigurationValue(this.contents, section) : this.contents;
  33. }
  34. getOverrideValue(section, overrideIdentifier) {
  35. const overrideContents = this.getContentsForOverrideIdentifer(overrideIdentifier);
  36. return overrideContents
  37. ? section ? getConfigurationValue(overrideContents, section) : overrideContents
  38. : undefined;
  39. }
  40. override(identifier) {
  41. let overrideConfigurationModel = this.overrideConfigurations.get(identifier);
  42. if (!overrideConfigurationModel) {
  43. overrideConfigurationModel = this.createOverrideConfigurationModel(identifier);
  44. this.overrideConfigurations.set(identifier, overrideConfigurationModel);
  45. }
  46. return overrideConfigurationModel;
  47. }
  48. merge(...others) {
  49. const contents = objects.deepClone(this.contents);
  50. const overrides = objects.deepClone(this.overrides);
  51. const keys = [...this.keys];
  52. for (const other of others) {
  53. if (other.isEmpty()) {
  54. continue;
  55. }
  56. this.mergeContents(contents, other.contents);
  57. for (const otherOverride of other.overrides) {
  58. const [override] = overrides.filter(o => arrays.equals(o.identifiers, otherOverride.identifiers));
  59. if (override) {
  60. this.mergeContents(override.contents, otherOverride.contents);
  61. override.keys.push(...otherOverride.keys);
  62. override.keys = arrays.distinct(override.keys);
  63. }
  64. else {
  65. overrides.push(objects.deepClone(otherOverride));
  66. }
  67. }
  68. for (const key of other.keys) {
  69. if (keys.indexOf(key) === -1) {
  70. keys.push(key);
  71. }
  72. }
  73. }
  74. return new ConfigurationModel(contents, keys, overrides);
  75. }
  76. freeze() {
  77. this.frozen = true;
  78. return this;
  79. }
  80. createOverrideConfigurationModel(identifier) {
  81. const overrideContents = this.getContentsForOverrideIdentifer(identifier);
  82. if (!overrideContents || typeof overrideContents !== 'object' || !Object.keys(overrideContents).length) {
  83. // If there are no valid overrides, return self
  84. return this;
  85. }
  86. const contents = {};
  87. for (const key of arrays.distinct([...Object.keys(this.contents), ...Object.keys(overrideContents)])) {
  88. let contentsForKey = this.contents[key];
  89. const overrideContentsForKey = overrideContents[key];
  90. // If there are override contents for the key, clone and merge otherwise use base contents
  91. if (overrideContentsForKey) {
  92. // Clone and merge only if base contents and override contents are of type object otherwise just override
  93. if (typeof contentsForKey === 'object' && typeof overrideContentsForKey === 'object') {
  94. contentsForKey = objects.deepClone(contentsForKey);
  95. this.mergeContents(contentsForKey, overrideContentsForKey);
  96. }
  97. else {
  98. contentsForKey = overrideContentsForKey;
  99. }
  100. }
  101. contents[key] = contentsForKey;
  102. }
  103. return new ConfigurationModel(contents, this.keys, this.overrides);
  104. }
  105. mergeContents(source, target) {
  106. for (const key of Object.keys(target)) {
  107. if (key in source) {
  108. if (types.isObject(source[key]) && types.isObject(target[key])) {
  109. this.mergeContents(source[key], target[key]);
  110. continue;
  111. }
  112. }
  113. source[key] = objects.deepClone(target[key]);
  114. }
  115. }
  116. checkAndFreeze(data) {
  117. if (this.frozen && !Object.isFrozen(data)) {
  118. return objects.deepFreeze(data);
  119. }
  120. return data;
  121. }
  122. getContentsForOverrideIdentifer(identifier) {
  123. let contentsForIdentifierOnly = null;
  124. let contents = null;
  125. const mergeContents = (contentsToMerge) => {
  126. if (contentsToMerge) {
  127. if (contents) {
  128. this.mergeContents(contents, contentsToMerge);
  129. }
  130. else {
  131. contents = objects.deepClone(contentsToMerge);
  132. }
  133. }
  134. };
  135. for (const override of this.overrides) {
  136. if (arrays.equals(override.identifiers, [identifier])) {
  137. contentsForIdentifierOnly = override.contents;
  138. }
  139. else if (override.identifiers.includes(identifier)) {
  140. mergeContents(override.contents);
  141. }
  142. }
  143. // Merge contents of the identifier only at the end to take precedence.
  144. mergeContents(contentsForIdentifierOnly);
  145. return contents;
  146. }
  147. toJSON() {
  148. return {
  149. contents: this.contents,
  150. overrides: this.overrides,
  151. keys: this.keys
  152. };
  153. }
  154. // Update methods
  155. setValue(key, value) {
  156. this.addKey(key);
  157. addToValueTree(this.contents, key, value, e => { throw new Error(e); });
  158. }
  159. removeValue(key) {
  160. if (this.removeKey(key)) {
  161. removeFromValueTree(this.contents, key);
  162. }
  163. }
  164. addKey(key) {
  165. let index = this.keys.length;
  166. for (let i = 0; i < index; i++) {
  167. if (key.indexOf(this.keys[i]) === 0) {
  168. index = i;
  169. }
  170. }
  171. this.keys.splice(index, 1, key);
  172. }
  173. removeKey(key) {
  174. const index = this.keys.indexOf(key);
  175. if (index !== -1) {
  176. this.keys.splice(index, 1);
  177. return true;
  178. }
  179. return false;
  180. }
  181. }
  182. export class Configuration {
  183. constructor(_defaultConfiguration, _policyConfiguration, _applicationConfiguration, _localUserConfiguration, _remoteUserConfiguration = new ConfigurationModel(), _workspaceConfiguration = new ConfigurationModel(), _folderConfigurations = new ResourceMap(), _memoryConfiguration = new ConfigurationModel(), _memoryConfigurationByResource = new ResourceMap(), _freeze = true) {
  184. this._defaultConfiguration = _defaultConfiguration;
  185. this._policyConfiguration = _policyConfiguration;
  186. this._applicationConfiguration = _applicationConfiguration;
  187. this._localUserConfiguration = _localUserConfiguration;
  188. this._remoteUserConfiguration = _remoteUserConfiguration;
  189. this._workspaceConfiguration = _workspaceConfiguration;
  190. this._folderConfigurations = _folderConfigurations;
  191. this._memoryConfiguration = _memoryConfiguration;
  192. this._memoryConfigurationByResource = _memoryConfigurationByResource;
  193. this._freeze = _freeze;
  194. this._workspaceConsolidatedConfiguration = null;
  195. this._foldersConsolidatedConfigurations = new ResourceMap();
  196. this._userConfiguration = null;
  197. }
  198. getValue(section, overrides, workspace) {
  199. const consolidateConfigurationModel = this.getConsolidatedConfigurationModel(section, overrides, workspace);
  200. return consolidateConfigurationModel.getValue(section);
  201. }
  202. updateValue(key, value, overrides = {}) {
  203. let memoryConfiguration;
  204. if (overrides.resource) {
  205. memoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource);
  206. if (!memoryConfiguration) {
  207. memoryConfiguration = new ConfigurationModel();
  208. this._memoryConfigurationByResource.set(overrides.resource, memoryConfiguration);
  209. }
  210. }
  211. else {
  212. memoryConfiguration = this._memoryConfiguration;
  213. }
  214. if (value === undefined) {
  215. memoryConfiguration.removeValue(key);
  216. }
  217. else {
  218. memoryConfiguration.setValue(key, value);
  219. }
  220. if (!overrides.resource) {
  221. this._workspaceConsolidatedConfiguration = null;
  222. }
  223. }
  224. inspect(key, overrides, workspace) {
  225. const consolidateConfigurationModel = this.getConsolidatedConfigurationModel(key, overrides, workspace);
  226. const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace);
  227. const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration;
  228. const defaultValue = overrides.overrideIdentifier ? this._defaultConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._defaultConfiguration.freeze().getValue(key);
  229. const policyValue = this._policyConfiguration.isEmpty() ? undefined : this._policyConfiguration.freeze().getValue(key);
  230. const applicationValue = this.applicationConfiguration.isEmpty() ? undefined : this.applicationConfiguration.freeze().getValue(key);
  231. const userValue = overrides.overrideIdentifier ? this.userConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.userConfiguration.freeze().getValue(key);
  232. const userLocalValue = overrides.overrideIdentifier ? this.localUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.localUserConfiguration.freeze().getValue(key);
  233. const userRemoteValue = overrides.overrideIdentifier ? this.remoteUserConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this.remoteUserConfiguration.freeze().getValue(key);
  234. const workspaceValue = workspace ? overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._workspaceConfiguration.freeze().getValue(key) : undefined; //Check on workspace exists or not because _workspaceConfiguration is never null
  235. const workspaceFolderValue = folderConfigurationModel ? overrides.overrideIdentifier ? folderConfigurationModel.freeze().override(overrides.overrideIdentifier).getValue(key) : folderConfigurationModel.freeze().getValue(key) : undefined;
  236. const memoryValue = overrides.overrideIdentifier ? memoryConfigurationModel.override(overrides.overrideIdentifier).getValue(key) : memoryConfigurationModel.getValue(key);
  237. const value = consolidateConfigurationModel.getValue(key);
  238. const overrideIdentifiers = arrays.distinct(consolidateConfigurationModel.overrides.map(override => override.identifiers).flat()).filter(overrideIdentifier => consolidateConfigurationModel.getOverrideValue(key, overrideIdentifier) !== undefined);
  239. return {
  240. defaultValue,
  241. policyValue,
  242. applicationValue,
  243. userValue,
  244. userLocalValue,
  245. userRemoteValue,
  246. workspaceValue,
  247. workspaceFolderValue,
  248. memoryValue,
  249. value,
  250. default: defaultValue !== undefined ? { value: this._defaultConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this._defaultConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  251. policy: policyValue !== undefined ? { value: policyValue } : undefined,
  252. application: applicationValue !== undefined ? { value: applicationValue, override: overrides.overrideIdentifier ? this.applicationConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  253. user: userValue !== undefined ? { value: this.userConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.userConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  254. userLocal: userLocalValue !== undefined ? { value: this.localUserConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.localUserConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  255. userRemote: userRemoteValue !== undefined ? { value: this.remoteUserConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this.remoteUserConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  256. workspace: workspaceValue !== undefined ? { value: this._workspaceConfiguration.freeze().getValue(key), override: overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  257. workspaceFolder: workspaceFolderValue !== undefined ? { value: folderConfigurationModel === null || folderConfigurationModel === void 0 ? void 0 : folderConfigurationModel.freeze().getValue(key), override: overrides.overrideIdentifier ? folderConfigurationModel === null || folderConfigurationModel === void 0 ? void 0 : folderConfigurationModel.freeze().getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  258. memory: memoryValue !== undefined ? { value: memoryConfigurationModel.getValue(key), override: overrides.overrideIdentifier ? memoryConfigurationModel.getOverrideValue(key, overrides.overrideIdentifier) : undefined } : undefined,
  259. overrideIdentifiers: overrideIdentifiers.length ? overrideIdentifiers : undefined
  260. };
  261. }
  262. get applicationConfiguration() {
  263. return this._applicationConfiguration;
  264. }
  265. get userConfiguration() {
  266. if (!this._userConfiguration) {
  267. this._userConfiguration = this._remoteUserConfiguration.isEmpty() ? this._localUserConfiguration : this._localUserConfiguration.merge(this._remoteUserConfiguration);
  268. if (this._freeze) {
  269. this._userConfiguration.freeze();
  270. }
  271. }
  272. return this._userConfiguration;
  273. }
  274. get localUserConfiguration() {
  275. return this._localUserConfiguration;
  276. }
  277. get remoteUserConfiguration() {
  278. return this._remoteUserConfiguration;
  279. }
  280. getConsolidatedConfigurationModel(section, overrides, workspace) {
  281. let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace);
  282. if (overrides.overrideIdentifier) {
  283. configurationModel = configurationModel.override(overrides.overrideIdentifier);
  284. }
  285. if (!this._policyConfiguration.isEmpty() && this._policyConfiguration.getValue(section) !== undefined) {
  286. configurationModel = configurationModel.merge(this._policyConfiguration);
  287. }
  288. return configurationModel;
  289. }
  290. getConsolidatedConfigurationModelForResource({ resource }, workspace) {
  291. let consolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
  292. if (workspace && resource) {
  293. const root = workspace.getFolder(resource);
  294. if (root) {
  295. consolidateConfiguration = this.getFolderConsolidatedConfiguration(root.uri) || consolidateConfiguration;
  296. }
  297. const memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource);
  298. if (memoryConfigurationForResource) {
  299. consolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource);
  300. }
  301. }
  302. return consolidateConfiguration;
  303. }
  304. getWorkspaceConsolidatedConfiguration() {
  305. if (!this._workspaceConsolidatedConfiguration) {
  306. this._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.applicationConfiguration, this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);
  307. if (this._freeze) {
  308. this._workspaceConfiguration = this._workspaceConfiguration.freeze();
  309. }
  310. }
  311. return this._workspaceConsolidatedConfiguration;
  312. }
  313. getFolderConsolidatedConfiguration(folder) {
  314. let folderConsolidatedConfiguration = this._foldersConsolidatedConfigurations.get(folder);
  315. if (!folderConsolidatedConfiguration) {
  316. const workspaceConsolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
  317. const folderConfiguration = this._folderConfigurations.get(folder);
  318. if (folderConfiguration) {
  319. folderConsolidatedConfiguration = workspaceConsolidateConfiguration.merge(folderConfiguration);
  320. if (this._freeze) {
  321. folderConsolidatedConfiguration = folderConsolidatedConfiguration.freeze();
  322. }
  323. this._foldersConsolidatedConfigurations.set(folder, folderConsolidatedConfiguration);
  324. }
  325. else {
  326. folderConsolidatedConfiguration = workspaceConsolidateConfiguration;
  327. }
  328. }
  329. return folderConsolidatedConfiguration;
  330. }
  331. getFolderConfigurationModelForResource(resource, workspace) {
  332. if (workspace && resource) {
  333. const root = workspace.getFolder(resource);
  334. if (root) {
  335. return this._folderConfigurations.get(root.uri);
  336. }
  337. }
  338. return undefined;
  339. }
  340. toData() {
  341. return {
  342. defaults: {
  343. contents: this._defaultConfiguration.contents,
  344. overrides: this._defaultConfiguration.overrides,
  345. keys: this._defaultConfiguration.keys
  346. },
  347. policy: {
  348. contents: this._policyConfiguration.contents,
  349. overrides: this._policyConfiguration.overrides,
  350. keys: this._policyConfiguration.keys
  351. },
  352. application: {
  353. contents: this.applicationConfiguration.contents,
  354. overrides: this.applicationConfiguration.overrides,
  355. keys: this.applicationConfiguration.keys
  356. },
  357. user: {
  358. contents: this.userConfiguration.contents,
  359. overrides: this.userConfiguration.overrides,
  360. keys: this.userConfiguration.keys
  361. },
  362. workspace: {
  363. contents: this._workspaceConfiguration.contents,
  364. overrides: this._workspaceConfiguration.overrides,
  365. keys: this._workspaceConfiguration.keys
  366. },
  367. folders: [...this._folderConfigurations.keys()].reduce((result, folder) => {
  368. const { contents, overrides, keys } = this._folderConfigurations.get(folder);
  369. result.push([folder, { contents, overrides, keys }]);
  370. return result;
  371. }, [])
  372. };
  373. }
  374. static parse(data) {
  375. const defaultConfiguration = this.parseConfigurationModel(data.defaults);
  376. const policyConfiguration = this.parseConfigurationModel(data.policy);
  377. const applicationConfiguration = this.parseConfigurationModel(data.application);
  378. const userConfiguration = this.parseConfigurationModel(data.user);
  379. const workspaceConfiguration = this.parseConfigurationModel(data.workspace);
  380. const folders = data.folders.reduce((result, value) => {
  381. result.set(URI.revive(value[0]), this.parseConfigurationModel(value[1]));
  382. return result;
  383. }, new ResourceMap());
  384. return new Configuration(defaultConfiguration, policyConfiguration, applicationConfiguration, userConfiguration, new ConfigurationModel(), workspaceConfiguration, folders, new ConfigurationModel(), new ResourceMap(), false);
  385. }
  386. static parseConfigurationModel(model) {
  387. return new ConfigurationModel(model.contents, model.keys, model.overrides).freeze();
  388. }
  389. }
  390. export class ConfigurationChangeEvent {
  391. constructor(change, previous, currentConfiguraiton, currentWorkspace) {
  392. this.change = change;
  393. this.previous = previous;
  394. this.currentConfiguraiton = currentConfiguraiton;
  395. this.currentWorkspace = currentWorkspace;
  396. this._previousConfiguration = undefined;
  397. const keysSet = new Set();
  398. change.keys.forEach(key => keysSet.add(key));
  399. change.overrides.forEach(([, keys]) => keys.forEach(key => keysSet.add(key)));
  400. this.affectedKeys = [...keysSet.values()];
  401. const configurationModel = new ConfigurationModel();
  402. this.affectedKeys.forEach(key => configurationModel.setValue(key, {}));
  403. this.affectedKeysTree = configurationModel.contents;
  404. }
  405. get previousConfiguration() {
  406. if (!this._previousConfiguration && this.previous) {
  407. this._previousConfiguration = Configuration.parse(this.previous.data);
  408. }
  409. return this._previousConfiguration;
  410. }
  411. affectsConfiguration(section, overrides) {
  412. var _a;
  413. if (this.doesAffectedKeysTreeContains(this.affectedKeysTree, section)) {
  414. if (overrides) {
  415. const value1 = this.previousConfiguration ? this.previousConfiguration.getValue(section, overrides, (_a = this.previous) === null || _a === void 0 ? void 0 : _a.workspace) : undefined;
  416. const value2 = this.currentConfiguraiton.getValue(section, overrides, this.currentWorkspace);
  417. return !objects.equals(value1, value2);
  418. }
  419. return true;
  420. }
  421. return false;
  422. }
  423. doesAffectedKeysTreeContains(affectedKeysTree, section) {
  424. let requestedTree = toValuesTree({ [section]: true }, () => { });
  425. let key;
  426. while (typeof requestedTree === 'object' && (key = Object.keys(requestedTree)[0])) { // Only one key should present, since we added only one property
  427. affectedKeysTree = affectedKeysTree[key];
  428. if (!affectedKeysTree) {
  429. return false; // Requested tree is not found
  430. }
  431. requestedTree = requestedTree[key];
  432. }
  433. return true;
  434. }
  435. }