'use strict'; const declarationValueIndex = require('../../utils/declarationValueIndex'); const findFontFamily = require('../../utils/findFontFamily'); const keywordSets = require('../../reference/keywordSets'); const optionsMatches = require('../../utils/optionsMatches'); const report = require('../../utils/report'); const ruleMessages = require('../../utils/ruleMessages'); const validateOptions = require('../../utils/validateOptions'); const _ = require('lodash'); const ruleName = 'font-family-no-missing-generic-family-keyword'; const messages = ruleMessages(ruleName, { rejected: 'Unexpected missing generic font family', }); const isFamilyNameKeyword = (node) => !node.quote && keywordSets.fontFamilyKeywords.has(node.value.toLowerCase()); function rule(actual, options) { return (root, result) => { const validOptions = validateOptions( result, ruleName, { actual }, { actual: options, possible: { ignoreFontFamilies: [_.isString, _.isRegExp], }, optional: true, }, ); if (!validOptions) { return; } root.walkDecls(/^font(-family)?$/i, (decl) => { // Ignore @font-face if ( decl.parent && decl.parent.type === 'atrule' && decl.parent.name.toLowerCase() === 'font-face' ) { return; } if (decl.prop === 'font' && keywordSets.systemFontValues.has(decl.value.toLowerCase())) { return; } const fontFamilies = findFontFamily(decl.value); if (fontFamilies.length === 0) { return; } if (fontFamilies.some(isFamilyNameKeyword)) { return; } if (fontFamilies.some((node) => optionsMatches(options, 'ignoreFontFamilies', node.value))) { return; } report({ result, ruleName, message: messages.rejected, node: decl, index: declarationValueIndex(decl) + fontFamilies[fontFamilies.length - 1].sourceIndex, }); }); }; } rule.ruleName = ruleName; rule.messages = messages; module.exports = rule;