UNPKG

stylelint-no-unsupported-browser-features

Version:

Disallow features that are unsupported by the browsers that you are targeting

121 lines (93 loc) 3.16 kB
import stylelint from 'stylelint'; import doiuse from 'doiuse'; import { Result } from 'postcss'; /** * Plugin settings */ const ruleName = 'plugin/no-unsupported-browser-features'; const messages = stylelint.utils.ruleMessages(ruleName, { rejected: (details) => `Unexpected browser feature ${details}`, }); /** * Options */ function isString(value) { return typeof value === 'string'; } function isBoolean(value) { return typeof value === 'boolean'; } const optionsSchema = { browsers: [isString], ignore: [isString], ignorePartialSupport: isBoolean, }; /** * Utilities */ function cleanWarningText(warningText, ignorePartialSupport) { // Get index of feature Id const featureIdIndex = warningText.lastIndexOf('('); // Get feature Id, then replace brackets with quotes const featureId = warningText.slice(featureIdIndex, warningText.length).replace(/\(|\)/g, '"'); // Get start of support text i.e. "x not supported by...", or "y only partially supported by..." const browserSupportStartIndex = warningText.indexOf('not') !== -1 ? warningText.indexOf('not') : warningText.indexOf('only'); // Get browser support text, then strip brackets. let browserSupport = warningText .slice(browserSupportStartIndex, featureIdIndex - 1) .replace(/\(|\)|:/g, ''); // Check if there's partial support for anything const andIndex = browserSupport.indexOf(' and'); // If there's an and, and partialSupport should be ignored, remove the partial support string if (ignorePartialSupport && andIndex !== -1) { browserSupport = browserSupport.slice(0, andIndex); } const cleanedWarningText = `${featureId} is ${browserSupport}`; return cleanedWarningText; } /** * The main plugin rule */ function ruleFunction(on, options) { return (root, result) => { const validOptions = stylelint.utils.validateOptions(result, ruleName, { actual: options, possible: optionsSchema, optional: true, }); if (!validOptions) { return; } const usedFeatures = {}; const doiuseResult = new Result(); const doiuseOptions = {}; if (options) { Object.keys(optionsSchema).forEach((optionsKey) => { doiuseOptions[optionsKey] = options[optionsKey]; }); } doiuseOptions.onFeatureUsage = (info) => { // Use the node as key to store feature information usedFeatures[info.usage] = info.featureData; }; const { ignorePartialSupport } = doiuseOptions; doiuse(doiuseOptions).postcss(root, doiuseResult); doiuseResult.warnings().forEach((doiuseWarning) => { const featureData = usedFeatures[doiuseWarning.node]; if (featureData && ignorePartialSupport && featureData.partial && !featureData.missing) { return; } stylelint.utils.report({ ruleName, result, message: messages.rejected(cleanWarningText(doiuseWarning.text, ignorePartialSupport)), node: doiuseWarning.node, }); }); }; } ruleFunction.ruleName = ruleName; ruleFunction.messages = messages; const plugin = stylelint.createPlugin(ruleName, ruleFunction); export default plugin;