'use strict'; const report = require('../../utils/report'); const ruleMessages = require('../../utils/ruleMessages'); const validateOptions = require('../../utils/validateOptions'); const ruleName = 'no-irregular-whitespace'; const messages = ruleMessages(ruleName, { unexpected: 'Unexpected irregular whitespace', }); const meta = { url: 'https://stylelint.io/user-guide/rules/no-irregular-whitespace', }; const IRREGULAR_WHITESPACES = [ '\u000B', // Line Tabulation (\v) - '\u000C', // Form Feed (\f) - '\u00A0', // No-Break Space - '\u0085', // Next Line '\u1680', // Ogham Space Mark '\u180E', // Mongolian Vowel Separator - '\uFEFF', // Zero Width No-Break Space - '\u2000', // En Quad '\u2001', // Em Quad '\u2002', // En Space - '\u2003', // Em Space - '\u2004', // Tree-Per-Em '\u2005', // Four-Per-Em '\u2006', // Six-Per-Em '\u2007', // Figure Space '\u2008', // Punctuation Space - '\u2009', // Thin Space '\u200A', // Hair Space '\u200B', // Zero Width Space - '\u2028', // Line Separator '\u2029', // Paragraph Separator '\u202F', // Narrow No-Break Space '\u205F', // Medium Mathematical Space '\u3000', // Ideographic Space ]; const IRREGULAR_WHITESPACES_PATTERN = new RegExp(`([${IRREGULAR_WHITESPACES.join('')}])`); /** * @param {string} str * @returns {string | null} */ const findIrregularWhitespace = (str) => { const result = IRREGULAR_WHITESPACES_PATTERN.exec(str); return (result && result[1]) || null; }; /** @type {import('stylelint').Rule} */ const rule = (primary) => { return (root, result) => { const validOptions = validateOptions(result, ruleName, { actual: primary }); if (!validOptions) { return; } /** * @param {import('postcss').Node} node * @param {string | undefined} value */ const validate = (node, value) => { const issue = value && findIrregularWhitespace(value); if (issue) { report({ ruleName, result, message: messages.unexpected, node, word: issue, }); } }; root.walkAtRules((atRule) => { validate(atRule, atRule.name); validate(atRule, atRule.params); validate(atRule, atRule.raws.before); validate(atRule, atRule.raws.after); validate(atRule, atRule.raws.afterName); validate(atRule, atRule.raws.between); }); root.walkRules((ruleNode) => { validate(ruleNode, ruleNode.selector); validate(ruleNode, ruleNode.raws.before); validate(ruleNode, ruleNode.raws.after); validate(ruleNode, ruleNode.raws.between); }); root.walkDecls((decl) => { validate(decl, decl.prop); validate(decl, decl.value); validate(decl, decl.raws.before); validate(decl, decl.raws.between); }); }; }; rule.ruleName = ruleName; rule.messages = messages; rule.meta = meta; module.exports = rule;