Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve browser names/versions reported by hint-compat-api #2978

Merged
merged 2 commits into from
Sep 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/hint-compat-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
"nyc": "^14.1.0",
"postcss": "^7.0.17",
"rimraf": "^3.0.0",
"semver": "^6.3.0",
"typescript": "^3.6.2"
},
"engines": {
Expand Down
21 changes: 13 additions & 8 deletions packages/hint-compat-api/src/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { vendor, AtRule, Rule, Declaration, ChildNode, ContainerBase } from 'pos
import { HintContext } from 'hint/dist/src/lib/hint-context';
import { IHint, ProblemLocation } from 'hint/dist/src/lib/types';
import { StyleEvents } from '@hint/parser-css/dist/src/types';
import { getUnsupported } from '@hint/utils/dist/src/compat';
import { getUnsupportedDetails, UnsupportedBrowsers } from '@hint/utils/dist/src/compat';
import { getCSSCodeSnippet } from '@hint/utils/dist/src/report';

import { filterBrowsers, joinBrowsers } from './utils/browsers';
Expand All @@ -21,7 +21,7 @@ import { getMessage } from './i18n.import';
type ReportData = {
feature: string;
node: ChildNode;
unsupported: string[];
unsupported: UnsupportedBrowsers;
};

type ReportMap = Map<string, ReportData[] | 'supported'>;
Expand Down Expand Up @@ -57,7 +57,7 @@ const validateAtRule = (node: AtRule, context: Context): ReportData | null => {
return null;
}

const unsupported = getUnsupported({ rule: node.name }, context.browsers);
const unsupported = getUnsupportedDetails({ rule: node.name }, context.browsers);

if (unsupported) {
return { feature: `@${node.name}`, node, unsupported };
Expand All @@ -69,7 +69,7 @@ const validateAtRule = (node: AtRule, context: Context): ReportData | null => {
};

const validateDeclValue = (node: Declaration, context: Context): ReportData | null => {
const unsupported = getUnsupported({ property: node.prop, value: node.value }, context.browsers);
const unsupported = getUnsupportedDetails({ property: node.prop, value: node.value }, context.browsers);

if (unsupported) {
return { feature: `${node.prop}: ${node.value}`, node, unsupported };
Expand All @@ -85,7 +85,7 @@ const validateDecl = (node: Declaration, context: Context): ReportData | null =>
return null;
}

const unsupported = getUnsupported({ property }, context.browsers);
const unsupported = getUnsupportedDetails({ property }, context.browsers);

if (unsupported) {
return { feature: `${property}`, node, unsupported };
Expand Down Expand Up @@ -132,12 +132,12 @@ const reportUnsupported = (reportsMap: ReportMap, context: Context): void => {
}

// Remove browsers not included in ALL reports for this property.
const unsupported = intersection(...reports.map((report) => {
return report.unsupported;
const browsers = intersection(...reports.map((report) => {
return report.unsupported.browsers;
}));

// Ignore if every browser passed at least one report for this property.
if (!unsupported.length) {
if (!browsers.length) {
continue;
}

Expand All @@ -156,6 +156,11 @@ const reportUnsupported = (reportsMap: ReportMap, context: Context): void => {
const finalReports = unprefixedReports.length ? unprefixedReports : reports;

for (const report of finalReports) {
const unsupported: UnsupportedBrowsers = {
browsers,
details: report.unsupported.details
};

context.report({ ...report, unsupported });
}
}
Expand Down
10 changes: 5 additions & 5 deletions packages/hint-compat-api/src/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { HintContext } from 'hint/dist/src/lib/hint-context';
import { IHint } from 'hint/dist/src/lib/types';
import { HTMLAttribute, HTMLElement } from '@hint/utils';
import { getUnsupported } from '@hint/utils/dist/src/compat';
import { getUnsupportedDetails, UnsupportedBrowsers } from '@hint/utils/dist/src/compat';

import { filterBrowsers, joinBrowsers } from './utils/browsers';
import { resolveIgnore } from './utils/ignore';
Expand All @@ -15,7 +15,7 @@ import { getMessage } from './i18n.import';

type ReportData = {
feature: string;
unsupported: string[];
unsupported: UnsupportedBrowsers;
};

type Context = {
Expand All @@ -29,7 +29,7 @@ const validateAttributeValue = (element: string, attr: HTMLAttribute, context: C
return;
}

const unsupported = getUnsupported({ attribute: attr.name, element, value: attr.value }, context.browsers);
const unsupported = getUnsupportedDetails({ attribute: attr.name, element, value: attr.value }, context.browsers);

if (unsupported) {
context.report({ feature: `${element}[${attr.name}=${attr.value}]`, unsupported });
Expand All @@ -41,7 +41,7 @@ const validateAttribute = (element: string, attr: HTMLAttribute, context: Contex
return;
}

const unsupported = getUnsupported({ attribute: attr.name, element }, context.browsers);
const unsupported = getUnsupportedDetails({ attribute: attr.name, element }, context.browsers);

if (unsupported) {
context.report({ feature: `${element}[${attr.name}]`, unsupported });
Expand All @@ -57,7 +57,7 @@ const validateElement = (node: HTMLElement, context: Context) => {
return;
}

const unsupported = getUnsupported({ element }, context.browsers);
const unsupported = getUnsupportedDetails({ element }, context.browsers);

if (unsupported) {
context.report({ feature: element, unsupported });
Expand Down
66 changes: 20 additions & 46 deletions packages/hint-compat-api/src/utils/browsers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import * as semver from 'semver';

const coerce = (version: string): semver.SemVer | string => {
return semver.coerce(version) || /* istanbul ignore next */ version;
};
import { UnsupportedBrowsers } from '@hint/utils/dist/src/compat';
import { getFriendlyName } from '@hint/utils/dist/src/compat/browsers';

/**
* Apply temporary filters to the list of target browsers to reduce
Expand Down Expand Up @@ -32,55 +29,32 @@ export const filterBrowsers = (browsers: string[]): string[] => {
};

/**
* Serialize condensed version ranges for provided browsers.
* Serialize summarized support ranges for provided browsers.
*
* ```js
* joinBrowsers(['chrome 74', 'chrome 75', 'chrome 76', 'edge 15', 'edge 16', 'firefox 67']);
* // returns 'chrome 74-76, edge 15-16, firefox 67';
* joinBrowsers({ browsers: ['edge 15'], browserDetails: new Map([['edge 15', { versionAdded: '18' }]]));
* // returns 'Edge < 18';
* ```
*/
export const joinBrowsers = (browsers: string[]): string => {
const versionsByName = new Map<string, string[]>();

// Group browser versions by browser name.
for (const browser of browsers) {
const [name, version] = browser.split(' ');
export const joinBrowsers = (unsupported: UnsupportedBrowsers): string => {
const summaries = unsupported.browsers.map((browser) => {
const name = getFriendlyName(browser);
const details = unsupported.details.get(browser);

if (!versionsByName.has(name)) {
versionsByName.set(name, []);
if (!details) {
throw new Error(`No details provided for browser: ${name}`);
}

versionsByName.get(name)!.push(version);
}

const results: string[] = [];

// Sort and serialize version ranges for each browser name.
for (const [name, versions] of versionsByName) {
versions.sort((v1, v2) => {
return semver.compare(coerce(v1), coerce(v2));
});

const ranges: string[] = [];

for (let i = 0, start = versions[0]; i < versions.length; i++) {
if (parseInt(versions[i + 1]) - parseInt(versions[i]) <= 1) {
continue; // Continue until the end of a range.
}

// Format current range as either `start` or `start-end`.
if (start === versions[i]) {
ranges.push(start);
} else {
ranges.push(`${start}-${versions[i]}`);
}

// Remember the start of the next range.
start = versions[i + 1];
if (details.versionAdded && details.versionRemoved) {
return `${name} ${details.versionRemoved}-${details.versionAdded}`;
} else if (details.versionAdded) {
return `${name} < ${details.versionAdded}`;
} else if (details.versionRemoved) {
return `${name} ${details.versionRemoved}+`;
}

results.push(`${name} ${ranges.join(', ')}`);
}
return name;
});

return results.join(', ');
return [...new Set(summaries)].sort().join(', ');
};
28 changes: 14 additions & 14 deletions packages/hint-compat-api/tests/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ testHint(hintPath,
name: 'Reports unsupported CSS at-rules',
reports: [
{
message: '@keyframes is not supported by ie 9.',
message: '@keyframes is not supported by Internet Explorer < 10.',
position: { match: '@keyframes' }
}
],
Expand All @@ -41,27 +41,27 @@ testHint(hintPath,
name: 'Reports unsupported properties, respecting prefixes and fallback',
reports: [
{
message: 'appearance is not supported by ie 9-11.',
message: 'appearance is not supported by Internet Explorer.',
position: { match: 'appearance: button; /* Report 1 */' }
},
{
message: 'appearance is not supported by ie 9-11.',
message: 'appearance is not supported by Internet Explorer.',
position: { match: 'appearance: button; /* Report 2 */' }
},
{
message: '-webkit-appearance is not supported by ie 9-11.',
message: '-webkit-appearance is not supported by Internet Explorer.',
position: { match: '-webkit-appearance: button; /* Report 3 */' }
},
{
message: '-moz-appearance is not supported by ie 9-11.',
message: '-moz-appearance is not supported by Internet Explorer.',
position: { match: '-moz-appearance: button; /* Report 4 */' }
},
{
message: '-webkit-appearance is not supported by firefox 65-66, ie 9-11.',
message: '-webkit-appearance is not supported by Firefox, Internet Explorer.',
position: { match: '-webkit-appearance: button; /* Report 5 */' }
},
{
message: 'appearance is not supported by chrome 73-74, edge 15-16, firefox 65-66, ie 9-11.',
message: 'appearance is not supported by Chrome, Edge, Firefox, Internet Explorer.',
position: { match: 'appearance: button; /* Report 6 */' }
}
],
Expand All @@ -74,7 +74,7 @@ testHint(hintPath,
* name: 'Reports unsupported CSS selectors',
* reports: [
* {
* message: ':valid is not supported by ie 9.',
* message: ':valid is not supported by Internet Explorer < 10.',
* position: { match: ':valid' }
* }
* ],
Expand All @@ -85,7 +85,7 @@ testHint(hintPath,
name: 'Respects CSS @supports rules when generating reports',
reports: [
{
message: 'display: grid is not supported by edge 15.',
message: 'display: grid is not supported by Edge < 16.',
position: { match: 'display: grid; /* Report */' }
}
],
Expand All @@ -95,19 +95,19 @@ testHint(hintPath,
name: 'Reports unsupported CSS property values, respecting prefixes and fallback',
reports: [
{
message: 'display: grid is not supported by ie 9.',
message: 'display: grid is not supported by Internet Explorer.',
position: { match: 'display: grid; /* Report 1 */' }
},
{
message: 'display: grid is not supported by ie 9.',
message: 'display: grid is not supported by Internet Explorer.',
position: { match: 'display: grid; /* Report 2 */' }
},
{
message: 'display: -ms-grid is not supported by chrome 73-74, firefox 65-66, ie 9.',
message: 'display: -ms-grid is not supported by Chrome, Firefox, Internet Explorer < 10.',
position: { match: 'display: -ms-grid; /* Report 3 */' }
},
{
message: 'display: grid is not supported by edge 15, ie 9-11.',
message: 'display: grid is not supported by Edge < 16, Internet Explorer.',
position: { match: 'display: grid; /* Report 4 */' }
}
],
Expand Down Expand Up @@ -139,7 +139,7 @@ testHint(hintPath,
name: 'Reports overridden ignored CSS features',
reports: [
{
message: 'appearance is not supported by ie 9-11.',
message: 'appearance is not supported by Internet Explorer.',
position: { match: 'appearance: none; /* unprefixed */' }
}
],
Expand Down
12 changes: 6 additions & 6 deletions packages/hint-compat-api/tests/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ testHint(hintPath,
name: 'Reports unsupported HTML attributes',
reports: [
{
message: 'img[srcset] is not supported by ie 10-11.',
message: 'img[srcset] is not supported by Internet Explorer.',
position: { match: 'img srcset=' }
},
{
message: 'div[hidden] is not supported by ie 10.',
message: 'div[hidden] is not supported by Internet Explorer < 11.',
position: { match: 'div hidden' }
}
],
Expand All @@ -35,11 +35,11 @@ testHint(hintPath,
name: 'Reports unsupported HTML elements',
reports: [
{
message: 'blink is not supported by chrome 73-74, edge 17-18, firefox 65-66, ie 10-11.',
message: 'blink is not supported by Chrome, Edge, Firefox 22+, Internet Explorer.',
position: { match: 'blink' }
},
{
message: 'details is not supported by edge 17-18, ie 10-11.',
message: 'details is not supported by Edge, Internet Explorer.',
position: { match: 'details' }
}
],
Expand All @@ -54,7 +54,7 @@ testHint(hintPath,
reports: [
// TODO: Include <form method="dialog"> or similar once MDN data is available
{
message: 'input[type=color] is not supported by ie 10-11.',
message: 'input[type=color] is not supported by Internet Explorer.',
position: { match: 'input type="color"' }
}
],
Expand All @@ -70,7 +70,7 @@ testHint(hintPath,
name: 'Reports overridden ignored HTML features',
reports: [
{
message: 'script[integrity] is not supported by ie 10-11.',
message: 'script[integrity] is not supported by Internet Explorer.',
position: { match: 'script integrity' }
}
],
Expand Down
Loading