caniemail
Version:
HTML and CSS Feature Support for Email Clients from caniemail.com
148 lines • 5.44 kB
JavaScript
import { getFeatures } from './features.js';
import { fromTitleEntries, getTitleMatches } from './helpers.js';
const { html: features, others } = getFeatures();
const keys = [...features.keys()];
const otherHtmlDetectedTitles = ['AMP for Email'].filter((title) => others.has(title));
keys.push(...otherHtmlDetectedTitles);
export const attributeTitles = fromTitleEntries(keys.map((title) => {
if (title === 'srcset and sizes attributes') {
return {
title,
value: ['srcset', 'sizes']
};
}
if (!title.endsWith('attribute'))
return void 0;
return {
title,
value: [title.replace(/ attribute$/, '')]
};
}));
export const elementAttributePairTitles = fromTitleEntries(keys.map((title) => {
if (title === 'Local anchors') {
return {
title,
value: {
attributes: [['href', /^#/], 'name'],
element: 'a'
}
};
}
if (title === 'mailto: links') {
return {
title,
value: {
attributes: [['href', /^mailto:/]],
element: 'a'
}
};
}
if (title === 'color-scheme meta tag') {
return {
title,
value: {
attributes: [['name', 'color-scheme']],
element: 'meta'
}
};
}
if (title === 'AMP for Email') {
return {
title,
value: {
attributes: ['⚡4email', 'amp4email'],
element: 'html'
}
};
}
const attributePairMatch = /<(\w+) (\w+)="(\w+)"> element/.exec(title);
if (attributePairMatch === null)
return void 0;
return {
title,
value: {
attributes: [[attributePairMatch[2], attributePairMatch[3]]],
element: attributePairMatch[1]
}
};
}));
// Map of property titles to the properties they support
export const elementTitles = fromTitleEntries(keys.map((title) => {
if (title === 'address') {
return { title, value: ['address'] };
}
if (title === 'HTML5 doctype') {
return { title, value: ['!doctype html'] };
}
if (title === 'HTML5 semantics') {
return {
title,
value: [
'article',
'aside',
'details',
'figcaption',
'figure',
'footer',
'header',
'main',
'mark',
'nav',
'section',
'summary',
'time'
]
};
}
if (title === 'Image maps') {
return { title, value: ['map'] };
}
if (title === 'Embedded <svg> image') {
return { title, value: ['image'] };
}
const htmlMatches = /<(\w+)>/.exec(title);
if (htmlMatches === null)
return void 0;
return {
title,
value: [htmlMatches[1]]
};
}));
export const getMatchingElementTitles = ({ tagName }) => getTitleMatches(elementTitles, tagName);
// TODO: test this
export const getMatchingAttributeTitles = ({ attributes }) => getTitleMatches(attributeTitles, attributes, (values) => values.some((attribute) => attributes.includes(attribute)));
export const getMatchingElementAttributePairTitles = ({ tagName, attributes }) => {
const matchingElementAttributePairTitles = [];
for (const [elementAttributePairTitle, elementAttributePairValues] of Object.entries(elementAttributePairTitles)) {
// Don't bother trying to match if the elements aren't even equal
// eslint-disable-next-line no-continue
if (elementAttributePairValues.element !== tagName)
continue;
for (const attributeMatcher of elementAttributePairValues.attributes) {
// If the attribute matcher is a string, we just check whether the element contains the attribute name
if (typeof attributeMatcher === 'string' &&
Object.keys(attributes).includes(attributeMatcher)) {
matchingElementAttributePairTitles.push(elementAttributePairTitle);
}
// If the attribute matcher is an array, we check each attribute name against an expected attribute value
else if (Array.isArray(attributeMatcher)) {
const [attributeName, attributeValue] = attributeMatcher;
// If the attribute doesn't even exist, try checking the next attribute
// eslint-disable-next-line no-continue
if (attributes[attributeName] === void 0)
continue;
// If the attribute to match is a string, we check for equality
if (typeof attributeValue === 'string' && attributes[attributeName] === attributeValue) {
matchingElementAttributePairTitles.push(elementAttributePairTitle);
}
// If the attribute to match is a regex, we check if the regex matches
else if (attributeValue instanceof RegExp &&
attributeValue.test(attributes[attributeName])) {
matchingElementAttributePairTitles.push(elementAttributePairTitle);
}
}
}
}
return matchingElementAttributePairTitles;
};
//# sourceMappingURL=html-titles.js.map