custom-element-vs-code-integration
Version:
Tools for integrating web components/custom elements into VS Code
475 lines (458 loc) • 16.8 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
customElementVsCodePlugin: () => customElementVsCodePlugin,
generateVsCodeCustomElementData: () => generateVsCodeCustomElementData,
getVsCodeCssCustomData: () => getVsCodeCssCustomData,
getVsCodeHtmlCustomData: () => getVsCodeHtmlCustomData
});
module.exports = __toCommonJS(src_exports);
// ../../tools/integrations/src/files.ts
var import_fs = __toESM(require("fs"), 1);
var import_path = __toESM(require("path"), 1);
var import_sync = __toESM(require("@prettier/sync"), 1);
function createOutDir(outDir) {
if (outDir !== "./" && !import_fs.default.existsSync(outDir)) {
import_fs.default.mkdirSync(outDir, { recursive: true });
}
}
function saveFile(outDir, fileName, contents, parser = "json", printWidth = 80) {
const outputPath = import_path.default.join(outDir, fileName);
import_fs.default.writeFileSync(
outputPath,
import_sync.default.format(contents, { parser, printWidth })
);
return outputPath;
}
// ../../tools/integrations/src/logs.ts
function log(message, skip, color = "\x1B[30m%s\x1B[0m") {
if (skip) {
return;
}
console.log(color, message);
}
function logRed(message, skip) {
log(message, skip, "\x1B[31m%s\x1B[0m");
}
function logGreen(message, skip) {
log(message, skip, "\x1B[32m%s\x1B[0m");
}
function logYellow(message, skip) {
log(message, skip, "\x1B[33m%s\x1B[0m");
}
// ../../tools/utilities/src/utilities.ts
var toKebabCase = (value) => value.replace(/([a-z0–9])([A-Z])/g, "$1-$2").toLowerCase();
function removeQuoteWrappers(value) {
return value.trim().replace(/^["'](.+(?=["']$))["']$/, "$1");
}
function has(arr) {
return Array.isArray(arr) && arr.length > 0;
}
// ../../tools/cem-utils/src/cem-utilities.ts
var EXCLUDED_TYPES = [
"any",
"bigint",
"boolean",
"never",
"null",
"number",
"string",
"Symbol",
"undefined",
"unknown"
];
function getComponentDescription(component, descriptionSrc) {
var _a;
let description = ((_a = descriptionSrc ? component[descriptionSrc] : component.summary || component.description) == null ? void 0 : _a.replace(/\\n/g, "\n")) || "";
if (component.deprecated) {
const deprecation = typeof component.deprecated === "string" ? `@deprecated ${component.deprecated}` : "@deprecated";
description = `${deprecation}
${description}`;
}
return description;
}
function getComponents(customElementsManifest, exclude) {
var _a;
return (((_a = customElementsManifest.modules) == null ? void 0 : _a.map(
(mod) => {
var _a2;
return ((_a2 = mod == null ? void 0 : mod.declarations) == null ? void 0 : _a2.filter(
(dec) => !(exclude == null ? void 0 : exclude.includes(dec.name)) && (dec.customElement || dec.tagName)
)) || [];
}
)) || []).flat();
}
function getAttributeValueOptions(attr, typeSrc = "type") {
var _a, _b;
const value = ((_a = attr[`${typeSrc}`]) == null ? void 0 : _a.text) || ((_b = attr.type) == null ? void 0 : _b.text);
return !value ? [] : (value.includes("|") ? value.split("|") : value.split(",")).filter((type) => !EXCLUDED_TYPES.includes(type.trim())).map((type) => removeQuoteWrappers(type));
}
function getComponentMethods(component) {
var _a;
return (_a = component.members) == null ? void 0 : _a.filter(
(member) => {
var _a2;
return member.kind === "method" && member.privacy !== "private" && ((_a2 = member.description) == null ? void 0 : _a2.length) && !member.name.startsWith("#");
}
);
}
// ../../tools/cem-utils/src/description-templates.ts
function getComponentDetailsTemplate(component, options, isComment = false) {
var _a, _b, _c, _d, _e;
const slots = getSlotsTemplate(
component == null ? void 0 : component.slots,
options == null ? void 0 : options.hideSlotDocs,
(_a = options == null ? void 0 : options.labels) == null ? void 0 : _a.slots
);
const events = getEventsTemplate(
component == null ? void 0 : component.events,
options == null ? void 0 : options.hideEventDocs,
(_b = options == null ? void 0 : options.labels) == null ? void 0 : _b.events
);
const cssProps = getCssPropsTemplate(
component == null ? void 0 : component.cssProperties,
options == null ? void 0 : options.hideCssPropertiesDocs,
(_c = options == null ? void 0 : options.labels) == null ? void 0 : _c.cssProperties
);
const parts = getPartsTemplate(
component == null ? void 0 : component.cssParts,
options == null ? void 0 : options.hideCssPartsDocs,
(_d = options == null ? void 0 : options.labels) == null ? void 0 : _d.cssParts
);
const methods = getMethodsTemplate(
getComponentMethods(component),
options == null ? void 0 : options.hideMethodDocs,
(_e = options == null ? void 0 : options.labels) == null ? void 0 : _e.methods
);
let description = getComponentDescription(component, options == null ? void 0 : options.descriptionSrc) + "\n---\n" + events + methods + slots + cssProps + parts;
if (isComment) {
description = description.split("\n").map((x) => ` * ${x}`).join("\n");
}
return description;
}
function getSlotsTemplate(slots, hide, label = "Slots") {
return has(slots) && !hide ? `
### **${label}:**
${getSlotDocs(slots)}` : "";
}
function getEventsTemplate(events, hide, label = "Events") {
return has(events) && !hide ? `
### **${label}:**
${getEventDocs(events)}` : "";
}
function getCssPropsTemplate(cssProperties, hide, label = "CSS Properties") {
return has(cssProperties) && !hide ? `
### **${label}:**
${getCssPropertyDocs(cssProperties)}` : "";
}
function getPartsTemplate(cssParts, hide, label = "CSS Parts") {
return has(cssParts) && !hide ? `
### **${label}:**
${getCssPartsDocs(cssParts)}` : "";
}
function getMethodsTemplate(methods, hide, label = "Methods") {
return has(methods) && !hide ? `
### **${label}:**
${getMethodDocs(methods)}` : "";
}
function getEventDocs(events) {
return events == null ? void 0 : events.filter((event) => event.name !== null && event.name !== void 0).map(
(event) => `- **${event.name}**${event.description ? ` - ${event.description}` : ""}`
).join("\n");
}
function getCssPropertyDocs(properties) {
return properties == null ? void 0 : properties.map(
(prop) => `- **${prop.name}** - ${prop.description} _(default: ${prop.default})_`
).join("\n");
}
function getCssPartsDocs(parts) {
return parts == null ? void 0 : parts.map((part) => `- **${part.name}** - ${part.description}`).join("\n");
}
function getSlotDocs(slots) {
return slots == null ? void 0 : slots.map(
(slot) => `- ${slot.name ? `**${slot.name}**` : "_default_"} - ${slot.description}`
).join("\n");
}
function getMethodDocs(methods) {
return methods == null ? void 0 : methods.map((method) => {
var _a;
if (method.privacy === "private" || method.privacy === "protected") {
return;
}
return `- **${method.name}${getParameters(method.parameters)}${method.return ? `: _${(_a = method.return.type) == null ? void 0 : _a.text}_` : ""}** - ${getMemberDescription(method.description, method.deprecated)}`;
}).join("\n");
}
function getParameters(parameters) {
return parameters ? "(" + parameters.map(
(x) => {
var _a, _b;
return `${x.name + (((_a = x == null ? void 0 : x.type) == null ? void 0 : _a.text) ? `: _${(_b = x == null ? void 0 : x.type) == null ? void 0 : _b.text}_` : "")}`;
}
).join(", ") + ")" : "()";
}
function getMemberDescription(description, deprecated) {
if (!deprecated) {
return description || "";
}
const desc = description ? ` - ${description}` : "";
return typeof deprecated === "string" ? `@deprecated ${deprecated}${desc}` : `@deprecated${desc}`;
}
// src/cem-utilities.ts
function getCssPropertyList(components, cssSets) {
return ((components == null ? void 0 : components.map((component) => {
var _a;
return ((_a = component.cssProperties) == null ? void 0 : _a.map((prop) => {
var _a2;
return {
name: prop.name,
description: prop.description,
values: getCssPropertyValues((_a2 = prop == null ? void 0 : prop.type) == null ? void 0 : _a2.text, cssSets)
};
})) || [];
})) || []).flat();
}
function getCssPartList(components) {
return ((components == null ? void 0 : components.map((component) => {
var _a;
return ((_a = component.cssParts) == null ? void 0 : _a.map((prop) => {
return {
name: `::part(${prop.name})`,
description: prop.description
};
})) || [];
})) || []).flat();
}
function getCssPropertyValues(value, cssSets) {
if (!value) {
return [];
}
if (value.trim().startsWith("set")) {
return getValueSet(value, cssSets);
}
return getCssValues(value);
}
function getValueSet(value, cssSets) {
var _a;
const setName = value.split(":")[1];
const valueSet = ((_a = cssSets == null ? void 0 : cssSets.find((x) => x.name.trim() === setName)) == null ? void 0 : _a.values) || [];
return valueSet.map((x) => {
if (typeof x === "string") {
return {
name: getCssNameValue(x)
};
} else {
x.name = getCssNameValue(x.name);
return x;
}
});
}
function getCssValues(value) {
return value ? (value.includes("|") ? value.split("|") : value.split(",")).map((x) => {
const propName = x.trim();
return {
name: getCssNameValue(propName)
};
}) : [];
}
function getCssNameValue(value) {
return !value ? "" : value.startsWith("--") ? `var(${value})` : value;
}
function getTagList(components, options) {
return (components == null ? void 0 : components.map((component) => {
return {
name: `${options.prefix}${component.tagName || toKebabCase(component.name)}${options.suffix}`,
description: getComponentDetailsTemplate(component, options),
attributes: getComponentAttributes(component, options == null ? void 0 : options.typesSrc),
references: (options == null ? void 0 : options.referencesTemplate) ? options.referencesTemplate(component.name, component.tagName) : []
};
})) || [];
}
function getComponentAttributes(component, typesSrc) {
var _a;
const attributes = [];
(_a = component == null ? void 0 : component.attributes) == null ? void 0 : _a.forEach((attr) => {
const existingAttr = attributes.find(
(x) => x.name === attr.name || x.name === attr.fieldName
);
if (existingAttr) {
return;
}
attributes.push({
name: attr.name || attr.fieldName,
description: attr.description,
values: getAttributeValues(attr, typesSrc)
});
});
return attributes;
}
function getAttributeValues(attr, typesSrc) {
const options = getAttributeValueOptions(attr, typesSrc);
return (options == null ? void 0 : options.map((option) => {
return {
name: option
};
})) || [];
}
// ../../tools/configurations/src/config.ts
var baseConfig = {
outdir: "./",
exclude: [],
descriptionSrc: void 0,
hideSlotDocs: false,
hideEventDocs: false,
hideCssPropertiesDocs: false,
hideCssPartsDocs: false,
hideMethodDocs: false,
labels: {
slots: "Slots",
events: "Events",
cssProperties: "CSS Properties",
cssParts: "CSS Parts",
methods: "Methods"
}
};
function updateConfig(params) {
const config = { ...baseConfig, ...params };
config.labels = { ...baseConfig.labels, ...params == null ? void 0 : params.labels };
return config;
}
// src/data-file-generator.ts
function generateVsCodeCustomElementData(customElementsManifest, options) {
if (options == null ? void 0 : options.skip) {
logYellow(
"[custom-element-vs-code-integration] - Skipped",
options == null ? void 0 : options.hideLogs
);
return;
}
log(
"[custom-element-vs-code-integration] - Updating Custom Elements Manifest...",
options == null ? void 0 : options.hideLogs
);
options = getOptions(options);
const components = getComponents(
customElementsManifest,
options.exclude
).filter((x) => x.tagName);
if (!components.length) {
logRed("[custom-element-vs-code-integration] - No components found.");
return;
}
const htmlTags = options.htmlFileName ? getTagList(components, options) : [];
const cssProperties = options.cssFileName ? getCssPropertyList(components, options.cssSets) : [];
const cssParts = options.cssFileName ? getCssPartList(components) : [];
const outputPath = saveCustomDataFiles(
options,
htmlTags,
cssProperties,
cssParts
);
logGreen(`[vs-code-custom-data-generator] - Generated ${outputPath}.`);
}
function getVsCodeHtmlCustomData(customElementsManifest, options) {
options = getOptions(options);
const components = getComponents(
customElementsManifest,
options.exclude
).filter((x) => x.tagName);
const htmlTags = getTagList(components, options);
return getCustomHtmlDataFileContents(htmlTags);
}
function getVsCodeCssCustomData(customElementsManifest, options) {
options = getOptions(options);
const components = getComponents(
customElementsManifest,
options.exclude
).filter((x) => x.tagName);
const cssProperties = getCssPropertyList(components, options.cssSets);
const cssParts = getCssPartList(components);
return getCustomCssDataFileContents(cssProperties, cssParts);
}
function getOptions(options) {
options = updateConfig(options);
options.htmlFileName = options.htmlFileName === void 0 ? "vscode.html-custom-data.json" : options.htmlFileName;
options.cssFileName = options.cssFileName === void 0 ? "vscode.css-custom-data.json" : options.cssFileName;
options.prefix = options.prefix === void 0 ? "" : options.prefix;
options.suffix = options.suffix === void 0 ? "" : options.suffix;
return options;
}
function saveCustomDataFiles(options, tags, cssProperties, cssParts) {
const outputPaths = [];
createOutDir(options.outdir);
if (options.htmlFileName) {
const htmlOutput = saveFile(
options.outdir,
options.htmlFileName,
getCustomHtmlDataFileContents(tags)
);
outputPaths.push(`"${htmlOutput}"`);
}
if (options.cssFileName) {
const cssOutput = saveFile(
options.outdir,
options.cssFileName,
getCustomCssDataFileContents(cssProperties, cssParts)
);
outputPaths.push(`"${cssOutput}"`);
}
return outputPaths.join(", ");
}
function getCustomHtmlDataFileContents(tags) {
return `{
"$schema": "https://raw.githubusercontent.com/microsoft/vscode-html-languageservice/main/docs/customData.schema.json",
"version": 1.1,
"tags": ${JSON.stringify(tags)}
}`;
}
function getCustomCssDataFileContents(properties, parts) {
return `{
"$schema": "https://raw.githubusercontent.com/microsoft/vscode-css-languageservice/main/docs/customData.schema.json",
"version": 1.1,
"properties": ${JSON.stringify(properties)},
"pseudoElements": ${JSON.stringify(parts)}
}`;
}
// src/cem-analyzer-plugin.ts
function customElementVsCodePlugin(params = {}) {
return {
name: "custom-element-vs-code-integration",
packageLinkPhase({ customElementsManifest }) {
generateVsCodeCustomElementData(customElementsManifest, params);
}
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
customElementVsCodePlugin,
generateVsCodeCustomElementData,
getVsCodeCssCustomData,
getVsCodeHtmlCustomData
});