@terrazzo/parser
Version:
Parser/validator for the Design Tokens Community Group (DTCG) standard.
98 lines • 4.12 kB
JavaScript
import { tokenToColor } from '@terrazzo/token-tools';
import { inGamut } from 'colorjs.io/fn';
import { docsLink } from '../lib/docs.js';
import { cachedLintMatcher } from '../lib/matchers.js';
export const MAX_GAMUT = 'core/max-gamut';
const ERROR_COLOR = 'COLOR';
const ERROR_BORDER = 'BORDER';
const ERROR_GRADIENT = 'GRADIENT';
const ERROR_SHADOW = 'SHADOW';
const rule = {
meta: {
messages: {
[ERROR_COLOR]: 'Color {{ id }} is outside {{ gamut }} gamut',
[ERROR_BORDER]: 'Border {{ id }} is outside {{ gamut }} gamut',
[ERROR_GRADIENT]: 'Gradient {{ id }} is outside {{ gamut }} gamut',
[ERROR_SHADOW]: 'Shadow {{ id }} is outside {{ gamut }} gamut',
},
docs: {
description: 'Enforce colors are within the specified gamut.',
url: docsLink(MAX_GAMUT),
},
},
defaultOptions: { gamut: 'rec2020' },
create({ tokens, options, report }) {
if (!options?.gamut) {
return;
}
if (options.gamut !== 'srgb' && options.gamut !== 'p3' && options.gamut !== 'rec2020') {
throw new Error(`Unknown gamut "${options.gamut}". Options are "srgb", "p3", or "rec2020"`);
}
const shouldIgnore = options.ignore ? cachedLintMatcher.tokenIDMatch(options.ignore) : null;
for (const t of Object.values(tokens)) {
// skip ignored tokens
if (shouldIgnore?.(t.id)) {
continue;
}
// skip aliases
if (t.aliasOf) {
continue;
}
switch (t.$type) {
case 'color': {
if (!inGamut(tokenToColor(t.$value), options.gamut)) {
report({
messageId: ERROR_COLOR,
data: { id: t.id, gamut: options.gamut },
node: t.source.node,
filename: t.source.filename,
});
}
break;
}
case 'border': {
if (!t.partialAliasOf?.color && !inGamut(tokenToColor(t.$value.color), options.gamut)) {
report({
messageId: ERROR_BORDER,
data: { id: t.id, gamut: options.gamut },
node: t.source.node,
filename: t.source.filename,
});
}
break;
}
case 'gradient': {
for (let stopI = 0; stopI < t.$value.length; stopI++) {
if (!t.partialAliasOf?.[stopI]?.color &&
!inGamut(tokenToColor(t.$value[stopI].color), options.gamut)) {
report({
messageId: ERROR_GRADIENT,
data: { id: t.id, gamut: options.gamut },
node: t.source.node,
filename: t.source.filename,
});
}
}
break;
}
case 'shadow': {
for (let shadowI = 0; shadowI < t.$value.length; shadowI++) {
if (!t.partialAliasOf?.[shadowI]?.color &&
// oxlint-disable-next-line no-non-null-assertion
!inGamut(tokenToColor(t.$value[shadowI].color), options.gamut)) {
report({
messageId: ERROR_SHADOW,
data: { id: t.id, gamut: options.gamut },
node: t.source.node,
filename: t.source.filename,
});
}
}
break;
}
}
}
},
};
export default rule;
//# sourceMappingURL=max-gamut.js.map