/**
* Copyright IBM Corp. 2016, 2021
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
const Audit = require('lighthouse').Audit;
const constants = require('../../config/constants');
const i18n = require(constants.paths.i18n);
const UIStrings = {
title: 'Carbon Design System color tokens are not being overwritten.',
failureTitle: 'Carbon Design System color tokens are being overwritten.',
description:
'Color token values must adhere to the guidelines specified by the Carbon Design System. To address the issue, replace any hard-coded hex values with the correct color tokens. [Learn more](https://www.carbondesignsystem.com/guidelines/color/usage/)',
};
const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);
const colorJson = {
'--cds-ui-background': ['#fff', '#f4f4f4', '#262626', '#161616'],
'--cds-interactive-01': ['#0f62fe'],
'--cds-interactive-02': ['#393939', '#6f6f6f'],
'--cds-interactive-03': ['#0f62fe', '#fff'],
'--cds-interactive-04': ['#0f62fe', '#4589ff'],
'--cds-danger-01': ['#da1e28'],
'--cds-danger-02': ['#da1e28', '#ff8389', '#fa4d56'],
'--cds-ui-01': ['#f4f4f4', '#fff', '#393939', '#262626'],
'--cds-ui-02': ['#fff', '#f4f4f4', '#525252', '#393939'],
'--cds-ui-03': ['#e0e0e0', '#525252', '#393939'],
'--cds-ui-04': ['#8d8d8d', '#6f6f6f'],
'--cds-ui-05': ['#161616', '#f4f4f4'],
'--cds-button-separator': ['#e0e0e0', '#161616'],
'--cds-decorative-01': ['#e0e0e0', '#6f6f6f', '#525252'],
'--cds-text-01': ['#161616', '#f4f4f4'],
'--cds-text-02': ['#525252', '#c6c6c6'],
'--cds-text-03': ['#a8a8a8', '#6f6f6f'],
'--cds-text-04': ['#fff'],
'--cds-text-05': ['#6f6f6f', '#8d8d8d'],
'--cds-text-error': ['#da1e28', '#ffb3b8', '#ff8389'],
'--cds-link-01': ['#0f62fe', '#78a9ff'],
'--cds-link-02': ['#0043ce', '#a6c8ff'],
'--cds-inverse-link': ['#78a9ff', '#0f62fe'],
'--cds-icon-01': ['#161616', '#f4f4f4'],
'--cds-icon-02': ['#525252', '#c6c6c6'],
'--cds-icon-03': ['#fff'],
'--cds-field-01': ['#f4f4f4', '#fff', '#393939', '#262626'],
'--cds-field-02': ['#fff', '#f4f4f4', '#525252', '#393939'],
'--cds-inverse-01': ['#fff', '#161616'],
'--cds-inverse-02': ['#393939', '#f4f4f4'],
'--cds-support-01': ['#da1e28', '#ff8389', '#fa4d56'],
'--cds-support-02': ['#198038', '#42be65', '#24a148'],
'--cds-support-03': ['#f1c21b'],
'--cds-support-04': ['#0043ce', '#4589ff'],
'--cds-inverse-support-01': ['#fa4d56', '#da1e28'],
'--cds-inverse-support-02': ['#42be65', '#24a148'],
'--cds-inverse-support-03': ['#f1c21b'],
'--cds-inverse-support-04': ['#4589ff', '#0043ce', '#0f62fe'],
'--cds-overlay-01': [
'rgba(22,22,22,0.5)',
'rgba(22,22,22,0.7)',
'rgba(0,0,0,0.65)',
],
'--cds-focus': ['#0f62fe', '#fff'],
'--cds-inverse-focus-ui': ['#fff', '#0f62fe'],
'--cds-hover-primary': ['#0353e9'],
'--cds-hover-primary-text': ['#0043ce', '#a6c8ff'],
'--cds-hover-secondary': ['#4c4c4c', '#606060'],
'--cds-hover-tertiary': ['#0353e9', '#f4f4f4'],
'--cds-hover-ui': ['#e5e5e5', '#4c4c4c', '#353535'],
'--cds-hover-light-ui': ['#e5e5e5', '#656565', '#4c4c4c'],
'--cds-hover-selected-ui': ['#cacaca', '#656565', '#4c4c4c'],
'--cds-hover-danger': ['#ba1b23', '#b81921'],
'--cds-hover-row': ['#e5e5e5', '#4c4c4c', '#353535'],
'--cds-inverse-hover-ui': ['#4c4c4c', '#e5e5e5'],
'--cds-active-primary': ['#002d9c'],
'--cds-active-secondary': ['#6f6f6f', '#393939'],
'--cds-active-tertiary': ['#002d9c', '#c6c6c6'],
'--cds-active-ui': ['#c6c6c6', '#6f6f6f', '#525252'],
'--cds-active-light-ui': ['#c6c6c6', '#8d8d8d', '#6f6f6f'],
'--cds-active-danger': ['#750e13'],
'--cds-selected-ui': ['#e0e0e0', '#525252', '#393939'],
'--cds-selected-light-ui': ['#e0e0e0', '#6f6f6f', '#525252'],
'--cds-highlight': ['#d0e2ff', '#edf5ff', '#002d9c', '#001d6c', '#0043ce'],
'--cds-skeleton-01': ['#e5e5e5', '#353535'],
'--cds-skeleton-02': ['#c6c6c6', '#525252'],
'--cds-visited-link': ['#8a3ffc', '#be95ff'],
'--cds-disabled-01': ['#f4f4f4', '#fff', '#393939', '#262626'],
'--cds-disabled-02': ['#c6c6c6', '#6f6f6f', '#525252'],
'--cds-disabled-03': ['#8d8d8d', '#6f6f6f', '#a8a8a8'],
};
/**
* @file Audits if page contains the Accessibility legal link
*/
class ColorUsageAudit extends Audit {
/**
* @returns {*} {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'color-usage-audit',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.failureTitle),
description: str_(UIStrings.description),
// The name of the custom gatherer class that provides input to this audit.
requiredArtifacts: ['CSSUsage'],
};
}
/**
* @param {object} artifacts Audit artifacts
* @returns {*} Audit artifacts
*/
static audit(artifacts) {
const loadMetrics = artifacts.CSSUsage;
let tokenArray = [];
loadMetrics.stylesheets.forEach((rules) => {
const filteredStyles = rules.content
.replace(/\n/g, '')
.split(';')
.filter((e) => e.trim().startsWith('--cds'));
filteredStyles.forEach((style) => {
const str = style.split(':');
str[0] = str[0].trim();
/* eslint-disable no-useless-escape */
let tokenValue = !str[1].startsWith('var')
? str[1]
: str[1].match(/\,(.*)\)/)[1];
tokenValue = tokenValue.split('}')[0].trim();
/* eslint-enable no-useless-escape */
if (!tokenArray[str[0]]) tokenArray[str[0]] = [];
if (tokenArray[str[0]].indexOf(tokenValue) === -1) {
tokenArray[str[0]].push(tokenValue);
}
});
});
let diffValues = 0;
let tableRows = [];
for (let key in tokenArray) {
// eslint-disable-next-line no-prototype-builtins
if (colorJson.hasOwnProperty(key)) {
let difference = tokenArray[key].filter(
(x) => !colorJson[key].includes(x)
);
if (difference.length > 0) {
tableRows.push({
name: key,
'wrong-value': difference.toString(),
'should-equal': colorJson[key].toString(),
});
}
diffValues += difference.length;
}
}
// binary scoring
const score = !diffValues ? 1 : 0;
const displayString = diffValues
? `${diffValues} color tokens with different values`
: '';
const headings = [
{ key: 'name', itemType: 'text', text: 'Token name' },
{ key: 'wrong-value', itemType: 'text', text: 'Wrong value' },
{ key: 'should-equal', itemType: 'text', text: 'Should equal' },
];
const details = Audit.makeTableDetails(headings, tableRows);
return {
rawValue: loadMetrics,
score: Number(score),
displayValue: displayString,
details,
};
}
}
module.exports = ColorUsageAudit;