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;
}
}