index.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // @ts-nocheck
  2. 'use strict';
  3. const declarationValueIndex = require('../../utils/declarationValueIndex');
  4. const findFontFamily = require('../../utils/findFontFamily');
  5. const isVariable = require('../../utils/isVariable');
  6. const keywordSets = require('../../reference/keywordSets');
  7. const optionsMatches = require('../../utils/optionsMatches');
  8. const postcss = require('postcss');
  9. const report = require('../../utils/report');
  10. const ruleMessages = require('../../utils/ruleMessages');
  11. const validateOptions = require('../../utils/validateOptions');
  12. const _ = require('lodash');
  13. const ruleName = 'font-family-no-missing-generic-family-keyword';
  14. const messages = ruleMessages(ruleName, {
  15. rejected: 'Unexpected missing generic font family',
  16. });
  17. const isFamilyNameKeyword = (node) =>
  18. !node.quote && keywordSets.fontFamilyKeywords.has(node.value.toLowerCase());
  19. function rule(actual, options) {
  20. return (root, result) => {
  21. const validOptions = validateOptions(
  22. result,
  23. ruleName,
  24. { actual },
  25. {
  26. actual: options,
  27. possible: {
  28. ignoreFontFamilies: [_.isString, _.isRegExp],
  29. },
  30. optional: true,
  31. },
  32. );
  33. if (!validOptions) {
  34. return;
  35. }
  36. root.walkDecls(/^font(-family)?$/i, (decl) => {
  37. // Ignore @font-face
  38. if (
  39. decl.parent &&
  40. decl.parent.type === 'atrule' &&
  41. decl.parent.name.toLowerCase() === 'font-face'
  42. ) {
  43. return;
  44. }
  45. if (decl.prop === 'font' && keywordSets.systemFontValues.has(decl.value.toLowerCase())) {
  46. return;
  47. }
  48. const fontFamilies = findFontFamily(decl.value);
  49. if (fontFamilies.length === 0) {
  50. return;
  51. }
  52. if (fontFamilies.some(isFamilyNameKeyword)) {
  53. return;
  54. }
  55. if (postcss.list.space(decl.value).some(isVariable)) {
  56. return;
  57. }
  58. if (fontFamilies.some((node) => optionsMatches(options, 'ignoreFontFamilies', node.value))) {
  59. return;
  60. }
  61. report({
  62. result,
  63. ruleName,
  64. message: messages.rejected,
  65. node: decl,
  66. index: declarationValueIndex(decl) + fontFamilies[fontFamilies.length - 1].sourceIndex,
  67. });
  68. });
  69. };
  70. }
  71. rule.ruleName = ruleName;
  72. rule.messages = messages;
  73. module.exports = rule;