.
This commit is contained in:
		
							
								
								
									
										276
									
								
								qwen/nodejs/node_modules/eslint/lib/rules/new-cap.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								qwen/nodejs/node_modules/eslint/lib/rules/new-cap.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,276 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @fileoverview Rule to flag use of constructors without capital letters
 | 
			
		||||
 * @author Nicholas C. Zakas
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
// Requirements
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
const astUtils = require("./utils/ast-utils");
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
// Helpers
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
const CAPS_ALLOWED = [
 | 
			
		||||
    "Array",
 | 
			
		||||
    "Boolean",
 | 
			
		||||
    "Date",
 | 
			
		||||
    "Error",
 | 
			
		||||
    "Function",
 | 
			
		||||
    "Number",
 | 
			
		||||
    "Object",
 | 
			
		||||
    "RegExp",
 | 
			
		||||
    "String",
 | 
			
		||||
    "Symbol",
 | 
			
		||||
    "BigInt"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Ensure that if the key is provided, it must be an array.
 | 
			
		||||
 * @param {Object} obj Object to check with `key`.
 | 
			
		||||
 * @param {string} key Object key to check on `obj`.
 | 
			
		||||
 * @param {any} fallback If obj[key] is not present, this will be returned.
 | 
			
		||||
 * @throws {TypeError} If key is not an own array type property of `obj`.
 | 
			
		||||
 * @returns {string[]} Returns obj[key] if it's an Array, otherwise `fallback`
 | 
			
		||||
 */
 | 
			
		||||
function checkArray(obj, key, fallback) {
 | 
			
		||||
 | 
			
		||||
    /* c8 ignore start */
 | 
			
		||||
    if (Object.prototype.hasOwnProperty.call(obj, key) && !Array.isArray(obj[key])) {
 | 
			
		||||
        throw new TypeError(`${key}, if provided, must be an Array`);
 | 
			
		||||
    }/* c8 ignore stop */
 | 
			
		||||
    return obj[key] || fallback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A reducer function to invert an array to an Object mapping the string form of the key, to `true`.
 | 
			
		||||
 * @param {Object} map Accumulator object for the reduce.
 | 
			
		||||
 * @param {string} key Object key to set to `true`.
 | 
			
		||||
 * @returns {Object} Returns the updated Object for further reduction.
 | 
			
		||||
 */
 | 
			
		||||
function invert(map, key) {
 | 
			
		||||
    map[key] = true;
 | 
			
		||||
    return map;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Creates an object with the cap is new exceptions as its keys and true as their values.
 | 
			
		||||
 * @param {Object} config Rule configuration
 | 
			
		||||
 * @returns {Object} Object with cap is new exceptions.
 | 
			
		||||
 */
 | 
			
		||||
function calculateCapIsNewExceptions(config) {
 | 
			
		||||
    let capIsNewExceptions = checkArray(config, "capIsNewExceptions", CAPS_ALLOWED);
 | 
			
		||||
 | 
			
		||||
    if (capIsNewExceptions !== CAPS_ALLOWED) {
 | 
			
		||||
        capIsNewExceptions = capIsNewExceptions.concat(CAPS_ALLOWED);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return capIsNewExceptions.reduce(invert, {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
// Rule Definition
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/** @type {import('../shared/types').Rule} */
 | 
			
		||||
module.exports = {
 | 
			
		||||
    meta: {
 | 
			
		||||
        type: "suggestion",
 | 
			
		||||
 | 
			
		||||
        docs: {
 | 
			
		||||
            description: "Require constructor names to begin with a capital letter",
 | 
			
		||||
            recommended: false,
 | 
			
		||||
            url: "https://eslint.org/docs/latest/rules/new-cap"
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        schema: [
 | 
			
		||||
            {
 | 
			
		||||
                type: "object",
 | 
			
		||||
                properties: {
 | 
			
		||||
                    newIsCap: {
 | 
			
		||||
                        type: "boolean",
 | 
			
		||||
                        default: true
 | 
			
		||||
                    },
 | 
			
		||||
                    capIsNew: {
 | 
			
		||||
                        type: "boolean",
 | 
			
		||||
                        default: true
 | 
			
		||||
                    },
 | 
			
		||||
                    newIsCapExceptions: {
 | 
			
		||||
                        type: "array",
 | 
			
		||||
                        items: {
 | 
			
		||||
                            type: "string"
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    newIsCapExceptionPattern: {
 | 
			
		||||
                        type: "string"
 | 
			
		||||
                    },
 | 
			
		||||
                    capIsNewExceptions: {
 | 
			
		||||
                        type: "array",
 | 
			
		||||
                        items: {
 | 
			
		||||
                            type: "string"
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    capIsNewExceptionPattern: {
 | 
			
		||||
                        type: "string"
 | 
			
		||||
                    },
 | 
			
		||||
                    properties: {
 | 
			
		||||
                        type: "boolean",
 | 
			
		||||
                        default: true
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                additionalProperties: false
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        messages: {
 | 
			
		||||
            upper: "A function with a name starting with an uppercase letter should only be used as a constructor.",
 | 
			
		||||
            lower: "A constructor name should not start with a lowercase letter."
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    create(context) {
 | 
			
		||||
 | 
			
		||||
        const config = Object.assign({}, context.options[0]);
 | 
			
		||||
 | 
			
		||||
        config.newIsCap = config.newIsCap !== false;
 | 
			
		||||
        config.capIsNew = config.capIsNew !== false;
 | 
			
		||||
        const skipProperties = config.properties === false;
 | 
			
		||||
 | 
			
		||||
        const newIsCapExceptions = checkArray(config, "newIsCapExceptions", []).reduce(invert, {});
 | 
			
		||||
        const newIsCapExceptionPattern = config.newIsCapExceptionPattern ? new RegExp(config.newIsCapExceptionPattern, "u") : null;
 | 
			
		||||
 | 
			
		||||
        const capIsNewExceptions = calculateCapIsNewExceptions(config);
 | 
			
		||||
        const capIsNewExceptionPattern = config.capIsNewExceptionPattern ? new RegExp(config.capIsNewExceptionPattern, "u") : null;
 | 
			
		||||
 | 
			
		||||
        const listeners = {};
 | 
			
		||||
 | 
			
		||||
        const sourceCode = context.sourceCode;
 | 
			
		||||
 | 
			
		||||
        //--------------------------------------------------------------------------
 | 
			
		||||
        // Helpers
 | 
			
		||||
        //--------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Get exact callee name from expression
 | 
			
		||||
         * @param {ASTNode} node CallExpression or NewExpression node
 | 
			
		||||
         * @returns {string} name
 | 
			
		||||
         */
 | 
			
		||||
        function extractNameFromExpression(node) {
 | 
			
		||||
            return node.callee.type === "Identifier"
 | 
			
		||||
                ? node.callee.name
 | 
			
		||||
                : astUtils.getStaticPropertyName(node.callee) || "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Returns the capitalization state of the string -
 | 
			
		||||
         * Whether the first character is uppercase, lowercase, or non-alphabetic
 | 
			
		||||
         * @param {string} str String
 | 
			
		||||
         * @returns {string} capitalization state: "non-alpha", "lower", or "upper"
 | 
			
		||||
         */
 | 
			
		||||
        function getCap(str) {
 | 
			
		||||
            const firstChar = str.charAt(0);
 | 
			
		||||
 | 
			
		||||
            const firstCharLower = firstChar.toLowerCase();
 | 
			
		||||
            const firstCharUpper = firstChar.toUpperCase();
 | 
			
		||||
 | 
			
		||||
            if (firstCharLower === firstCharUpper) {
 | 
			
		||||
 | 
			
		||||
                // char has no uppercase variant, so it's non-alphabetic
 | 
			
		||||
                return "non-alpha";
 | 
			
		||||
            }
 | 
			
		||||
            if (firstChar === firstCharLower) {
 | 
			
		||||
                return "lower";
 | 
			
		||||
            }
 | 
			
		||||
            return "upper";
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Check if capitalization is allowed for a CallExpression
 | 
			
		||||
         * @param {Object} allowedMap Object mapping calleeName to a Boolean
 | 
			
		||||
         * @param {ASTNode} node CallExpression node
 | 
			
		||||
         * @param {string} calleeName Capitalized callee name from a CallExpression
 | 
			
		||||
         * @param {Object} pattern RegExp object from options pattern
 | 
			
		||||
         * @returns {boolean} Returns true if the callee may be capitalized
 | 
			
		||||
         */
 | 
			
		||||
        function isCapAllowed(allowedMap, node, calleeName, pattern) {
 | 
			
		||||
            const sourceText = sourceCode.getText(node.callee);
 | 
			
		||||
 | 
			
		||||
            if (allowedMap[calleeName] || allowedMap[sourceText]) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (pattern && pattern.test(sourceText)) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const callee = astUtils.skipChainExpression(node.callee);
 | 
			
		||||
 | 
			
		||||
            if (calleeName === "UTC" && callee.type === "MemberExpression") {
 | 
			
		||||
 | 
			
		||||
                // allow if callee is Date.UTC
 | 
			
		||||
                return callee.object.type === "Identifier" &&
 | 
			
		||||
                    callee.object.name === "Date";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return skipProperties && callee.type === "MemberExpression";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Reports the given messageId for the given node. The location will be the start of the property or the callee.
 | 
			
		||||
         * @param {ASTNode} node CallExpression or NewExpression node.
 | 
			
		||||
         * @param {string} messageId The messageId to report.
 | 
			
		||||
         * @returns {void}
 | 
			
		||||
         */
 | 
			
		||||
        function report(node, messageId) {
 | 
			
		||||
            let callee = astUtils.skipChainExpression(node.callee);
 | 
			
		||||
 | 
			
		||||
            if (callee.type === "MemberExpression") {
 | 
			
		||||
                callee = callee.property;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            context.report({ node, loc: callee.loc, messageId });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //--------------------------------------------------------------------------
 | 
			
		||||
        // Public
 | 
			
		||||
        //--------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
        if (config.newIsCap) {
 | 
			
		||||
            listeners.NewExpression = function(node) {
 | 
			
		||||
 | 
			
		||||
                const constructorName = extractNameFromExpression(node);
 | 
			
		||||
 | 
			
		||||
                if (constructorName) {
 | 
			
		||||
                    const capitalization = getCap(constructorName);
 | 
			
		||||
                    const isAllowed = capitalization !== "lower" || isCapAllowed(newIsCapExceptions, node, constructorName, newIsCapExceptionPattern);
 | 
			
		||||
 | 
			
		||||
                    if (!isAllowed) {
 | 
			
		||||
                        report(node, "lower");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (config.capIsNew) {
 | 
			
		||||
            listeners.CallExpression = function(node) {
 | 
			
		||||
 | 
			
		||||
                const calleeName = extractNameFromExpression(node);
 | 
			
		||||
 | 
			
		||||
                if (calleeName) {
 | 
			
		||||
                    const capitalization = getCap(calleeName);
 | 
			
		||||
                    const isAllowed = capitalization !== "upper" || isCapAllowed(capIsNewExceptions, node, calleeName, capIsNewExceptionPattern);
 | 
			
		||||
 | 
			
		||||
                    if (!isAllowed) {
 | 
			
		||||
                        report(node, "upper");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return listeners;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user