Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/vs/platform/extensions/common/extensionValidator.ts')
-rw-r--r--src/vs/platform/extensions/common/extensionValidator.ts108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/vs/platform/extensions/common/extensionValidator.ts b/src/vs/platform/extensions/common/extensionValidator.ts
index dfeea91105f..c36ca616ae2 100644
--- a/src/vs/platform/extensions/common/extensionValidator.ts
+++ b/src/vs/platform/extensions/common/extensionValidator.ts
@@ -3,7 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
+import { isEqualOrParent, joinPath } from 'vs/base/common/resources';
+import Severity from 'vs/base/common/severity';
+import { URI } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
+import * as semver from 'vs/base/common/semver/semver';
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
export interface IParsedVersion {
@@ -235,6 +239,98 @@ export function isValidVersion(_inputVersion: string | INormalizedVersion, _inpu
type ProductDate = string | Date | undefined;
+export function validateExtensionManifest(productVersion: string, productDate: ProductDate, extensionLocation: URI, extensionManifest: IExtensionManifest, extensionIsBuiltin: boolean): readonly [Severity, string][] {
+ const validations: [Severity, string][] = [];
+ if (typeof extensionManifest.publisher !== 'undefined' && typeof extensionManifest.publisher !== 'string') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.publisher', "property publisher must be of type `string`.")]);
+ return validations;
+ }
+ if (typeof extensionManifest.name !== 'string') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.name', "property `{0}` is mandatory and must be of type `string`", 'name')]);
+ return validations;
+ }
+ if (typeof extensionManifest.version !== 'string') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.version', "property `{0}` is mandatory and must be of type `string`", 'version')]);
+ return validations;
+ }
+ if (!extensionManifest.engines) {
+ validations.push([Severity.Error, nls.localize('extensionDescription.engines', "property `{0}` is mandatory and must be of type `object`", 'engines')]);
+ return validations;
+ }
+ if (typeof extensionManifest.engines.vscode !== 'string') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.engines.vscode', "property `{0}` is mandatory and must be of type `string`", 'engines.vscode')]);
+ return validations;
+ }
+ if (typeof extensionManifest.extensionDependencies !== 'undefined') {
+ if (!isStringArray(extensionManifest.extensionDependencies)) {
+ validations.push([Severity.Error, nls.localize('extensionDescription.extensionDependencies', "property `{0}` can be omitted or must be of type `string[]`", 'extensionDependencies')]);
+ return validations;
+ }
+ }
+ if (typeof extensionManifest.activationEvents !== 'undefined') {
+ if (!isStringArray(extensionManifest.activationEvents)) {
+ validations.push([Severity.Error, nls.localize('extensionDescription.activationEvents1', "property `{0}` can be omitted or must be of type `string[]`", 'activationEvents')]);
+ return validations;
+ }
+ if (typeof extensionManifest.main === 'undefined' && typeof extensionManifest.browser === 'undefined') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.activationEvents2', "properties `{0}` and `{1}` must both be specified or must both be omitted", 'activationEvents', 'main')]);
+ return validations;
+ }
+ }
+ if (typeof extensionManifest.extensionKind !== 'undefined') {
+ if (typeof extensionManifest.main === 'undefined') {
+ validations.push([Severity.Warning, nls.localize('extensionDescription.extensionKind', "property `{0}` can be defined only if property `main` is also defined.", 'extensionKind')]);
+ // not a failure case
+ }
+ }
+ if (typeof extensionManifest.main !== 'undefined') {
+ if (typeof extensionManifest.main !== 'string') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.main1', "property `{0}` can be omitted or must be of type `string`", 'main')]);
+ return validations;
+ } else {
+ const mainLocation = joinPath(extensionLocation, extensionManifest.main);
+ if (!isEqualOrParent(mainLocation, extensionLocation)) {
+ validations.push([Severity.Warning, nls.localize('extensionDescription.main2', "Expected `main` ({0}) to be included inside extension's folder ({1}). This might make the extension non-portable.", mainLocation.path, extensionLocation.path)]);
+ // not a failure case
+ }
+ }
+ if (typeof extensionManifest.activationEvents === 'undefined') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.main3', "properties `{0}` and `{1}` must both be specified or must both be omitted", 'activationEvents', 'main')]);
+ return validations;
+ }
+ }
+ if (typeof extensionManifest.browser !== 'undefined') {
+ if (typeof extensionManifest.browser !== 'string') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.browser1', "property `{0}` can be omitted or must be of type `string`", 'browser')]);
+ return validations;
+ } else {
+ const browserLocation = joinPath(extensionLocation, extensionManifest.browser);
+ if (!isEqualOrParent(browserLocation, extensionLocation)) {
+ validations.push([Severity.Warning, nls.localize('extensionDescription.browser2', "Expected `browser` ({0}) to be included inside extension's folder ({1}). This might make the extension non-portable.", browserLocation.path, extensionLocation.path)]);
+ // not a failure case
+ }
+ }
+ if (typeof extensionManifest.activationEvents === 'undefined') {
+ validations.push([Severity.Error, nls.localize('extensionDescription.browser3', "properties `{0}` and `{1}` must both be specified or must both be omitted", 'activationEvents', 'browser')]);
+ return validations;
+ }
+ }
+
+ if (!semver.valid(extensionManifest.version)) {
+ validations.push([Severity.Error, nls.localize('notSemver', "Extension version is not semver compatible.")]);
+ return validations;
+ }
+
+ const notices: string[] = [];
+ const isValid = isValidExtensionVersion(productVersion, productDate, extensionManifest, extensionIsBuiltin, notices);
+ if (!isValid) {
+ for (const notice of notices) {
+ validations.push([Severity.Error, notice]);
+ }
+ }
+ return validations;
+}
+
export function isValidExtensionVersion(productVersion: string, productDate: ProductDate, extensionManifest: IExtensionManifest, extensionIsBuiltin: boolean, notices: string[]): boolean {
if (extensionIsBuiltin || (typeof extensionManifest.main === 'undefined' && typeof extensionManifest.browser === 'undefined')) {
@@ -282,3 +378,15 @@ function isVersionValid(currentVersion: string, date: ProductDate, requestedVers
return true;
}
+
+function isStringArray(arr: string[]): boolean {
+ if (!Array.isArray(arr)) {
+ return false;
+ }
+ for (let i = 0, len = arr.length; i < len; i++) {
+ if (typeof arr[i] !== 'string') {
+ return false;
+ }
+ }
+ return true;
+}