eslint-plugin-html-compat
Version:
ESLint plugin to check HTML element and attribute compatibility using browserslist and @mdn/browser-compat-data
247 lines • 9.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkHtmlElementCompatibility = checkHtmlElementCompatibility;
exports.checkHtmlElementDeprecation = checkHtmlElementDeprecation;
exports.checkHtmlAttributeDeprecation = checkHtmlAttributeDeprecation;
exports.checkHtmlAttributeCompatibility = checkHtmlAttributeCompatibility;
const bcd = require("@mdn/browser-compat-data");
function generateMdnUrl(feature) {
const baseUrl = "https://developer.mozilla.org/en-US/docs/Web/";
if (feature.startsWith("html.elements.")) {
const element = feature.replace("html.elements.", "");
if (element.includes(".")) {
const [elementName, attribute] = element.split(".");
return `${baseUrl}HTML/Element/${elementName}#${attribute}`;
}
return `${baseUrl}HTML/Element/${element}`;
}
if (feature.startsWith("html.global_attributes.")) {
const attribute = feature.replace("html.global_attributes.", "");
return `${baseUrl}HTML/Global_attributes/${attribute}`;
}
return `${baseUrl}HTML`;
}
function getBrowserName(browserKey) {
const browserMap = {
chrome: "chrome",
firefox: "firefox",
safari: "safari",
edge: "edge",
ie: "ie",
opera: "opera",
ios_saf: "safari_ios",
and_chr: "chrome_android",
and_ff: "firefox_android",
and_qq: "qq_android",
and_uc: "uc_android",
android: "webview_android",
baidu: "baidu",
ie_mob: "ie",
op_mini: "opera_mini",
op_mob: "opera_android",
samsung: "samsunginternet_android",
kaios: "kaios",
};
return browserMap[browserKey] || browserKey;
}
function compareVersions(version1, version2) {
const v1Parts = version1.split(".").map(Number);
const v2Parts = version2.split(".").map(Number);
const maxLength = Math.max(v1Parts.length, v2Parts.length);
for (let i = 0; i < maxLength; i++) {
const v1Part = v1Parts[i] || 0;
const v2Part = v2Parts[i] || 0;
if (v1Part > v2Part)
return 1;
if (v1Part < v2Part)
return -1;
}
return 0;
}
function isVersionSupported(supportInfo, targetVersion) {
if (!supportInfo)
return false;
if (Array.isArray(supportInfo)) {
return supportInfo.some((info) => isVersionSupported(info, targetVersion));
}
if (typeof supportInfo === "object") {
const versionAdded = supportInfo.version_added;
if (versionAdded === true)
return true;
if (versionAdded === false || versionAdded === null)
return false;
if (typeof versionAdded === "string") {
const cleanVersion = versionAdded.replace(/[^\d.]/g, "");
return compareVersions(targetVersion, cleanVersion) >= 0;
}
}
return false;
}
function filterIgnoredBrowsers(unsupportedBrowsers, ignoreBrowsers = []) {
if (ignoreBrowsers.length === 0)
return unsupportedBrowsers;
return unsupportedBrowsers.filter((browser) => {
return !ignoreBrowsers.some((ignored) => {
const normalizedIgnored = ignored.toLowerCase().trim();
const normalizedBrowser = browser.toLowerCase().trim();
// Exact match
if (normalizedBrowser === normalizedIgnored)
return true;
// Browser name match (e.g., "ie" matches "ie 11")
if (normalizedBrowser.startsWith(`${normalizedIgnored} `))
return true;
return false;
});
});
}
function checkHtmlElementCompatibility(element, targetBrowsers, ignoreBrowsers) {
const feature = `html.elements.${element}`;
const elementData = bcd.html?.elements?.[element];
if (!elementData || !elementData.__compat) {
return {
isSupported: true,
unsupportedBrowsers: [],
feature,
};
}
const support = elementData.__compat.support;
const unsupportedBrowsers = [];
for (const target of targetBrowsers) {
const browserName = getBrowserName(target.browser);
const browserSupport = support[browserName];
if (browserSupport && !isVersionSupported(browserSupport, target.version)) {
unsupportedBrowsers.push(`${target.browser} ${target.version}`);
}
}
const filteredUnsupportedBrowsers = filterIgnoredBrowsers(unsupportedBrowsers, ignoreBrowsers);
return {
isSupported: filteredUnsupportedBrowsers.length === 0,
unsupportedBrowsers: filteredUnsupportedBrowsers,
feature,
mdnUrl: generateMdnUrl(feature),
};
}
function checkHtmlElementDeprecation(element) {
const feature = `html.elements.${element}`;
const elementData = bcd.html?.elements?.[element];
if (!elementData || !elementData.__compat) {
return {
isDeprecated: false,
feature,
mdnUrl: generateMdnUrl(feature),
};
}
const status = elementData.__compat.status;
if (status?.deprecated) {
return {
isDeprecated: true,
deprecationNote: status.deprecated === true ? undefined : String(status.deprecated),
feature,
mdnUrl: generateMdnUrl(feature),
};
}
return {
isDeprecated: false,
feature,
mdnUrl: generateMdnUrl(feature),
};
}
function checkHtmlAttributeDeprecation(element, attribute) {
const feature = `html.elements.${element}.${attribute}`;
const elementData = bcd.html?.elements?.[element];
if (!elementData) {
return {
isDeprecated: false,
feature,
};
}
const attributeData = elementData[attribute];
if (!attributeData || !attributeData.__compat) {
const globalAttribute = bcd.html?.global_attributes?.[attribute];
if (!globalAttribute || !globalAttribute.__compat) {
return {
isDeprecated: false,
feature,
};
}
const status = globalAttribute.__compat.status;
if (status?.deprecated) {
return {
isDeprecated: true,
deprecationNote: status.deprecated === true ? undefined : String(status.deprecated),
feature: `html.global_attributes.${attribute}`,
};
}
return {
isDeprecated: false,
feature: `html.global_attributes.${attribute}`,
};
}
const status = attributeData.__compat.status;
if (status?.deprecated) {
return {
isDeprecated: true,
deprecationNote: status.deprecated === true ? undefined : String(status.deprecated),
feature,
};
}
return {
isDeprecated: false,
feature,
};
}
function checkHtmlAttributeCompatibility(element, attribute, targetBrowsers, ignoreBrowsers) {
const feature = `html.elements.${element}.${attribute}`;
const elementData = bcd.html?.elements?.[element];
if (!elementData) {
return {
isSupported: true,
unsupportedBrowsers: [],
feature,
};
}
const attributeData = elementData[attribute];
if (!attributeData || !attributeData.__compat) {
const globalAttribute = bcd.html?.global_attributes?.[attribute];
if (!globalAttribute || !globalAttribute.__compat) {
return {
isSupported: true,
unsupportedBrowsers: [],
feature,
};
}
const support = globalAttribute.__compat.support;
const unsupportedBrowsers = [];
for (const target of targetBrowsers) {
const browserName = getBrowserName(target.browser);
const browserSupport = support[browserName];
if (browserSupport &&
!isVersionSupported(browserSupport, target.version)) {
unsupportedBrowsers.push(`${target.browser} ${target.version}`);
}
}
const filteredUnsupportedBrowsers = filterIgnoredBrowsers(unsupportedBrowsers, ignoreBrowsers);
return {
isSupported: filteredUnsupportedBrowsers.length === 0,
unsupportedBrowsers: filteredUnsupportedBrowsers,
feature: `html.global_attributes.${attribute}`,
};
}
const support = attributeData.__compat.support;
const unsupportedBrowsers = [];
for (const target of targetBrowsers) {
const browserName = getBrowserName(target.browser);
const browserSupport = support[browserName];
if (browserSupport && !isVersionSupported(browserSupport, target.version)) {
unsupportedBrowsers.push(`${target.browser} ${target.version}`);
}
}
const filteredUnsupportedBrowsers = filterIgnoredBrowsers(unsupportedBrowsers, ignoreBrowsers);
return {
isSupported: filteredUnsupportedBrowsers.length === 0,
unsupportedBrowsers: filteredUnsupportedBrowsers,
feature,
mdnUrl: generateMdnUrl(feature),
};
}
//# sourceMappingURL=compatibility.js.map