@terrazzo/parser
Version:
Parser/validator for the Design Tokens Community Group (DTCG) standard.
106 lines • 4.09 kB
JavaScript
import { getObjMember } from '@terrazzo/json-schema-tools';
import { isAlias } from '@terrazzo/token-tools';
import { docsLink } from '../lib/docs.js';
export const VALID_DURATION = 'core/valid-duration';
const ERROR_FORMAT = 'ERROR_FORMAT';
const ERROR_INVALID_PROP = 'ERROR_INVALID_PROP';
const ERROR_LEGACY = 'ERROR_LEGACY';
const ERROR_UNIT = 'ERROR_UNIT';
const ERROR_VALUE = 'ERROR_VALUE';
const rule = {
meta: {
messages: {
[ERROR_FORMAT]: 'Migrate to the new object format: { "value": 2, "unit": "ms" }.',
[ERROR_LEGACY]: 'Migrate to the new object format: { "value": 10, "unit": "px" }.',
[ERROR_INVALID_PROP]: 'Unknown property: {{ key }}.',
[ERROR_UNIT]: 'Unknown unit {{ unit }}. Expected "ms" or "s".',
[ERROR_VALUE]: 'Expected number, received {{ value }}.',
},
docs: {
description: 'Require duration tokens to follow the format',
url: docsLink(VALID_DURATION),
},
},
defaultOptions: {
legacyFormat: false,
unknownUnits: false,
},
create({ tokens, options, report }) {
for (const t of Object.values(tokens)) {
if (t.aliasOf || !t.originalValue) {
continue;
}
switch (t.$type) {
case 'duration': {
validateDuration(t.originalValue.$value, {
node: getObjMember(t.source.node, '$value'),
filename: t.source.filename,
options,
report,
});
break;
}
case 'transition': {
if (typeof t.originalValue.$value === 'object') {
const $valueNode = getObjMember(t.source.node, '$value');
for (const property of ['duration', 'delay']) {
if (t.originalValue.$value[property] &&
!isAlias(t.originalValue.$value[property])) {
validateDuration(t.originalValue.$value[property], {
node: getObjMember($valueNode, property),
filename: t.source.filename,
options,
report,
});
}
}
}
break;
}
}
}
},
};
function validateDuration(value, { node, filename, options, report, }) {
if (value && typeof value === 'object') {
for (const key of Object.keys(value)) {
if (!['value', 'unit'].includes(key)) {
report({
data: { key: JSON.stringify(key) },
filename,
messageId: ERROR_INVALID_PROP,
node: getObjMember(node, key) ?? node,
});
}
}
const { unit, value: numValue } = value;
if (!('value' in value || 'unit' in value)) {
report({ data: { value }, filename, messageId: ERROR_FORMAT, node });
return;
}
if (!options.unknownUnits && !['ms', 's'].includes(unit)) {
report({
data: { unit },
filename,
messageId: ERROR_UNIT,
node: getObjMember(node, 'unit') ?? node,
});
}
if (!Number.isFinite(numValue)) {
report({
data: { value },
filename,
messageId: ERROR_VALUE,
node: getObjMember(node, 'value') ?? node,
});
}
}
else if (typeof value === 'string' && !options.legacyFormat) {
report({ filename, messageId: ERROR_FORMAT, node });
}
else {
report({ data: { value }, filename, messageId: ERROR_FORMAT, node });
}
}
export default rule;
//# sourceMappingURL=valid-duration.js.map