All files / stylelint-plugin-craftsmanlint/src/rules/props-in-files index.ts

97.5% Statements 39/40
88% Branches 22/25
100% Functions 6/6
97.43% Lines 38/39

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97                1x                       1x 1x   25x 25x     1x       1x   1x 17x 17x       17x       17x   68x   68x 21x     47x 47x 47x 47x   47x   47x 47x 47x 47x 20x   27x   47x     47x 30x     47x 17x     47x 22x     25x                   1x 1x 1x   1x  
/**
 * Copyright (c) 2022-present, Matti Bar-Zeev.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
 
/* eslint-disable @pedalboard/craftsmanlint/no-namespace-imports */
import stylelint from 'stylelint';
import * as CSS from 'csstype';
import type * as PostCSS from 'postcss';
 
type Policy = {
    forbidden?: string[];
    allowed?: string[];
    valueRegex?: RegExp | string;
};
 
type PrimaryOption = Record<keyof CSS.StandardPropertiesHyphen, Partial<Policy>>;
 
const ruleName = 'stylelint-plugin-craftsmanlint/props-in-files';
const messages = stylelint.utils.ruleMessages(ruleName, {
    expected: (...args) => {
        const [prop, value] = args;
        return `"${prop}" CSS property with "${value}" value was found in a file it should not be in`;
    },
});
const meta = {
    url: 'https://github.com/mbarzeev/pedalboard/blob/master/packages/stylelint-plugin-craftsmanlint/README.md',
};
 
const ALL_FILES_KEYWORD = 'all';
 
const ruleFunction = (primaryOption: PrimaryOption) => {
    return (postcssRoot: PostCSS.Root, postcssResult: stylelint.PostcssResult) => {
        const validOptions = stylelint.utils.validateOptions(postcssResult, ruleName, {
            actual: null,
        });
 
        Iif (!validOptions) {
            return;
        }
 
        postcssRoot.walkDecls((decl: PostCSS.Declaration) => {
            // Iterate CSS declarations
            const propRule = primaryOption[decl.prop as keyof CSS.StandardPropertiesHyphen];
 
            if (!propRule) {
                return;
            }
 
            const file = postcssRoot?.source?.input?.file;
            const allowedFiles = propRule.allowed;
            const forbiddenFiles = propRule.forbidden;
            let shouldReport = false;
            const valueRegex =
                typeof propRule.valueRegex === 'string' ? new RegExp(propRule.valueRegex) : propRule.valueRegex;
 
            const isFileValid = (inspectedFile: string, index: number, files: string[]) => {
                let result = false;
                const isRegexValueComply = valueRegex ? valueRegex.test(decl.value) : true;
                if (files.includes(ALL_FILES_KEYWORD)) {
                    result = isRegexValueComply;
                } else {
                    result = (file?.includes(inspectedFile) as boolean) && isRegexValueComply;
                }
                return result;
            };
 
            if (allowedFiles) {
                shouldReport = !allowedFiles.some(isFileValid);
            }
 
            if (forbiddenFiles) {
                shouldReport = forbiddenFiles.some(isFileValid);
            }
 
            if (!shouldReport) {
                return;
            }
 
            stylelint.utils.report({
                ruleName,
                result: postcssResult,
                message: messages.expected(decl.prop, decl.value),
                node: decl,
            });
        });
    };
};
 
ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
ruleFunction.meta = meta;
 
export default ruleFunction;