public processKey()

in app/exec/extension/_lib/vsix-manifest-builder.ts [190:473]


	public processKey(key: string, value: any, override: boolean): void {
		switch (key.toLowerCase()) {
			case "namespace":
			case "extensionid":
			case "id":
				if (_.isString(value)) {
					this.singleValueProperty(
						"PackageManifest.Metadata[0].Identity[0].$.Id",
						value,
						"namespace/extensionId/id",
						override,
					);
				}
				break;
			case "version":
				this.singleValueProperty("PackageManifest.Metadata[0].Identity[0].$.Version", value, key, override);
				break;
			case "name":
				this.singleValueProperty("PackageManifest.Metadata[0].DisplayName[0]", value, key, override);
				break;
			case "description":
				_.set(this.data, "PackageManifest.Metadata[0].Description[0].$", { "xml:space": "preserve" });
				this.singleValueProperty("PackageManifest.Metadata[0].Description[0]._", value, key, override);
				break;
			case "icons":
				Object.keys(value).forEach(key => {
					let iconType = _.startCase(key.toLowerCase());
					let fileDecl: FileDeclaration = {
						path: value[key],
						addressable: true,
						auto: true,
						assetType: "Microsoft.VisualStudio.Services.Icons." + iconType,
					};
					this.addFile(fileDecl, true);
				});
				break;
			case "screenshots":
				if (_.isArray(value)) {
					let screenshotIndex = 0;
					value.forEach((screenshot: ScreenshotDeclaration) => {
						let fileDecl: FileDeclaration = {
							path: screenshot.path,
							addressable: true,
							auto: true,
							assetType: "Microsoft.VisualStudio.Services.Screenshots." + ++screenshotIndex,
							contentType: screenshot.contentType,
						};
						this.addFile(fileDecl, true);
					});
				}
				break;
			case "content":
				Object.keys(value).forEach(key => {
					let contentKey = _.startCase(key.toLowerCase());
					if (value[key].path) {
						let fileDecl: FileDeclaration = {
							path: value[key].path,
							addressable: true,
							auto: true,
							assetType: "Microsoft.VisualStudio.Services.Content." + contentKey,
						};
						if (value[key].contentType) {
							fileDecl.contentType = value[key].contentType;
						}
						this.addFile(fileDecl, true);
					} else {
						trace.warn("Did not find 'path' property for content item '%s'. Ignoring.", key);
					}
				});
				break;
			case "details":
				if (_.isObject(value) && value.path) {
					let fileDecl: FileDeclaration = {
						path: value.path,
						addressable: true,
						auto: true,
						assetType: "Microsoft.VisualStudio.Services.Content.Details",
						contentType: value.contentType,
					};
					this.addFile(fileDecl, true);
				}
				break;
			case "targets":
				if (_.isArray(value)) {
					let existingTargets = _.get<any[]>(this.data, "PackageManifest.Installation[0].InstallationTarget", []);
					value.forEach((target: TargetDeclaration) => {
						if (!target.id) {
							return;
						}
						let newTargetAttrs = {
							Id: target.id,
						};
						if (target.version) {
							newTargetAttrs["Version"] = target.version;
						}
						existingTargets.push({
							$: newTargetAttrs,
						});
					});
					_.set(this.data, "PackageManifest.Installation[0].InstallationTarget", existingTargets);
				}
				break;
			case "links":
				if (_.isObject(value)) {
					Object.keys(value).forEach(linkType => {
						let url = _.get<any, string>(value, linkType + ".uri") || _.get<any, string>(value, linkType + ".url");
						if (url) {
							let linkTypeCased = _.capitalize(_.camelCase(linkType));
							this.addProperty("Microsoft.VisualStudio.Services.Links." + linkTypeCased, url);
						} else {
							trace.warn("'uri' property not found for link: '%s'... ignoring.", linkType);
						}
					});
				}
				break;
			case "repository":
				if (_.isObject(value)) {
					const { type, url, uri } = value;
					if (!type) {
						throw new Error("Repository must have a 'type' property.");
					}
					if (type !== "git") {
						throw new Error("Currently 'git' is the only supported repository type.");
					}
					if (!url && !uri) {
						throw new Error("Repository must contain a 'url' property.");
					}
					this.addProperty("Microsoft.VisualStudio.Services.Links.GitHub", url || uri);
				}
				break;
			case "badges":
				if (_.isArray(value)) {
					let existingBadges = _.get<any[]>(this.data, "PackageManifest.Metadata[0].Badges[0].Badge", []);
					value.forEach(
						(badge: { link?: string; imgUri?: string; description?: string; href?: string; uri?: string }) => {
							existingBadges.push({
								$: {
									Link: badge.link || badge.href,
									ImgUri: badge.imgUri || badge.uri,
									Description: badge.description,
								},
							});
						},
					);
					_.set(this.data, "PackageManifest.Metadata[0].Badges[0].Badge", existingBadges);
				}
				break;
			case "branding":
				if (_.isObject(value)) {
					Object.keys(value).forEach(brandingType => {
						let brandingTypeCased = _.capitalize(_.camelCase(brandingType));
						let brandingValue = value[brandingType];
						if (brandingTypeCased === "Color") {
							try {
								brandingValue = onecolor(brandingValue).hex();
							} catch (e) {
								throw "Could not parse branding color as a valid color. Please use a hex or rgb format, e.g. #00ff00 or rgb(0, 255, 0)";
							}
						}
						this.addProperty("Microsoft.VisualStudio.Services.Branding." + brandingTypeCased, brandingValue);
					});
				}
				break;
			case "customerqnasupport":
				if (_.isObject(value)) {
					// Normalize keys by fixing casing
					Object.keys(value).forEach(k => {
						const lck = k.toLowerCase();
						if (lck === "url" || lck === "uri") {
							value["url"] = value[k];
						}
						if (lck === "enablemarketplaceqna") {
							value["enableMarketplaceQnA"] = value[k];
						}
					});
					const qnaSupportVal = value as CustomerQnASupport;
					if (typeof qnaSupportVal.enableMarketplaceQnA === "boolean") {
						this.addProperty(
							"Microsoft.VisualStudio.Services.EnableMarketplaceQnA",
							String(qnaSupportVal.enableMarketplaceQnA),
						);
					}
					if (typeof qnaSupportVal.url === "string") {
						this.addProperty("Microsoft.VisualStudio.Services.CustomerQnALink", qnaSupportVal.url);
					}
				}
				break;
			case "githubflavoredmarkdown":
				if (typeof value !== "boolean") {
					throw "Value for gitHubFlavoredMarkdown is invalid. Only boolean values are allowed.";
				}
				this.addProperty("Microsoft.VisualStudio.Services.GitHubFlavoredMarkdown", value.toString());
				break;
			case "public":
				if (typeof value === "boolean") {
					let flags = _.get(this.data, "PackageManifest.Metadata[0].GalleryFlags[0]", "").split(" ");
					_.remove(flags, v => v === "");
					if (value === true) {
						flags.push("Public");
					}
					if (value === false) {
						_.remove(flags, v => v === "Public");
					}
					_.set(this.data, "PackageManifest.Metadata[0].GalleryFlags[0]", _.uniq(flags).join(" "));
				} else {
					throw new Error("The value for `public` must be a boolean true or false.");
				}
				break;
			case "publisher":
				this.singleValueProperty("PackageManifest.Metadata[0].Identity[0].$.Publisher", value, key, override);
				break;
			case "releasenotes":
				this.singleValueProperty("PackageManifest.Metadata[0].ReleaseNotes[0]", value, key, override);
				break;
			case "tags":
				this.handleDelimitedList(value, "PackageManifest.Metadata[0].Tags[0]");
				break;
			case "galleryflags":
				// Gallery Flags are space-separated since it's a Flags enum.
				this.handleDelimitedList(value, "PackageManifest.Metadata[0].GalleryFlags[0]", " ", true);
				break;
			case "categories":
				this.handleDelimitedList(value, "PackageManifest.Metadata[0].Categories[0]");
				break;
			case "files":
				if (_.isArray(value)) {
					value.forEach((asset: FileDeclaration) => {
						this.addFile(asset);
					});
				}
				break;
			case "showpricingcalculator":
				if (typeof value !== "boolean") {
					throw new Error("Value for showPricingCalculator is invalid. Only boolean values are allowed.");
				}
				this.addProperty("Microsoft.VisualStudio.Services.Content.Pricing.PriceCalculator", value.toString());
				break;
			case "galleryproperties":
				/**
				 * The Gallery Properties would be a generic array of JSON elements
				 */
				let normalizedValue = value;
				if (_.isObject(value)) {
					normalizedValue = Object.keys(value).map(k => {
						return { [k]: value[k] };
					});
				}
				if (_.isArray(normalizedValue)) {
					normalizedValue.forEach(propertyGroup => {
						Object.keys(propertyGroup).forEach((propertyKey: string) => {
							if (typeof propertyKey === "string" && propertyKey.length > 0 && propertyGroup[propertyKey]) {
								let propertyName: string;

								if (_.startsWith(propertyKey, "Microsoft.")) {
									propertyName = propertyKey;
								} else {
									// Property ID would be in upper camel case (First letter Capital)
									let ucck: string = _.upperFirst(propertyKey);
									propertyName = "Microsoft.VisualStudio.Services.GalleryProperties." + ucck;
								}

								// Check for duplicates
								let existingProperties = _.get<any[]>(
									this.data,
									"PackageManifest.Metadata[0].Properties[0].Property",
									[],
								);
								let pIds = existingProperties.map(p => _.get(p, "$.Id"));
								if (_.intersection([propertyName], pIds).length !== 0) {
									trace.warn(
										"multiple entries found for the same property group in the extension manifest ... ignoring the duplicates.",
									);
								} else {
									this.addProperty(propertyName, String(propertyGroup[propertyKey]));
								}
							} else {
								trace.warn("incorrectly formed property group in the extension manifest ... ignoring.");
							}
						});
					});
				}
				break;
		}
	}