diff --git a/src/vs/workbench/api/common/configurationExtensionPoint.ts b/src/vs/workbench/api/common/configurationExtensionPoint.ts index 75476f2f82d..b3d1b380775 100644 --- a/src/vs/workbench/api/common/configurationExtensionPoint.ts +++ b/src/vs/workbench/api/common/configurationExtensionPoint.ts @@ -159,6 +159,8 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => { configurationRegistry.deregisterConfigurations(removedConfigurations); } + const seenProperties = new Set(); + function handleConfiguration(node: IConfigurationNode, extension: IExtensionPointUser): IConfigurationNode[] { const configurations: IConfigurationNode[] = []; let configuration = objects.deepClone(node); @@ -176,6 +178,60 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => { return configurations; } + function validateProperties(configuration: IConfigurationNode, extension: IExtensionPointUser): void { + let properties = configuration.properties; + if (properties) { + if (typeof properties !== 'object') { + extension.collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object")); + configuration.properties = {}; + } + for (let key in properties) { + const message = validateProperty(key); + if (message) { + delete properties[key]; + extension.collector.warn(message); + continue; + } + if (seenProperties.has(key)) { + delete properties[key]; + extension.collector.warn(nls.localize('config.property.duplicate', "Cannot register '{0}'. This property is already registered.", key)); + continue; + } + const propertyConfiguration = properties[key]; + if (!isObject(propertyConfiguration)) { + delete properties[key]; + extension.collector.error(nls.localize('invalid.property', "configuration.properties property '{0}' must be an object", key)); + continue; + } + seenProperties.add(key); + if (propertyConfiguration.scope) { + if (propertyConfiguration.scope.toString() === 'application') { + propertyConfiguration.scope = ConfigurationScope.APPLICATION; + } else if (propertyConfiguration.scope.toString() === 'machine') { + propertyConfiguration.scope = ConfigurationScope.MACHINE; + } else if (propertyConfiguration.scope.toString() === 'resource') { + propertyConfiguration.scope = ConfigurationScope.RESOURCE; + } else if (propertyConfiguration.scope.toString() === 'machine-overridable') { + propertyConfiguration.scope = ConfigurationScope.MACHINE_OVERRIDABLE; + } else if (propertyConfiguration.scope.toString() === 'language-overridable') { + propertyConfiguration.scope = ConfigurationScope.LANGUAGE_OVERRIDABLE; + } else { + propertyConfiguration.scope = ConfigurationScope.WINDOW; + } + } else { + propertyConfiguration.scope = ConfigurationScope.WINDOW; + } + } + } + let subNodes = configuration.allOf; + if (subNodes) { + extension.collector.error(nls.localize('invalid.allOf', "'configuration.allOf' is deprecated and should no longer be used. Instead, pass multiple configuration sections as an array to the 'configuration' contribution point.")); + for (let node of subNodes) { + validateProperties(node, extension); + } + } + } + if (added.length) { const addedConfigurations: IConfigurationNode[] = []; for (let extension of added) { @@ -196,54 +252,6 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => { }); // END VSCode extension point `configuration` -function validateProperties(configuration: IConfigurationNode, extension: IExtensionPointUser): void { - let properties = configuration.properties; - if (properties) { - if (typeof properties !== 'object') { - extension.collector.error(nls.localize('invalid.properties', "'configuration.properties' must be an object")); - configuration.properties = {}; - } - for (let key in properties) { - const message = validateProperty(key); - if (message) { - delete properties[key]; - extension.collector.warn(message); - continue; - } - const propertyConfiguration = properties[key]; - if (!isObject(propertyConfiguration)) { - delete properties[key]; - extension.collector.error(nls.localize('invalid.property', "configuration.properties property '{0}' must be an object", key)); - continue; - } - if (propertyConfiguration.scope) { - if (propertyConfiguration.scope.toString() === 'application') { - propertyConfiguration.scope = ConfigurationScope.APPLICATION; - } else if (propertyConfiguration.scope.toString() === 'machine') { - propertyConfiguration.scope = ConfigurationScope.MACHINE; - } else if (propertyConfiguration.scope.toString() === 'resource') { - propertyConfiguration.scope = ConfigurationScope.RESOURCE; - } else if (propertyConfiguration.scope.toString() === 'machine-overridable') { - propertyConfiguration.scope = ConfigurationScope.MACHINE_OVERRIDABLE; - } else if (propertyConfiguration.scope.toString() === 'language-overridable') { - propertyConfiguration.scope = ConfigurationScope.LANGUAGE_OVERRIDABLE; - } else { - propertyConfiguration.scope = ConfigurationScope.WINDOW; - } - } else { - propertyConfiguration.scope = ConfigurationScope.WINDOW; - } - } - } - let subNodes = configuration.allOf; - if (subNodes) { - extension.collector.error(nls.localize('invalid.allOf', "'configuration.allOf' is deprecated and should no longer be used. Instead, pass multiple configuration sections as an array to the 'configuration' contribution point.")); - for (let node of subNodes) { - validateProperties(node, extension); - } - } -} - const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', { allowComments: true,