8110f03fbc6a6f9b69a8bd5ecaf449ee75bad11ae3811eb782d0cec842f07363d009d62fb4006a29500360a41005b213756712bc960ceb91c016d707d7a8df 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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 { distinct } from '../../../base/common/arrays.js';
  6. import { Emitter } from '../../../base/common/event.js';
  7. import * as types from '../../../base/common/types.js';
  8. import * as nls from '../../../nls.js';
  9. import { getLanguageTagSettingPlainKey } from './configuration.js';
  10. import { Extensions as JSONExtensions } from '../../jsonschemas/common/jsonContributionRegistry.js';
  11. import { Registry } from '../../registry/common/platform.js';
  12. export const Extensions = {
  13. Configuration: 'base.contributions.configuration'
  14. };
  15. export const allSettings = { properties: {}, patternProperties: {} };
  16. export const applicationSettings = { properties: {}, patternProperties: {} };
  17. export const machineSettings = { properties: {}, patternProperties: {} };
  18. export const machineOverridableSettings = { properties: {}, patternProperties: {} };
  19. export const windowSettings = { properties: {}, patternProperties: {} };
  20. export const resourceSettings = { properties: {}, patternProperties: {} };
  21. export const resourceLanguageSettingsSchemaId = 'vscode://schemas/settings/resourceLanguage';
  22. const contributionRegistry = Registry.as(JSONExtensions.JSONContribution);
  23. class ConfigurationRegistry {
  24. constructor() {
  25. this.overrideIdentifiers = new Set();
  26. this._onDidSchemaChange = new Emitter();
  27. this._onDidUpdateConfiguration = new Emitter();
  28. this.configurationDefaultsOverrides = new Map();
  29. this.defaultLanguageConfigurationOverridesNode = {
  30. id: 'defaultOverrides',
  31. title: nls.localize('defaultLanguageConfigurationOverrides.title', "Default Language Configuration Overrides"),
  32. properties: {}
  33. };
  34. this.configurationContributors = [this.defaultLanguageConfigurationOverridesNode];
  35. this.resourceLanguageSettingsSchema = { properties: {}, patternProperties: {}, additionalProperties: false, errorMessage: 'Unknown editor configuration setting', allowTrailingCommas: true, allowComments: true };
  36. this.configurationProperties = {};
  37. this.policyConfigurations = new Map();
  38. this.excludedConfigurationProperties = {};
  39. contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
  40. this.registerOverridePropertyPatternKey();
  41. }
  42. registerConfiguration(configuration, validate = true) {
  43. this.registerConfigurations([configuration], validate);
  44. }
  45. registerConfigurations(configurations, validate = true) {
  46. const properties = this.doRegisterConfigurations(configurations, validate);
  47. contributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);
  48. this._onDidSchemaChange.fire();
  49. this._onDidUpdateConfiguration.fire({ properties });
  50. }
  51. registerDefaultConfigurations(configurationDefaults) {
  52. var _a;
  53. const properties = [];
  54. const overrideIdentifiers = [];
  55. for (const { overrides, source } of configurationDefaults) {
  56. for (const key in overrides) {
  57. properties.push(key);
  58. if (OVERRIDE_PROPERTY_REGEX.test(key)) {
  59. const configurationDefaultOverride = this.configurationDefaultsOverrides.get(key);
  60. const valuesSources = (_a = configurationDefaultOverride === null || configurationDefaultOverride === void 0 ? void 0 : configurationDefaultOverride.valuesSources) !== null && _a !== void 0 ? _a : new Map();
  61. if (source) {
  62. for (const configuration of Object.keys(overrides[key])) {
  63. valuesSources.set(configuration, source);
  64. }
  65. }
  66. const defaultValue = Object.assign(Object.assign({}, ((configurationDefaultOverride === null || configurationDefaultOverride === void 0 ? void 0 : configurationDefaultOverride.value) || {})), overrides[key]);
  67. this.configurationDefaultsOverrides.set(key, { source, value: defaultValue, valuesSources });
  68. const plainKey = getLanguageTagSettingPlainKey(key);
  69. const property = {
  70. type: 'object',
  71. default: defaultValue,
  72. description: nls.localize('defaultLanguageConfiguration.description', "Configure settings to be overridden for the {0} language.", plainKey),
  73. $ref: resourceLanguageSettingsSchemaId,
  74. defaultDefaultValue: defaultValue,
  75. source: types.isString(source) ? undefined : source,
  76. defaultValueSource: source
  77. };
  78. overrideIdentifiers.push(...overrideIdentifiersFromKey(key));
  79. this.configurationProperties[key] = property;
  80. this.defaultLanguageConfigurationOverridesNode.properties[key] = property;
  81. }
  82. else {
  83. this.configurationDefaultsOverrides.set(key, { value: overrides[key], source });
  84. const property = this.configurationProperties[key];
  85. if (property) {
  86. this.updatePropertyDefaultValue(key, property);
  87. this.updateSchema(key, property);
  88. }
  89. }
  90. }
  91. }
  92. this.registerOverrideIdentifiers(overrideIdentifiers);
  93. this._onDidSchemaChange.fire();
  94. this._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });
  95. }
  96. registerOverrideIdentifiers(overrideIdentifiers) {
  97. for (const overrideIdentifier of overrideIdentifiers) {
  98. this.overrideIdentifiers.add(overrideIdentifier);
  99. }
  100. this.updateOverridePropertyPatternKey();
  101. }
  102. doRegisterConfigurations(configurations, validate) {
  103. const properties = [];
  104. configurations.forEach(configuration => {
  105. properties.push(...this.validateAndRegisterProperties(configuration, validate, configuration.extensionInfo, configuration.restrictedProperties)); // fills in defaults
  106. this.configurationContributors.push(configuration);
  107. this.registerJSONConfiguration(configuration);
  108. });
  109. return properties;
  110. }
  111. validateAndRegisterProperties(configuration, validate = true, extensionInfo, restrictedProperties, scope = 3 /* ConfigurationScope.WINDOW */) {
  112. var _a;
  113. scope = types.isUndefinedOrNull(configuration.scope) ? scope : configuration.scope;
  114. const propertyKeys = [];
  115. const properties = configuration.properties;
  116. if (properties) {
  117. for (const key in properties) {
  118. const property = properties[key];
  119. if (validate && validateProperty(key, property)) {
  120. delete properties[key];
  121. continue;
  122. }
  123. property.source = extensionInfo;
  124. // update default value
  125. property.defaultDefaultValue = properties[key].default;
  126. this.updatePropertyDefaultValue(key, property);
  127. // update scope
  128. if (OVERRIDE_PROPERTY_REGEX.test(key)) {
  129. property.scope = undefined; // No scope for overridable properties `[${identifier}]`
  130. }
  131. else {
  132. property.scope = types.isUndefinedOrNull(property.scope) ? scope : property.scope;
  133. property.restricted = types.isUndefinedOrNull(property.restricted) ? !!(restrictedProperties === null || restrictedProperties === void 0 ? void 0 : restrictedProperties.includes(key)) : property.restricted;
  134. }
  135. // Add to properties maps
  136. // Property is included by default if 'included' is unspecified
  137. if (properties[key].hasOwnProperty('included') && !properties[key].included) {
  138. this.excludedConfigurationProperties[key] = properties[key];
  139. delete properties[key];
  140. continue;
  141. }
  142. else {
  143. this.configurationProperties[key] = properties[key];
  144. if ((_a = properties[key].policy) === null || _a === void 0 ? void 0 : _a.name) {
  145. this.policyConfigurations.set(properties[key].policy.name, key);
  146. }
  147. }
  148. if (!properties[key].deprecationMessage && properties[key].markdownDeprecationMessage) {
  149. // If not set, default deprecationMessage to the markdown source
  150. properties[key].deprecationMessage = properties[key].markdownDeprecationMessage;
  151. }
  152. propertyKeys.push(key);
  153. }
  154. }
  155. const subNodes = configuration.allOf;
  156. if (subNodes) {
  157. for (const node of subNodes) {
  158. propertyKeys.push(...this.validateAndRegisterProperties(node, validate, extensionInfo, restrictedProperties, scope));
  159. }
  160. }
  161. return propertyKeys;
  162. }
  163. getConfigurationProperties() {
  164. return this.configurationProperties;
  165. }
  166. getPolicyConfigurations() {
  167. return this.policyConfigurations;
  168. }
  169. registerJSONConfiguration(configuration) {
  170. const register = (configuration) => {
  171. const properties = configuration.properties;
  172. if (properties) {
  173. for (const key in properties) {
  174. this.updateSchema(key, properties[key]);
  175. }
  176. }
  177. const subNodes = configuration.allOf;
  178. subNodes === null || subNodes === void 0 ? void 0 : subNodes.forEach(register);
  179. };
  180. register(configuration);
  181. }
  182. updateSchema(key, property) {
  183. allSettings.properties[key] = property;
  184. switch (property.scope) {
  185. case 1 /* ConfigurationScope.APPLICATION */:
  186. applicationSettings.properties[key] = property;
  187. break;
  188. case 2 /* ConfigurationScope.MACHINE */:
  189. machineSettings.properties[key] = property;
  190. break;
  191. case 6 /* ConfigurationScope.MACHINE_OVERRIDABLE */:
  192. machineOverridableSettings.properties[key] = property;
  193. break;
  194. case 3 /* ConfigurationScope.WINDOW */:
  195. windowSettings.properties[key] = property;
  196. break;
  197. case 4 /* ConfigurationScope.RESOURCE */:
  198. resourceSettings.properties[key] = property;
  199. break;
  200. case 5 /* ConfigurationScope.LANGUAGE_OVERRIDABLE */:
  201. resourceSettings.properties[key] = property;
  202. this.resourceLanguageSettingsSchema.properties[key] = property;
  203. break;
  204. }
  205. }
  206. updateOverridePropertyPatternKey() {
  207. for (const overrideIdentifier of this.overrideIdentifiers.values()) {
  208. const overrideIdentifierProperty = `[${overrideIdentifier}]`;
  209. const resourceLanguagePropertiesSchema = {
  210. type: 'object',
  211. description: nls.localize('overrideSettings.defaultDescription', "Configure editor settings to be overridden for a language."),
  212. errorMessage: nls.localize('overrideSettings.errorMessage', "This setting does not support per-language configuration."),
  213. $ref: resourceLanguageSettingsSchemaId,
  214. };
  215. this.updatePropertyDefaultValue(overrideIdentifierProperty, resourceLanguagePropertiesSchema);
  216. allSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
  217. applicationSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
  218. machineSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
  219. machineOverridableSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
  220. windowSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
  221. resourceSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;
  222. }
  223. this._onDidSchemaChange.fire();
  224. }
  225. registerOverridePropertyPatternKey() {
  226. const resourceLanguagePropertiesSchema = {
  227. type: 'object',
  228. description: nls.localize('overrideSettings.defaultDescription', "Configure editor settings to be overridden for a language."),
  229. errorMessage: nls.localize('overrideSettings.errorMessage', "This setting does not support per-language configuration."),
  230. $ref: resourceLanguageSettingsSchemaId,
  231. };
  232. allSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
  233. applicationSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
  234. machineSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
  235. machineOverridableSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
  236. windowSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
  237. resourceSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;
  238. this._onDidSchemaChange.fire();
  239. }
  240. updatePropertyDefaultValue(key, property) {
  241. const configurationdefaultOverride = this.configurationDefaultsOverrides.get(key);
  242. let defaultValue = configurationdefaultOverride === null || configurationdefaultOverride === void 0 ? void 0 : configurationdefaultOverride.value;
  243. let defaultSource = configurationdefaultOverride === null || configurationdefaultOverride === void 0 ? void 0 : configurationdefaultOverride.source;
  244. if (types.isUndefined(defaultValue)) {
  245. defaultValue = property.defaultDefaultValue;
  246. defaultSource = undefined;
  247. }
  248. if (types.isUndefined(defaultValue)) {
  249. defaultValue = getDefaultValue(property.type);
  250. }
  251. property.default = defaultValue;
  252. property.defaultValueSource = defaultSource;
  253. }
  254. }
  255. const OVERRIDE_IDENTIFIER_PATTERN = `\\[([^\\]]+)\\]`;
  256. const OVERRIDE_IDENTIFIER_REGEX = new RegExp(OVERRIDE_IDENTIFIER_PATTERN, 'g');
  257. export const OVERRIDE_PROPERTY_PATTERN = `^(${OVERRIDE_IDENTIFIER_PATTERN})+$`;
  258. export const OVERRIDE_PROPERTY_REGEX = new RegExp(OVERRIDE_PROPERTY_PATTERN);
  259. export function overrideIdentifiersFromKey(key) {
  260. const identifiers = [];
  261. if (OVERRIDE_PROPERTY_REGEX.test(key)) {
  262. let matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
  263. while (matches === null || matches === void 0 ? void 0 : matches.length) {
  264. const identifier = matches[1].trim();
  265. if (identifier) {
  266. identifiers.push(identifier);
  267. }
  268. matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);
  269. }
  270. }
  271. return distinct(identifiers);
  272. }
  273. export function getDefaultValue(type) {
  274. const t = Array.isArray(type) ? type[0] : type;
  275. switch (t) {
  276. case 'boolean':
  277. return false;
  278. case 'integer':
  279. case 'number':
  280. return 0;
  281. case 'string':
  282. return '';
  283. case 'array':
  284. return [];
  285. case 'object':
  286. return {};
  287. default:
  288. return null;
  289. }
  290. }
  291. const configurationRegistry = new ConfigurationRegistry();
  292. Registry.add(Extensions.Configuration, configurationRegistry);
  293. export function validateProperty(property, schema) {
  294. var _a, _b, _c, _d;
  295. if (!property.trim()) {
  296. return nls.localize('config.property.empty', "Cannot register an empty property");
  297. }
  298. if (OVERRIDE_PROPERTY_REGEX.test(property)) {
  299. return nls.localize('config.property.languageDefault', "Cannot register '{0}'. This matches property pattern '\\\\[.*\\\\]$' for describing language specific editor settings. Use 'configurationDefaults' contribution.", property);
  300. }
  301. if (configurationRegistry.getConfigurationProperties()[property] !== undefined) {
  302. return nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", property);
  303. }
  304. if (((_a = schema.policy) === null || _a === void 0 ? void 0 : _a.name) && configurationRegistry.getPolicyConfigurations().get((_b = schema.policy) === null || _b === void 0 ? void 0 : _b.name) !== undefined) {
  305. return nls.localize('config.policy.duplicate', "Cannot register '{0}'. The associated policy {1} is already registered with {2}.", property, (_c = schema.policy) === null || _c === void 0 ? void 0 : _c.name, configurationRegistry.getPolicyConfigurations().get((_d = schema.policy) === null || _d === void 0 ? void 0 : _d.name));
  306. }
  307. return null;
  308. }