diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index b5f62c98da6940123b62cd0f570e158d275d6f1e..cf442e6c925dee22d5fb0e1fd109ddfb60bd2945 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -12,6 +12,8 @@ import { IPager } from 'vs/base/common/paging'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IRequestContext } from 'vs/base/node/request'; +export const EXTENSION_IDENTIFIER_PATTERN = '^[a-z0-9A-Z][a-z0-9\-A-Z]*\\.[a-z0-9A-Z][a-z0-9\-A-Z]*$'; + export interface ICommand { command: string; title: string; diff --git a/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts b/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..75794b5171bb92fd2b478de01234f47b4ab0cc91 --- /dev/null +++ b/src/vs/platform/extensionManagement/test/common/extensionManagement.test.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as assert from 'assert'; +import {EXTENSION_IDENTIFIER_PATTERN} from 'vs/platform/extensionManagement/common/extensionManagement'; + +suite('Extension Identifier Pattern', () => { + + test('extension identifier pattern', () => { + var regEx = new RegExp(EXTENSION_IDENTIFIER_PATTERN); + assert.equal(true, regEx.test('publisher.name')); + assert.equal(true, regEx.test('publiSher.name')); + assert.equal(true, regEx.test('publisher.Name')); + assert.equal(true, regEx.test('PUBLISHER.NAME')); + assert.equal(true, regEx.test('PUBLISHEr.NAMe')); + assert.equal(true, regEx.test('PUBLISHEr.N-AMe')); + assert.equal(true, regEx.test('PUBLISH12Er90.N-A54Me123')); + assert.equal(true, regEx.test('111PUBLISH12Er90.N-1111A54Me123')); + assert.equal(false, regEx.test('publishername')); + assert.equal(false, regEx.test('-publisher.name')); + assert.equal(false, regEx.test('publisher.-name')); + assert.equal(false, regEx.test('-publisher.-name')); + assert.equal(false, regEx.test('publ_isher.name')); + assert.equal(false, regEx.test('publisher._name')); + }); +}); \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts index 87d31a4e598f24c20a670c2e6430aa389bbdc1fa..6dc6589d68ee07764c74d1c0dc85a986c55c9abd 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionTipsService.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import {forEach} from 'vs/base/common/collections'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {match} from 'vs/base/common/glob'; -import {IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, LocalExtensionType} from 'vs/platform/extensionManagement/common/extensionManagement'; +import {IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, LocalExtensionType, EXTENSION_IDENTIFIER_PATTERN} from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionsConfiguration, ConfigurationKey } from './extensions'; import {IModelService} from 'vs/editor/common/services/modelService'; import {IModel} from 'vs/editor/common/editorCommon'; @@ -49,6 +49,10 @@ export class ExtensionTipsService implements IExtensionTipsService { getWorkspaceRecommendations(): string[] { const configuration = this.configurationService.getConfiguration(ConfigurationKey); + if (configuration.recommendations) { + const regEx = new RegExp(EXTENSION_IDENTIFIER_PATTERN); + return configuration.recommendations.filter(recommendation => regEx.test(recommendation)); + } return configuration.recommendations || []; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate.ts index eb6520b8e699a9c706cce9f23f3978db6f939469..6588bff30cad48c2e25b988baf5ae459a85526b5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate.ts @@ -5,6 +5,7 @@ import { localize } from 'vs/nls'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/common/extensionManagement'; export const SchemaId = 'vscode://schemas/extensions'; export const Schema: IJSONSchema = { @@ -14,10 +15,12 @@ export const Schema: IJSONSchema = { properties: { recommendations: { type: 'array', - description: localize('app.extensions.json.recommendations', "List of extensions recommendations. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp."), + description: localize('app.extensions.json.recommendations', "List of extensions recommendations. The identifier of an extension is always '${publisher}.${name}'. For example: 'vscode.csharp'."), items: { type: 'string', defaultSnippets: [{ label: 'Example', body: 'vscode.csharp' }], + pattern: EXTENSION_IDENTIFIER_PATTERN, + errorMessage: localize('app.extension.identifier.errorMessage', "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'.") }, }, }