Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / no-use-before-define.js
diff --git a/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/no-use-before-define.js b/.config/coc/extensions/node_modules/coc-prettier/node_modules/eslint/lib/rules/no-use-before-define.js
new file mode 100644 (file)
index 0000000..ed35405
--- /dev/null
@@ -0,0 +1,229 @@
+/**
+ * @fileoverview Rule to flag use of variables before they are defined
+ * @author Ilya Volodin
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const SENTINEL_TYPE = /^(?:(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|CatchClause|ImportDeclaration|ExportNamedDeclaration)$/u;
+const FOR_IN_OF_TYPE = /^For(?:In|Of)Statement$/u;
+
+/**
+ * Parses a given value as options.
+ * @param {any} options A value to parse.
+ * @returns {Object} The parsed options.
+ */
+function parseOptions(options) {
+    let functions = true;
+    let classes = true;
+    let variables = true;
+
+    if (typeof options === "string") {
+        functions = (options !== "nofunc");
+    } else if (typeof options === "object" && options !== null) {
+        functions = options.functions !== false;
+        classes = options.classes !== false;
+        variables = options.variables !== false;
+    }
+
+    return { functions, classes, variables };
+}
+
+/**
+ * Checks whether or not a given variable is a function declaration.
+ * @param {eslint-scope.Variable} variable A variable to check.
+ * @returns {boolean} `true` if the variable is a function declaration.
+ */
+function isFunction(variable) {
+    return variable.defs[0].type === "FunctionName";
+}
+
+/**
+ * Checks whether or not a given variable is a class declaration in an upper function scope.
+ * @param {eslint-scope.Variable} variable A variable to check.
+ * @param {eslint-scope.Reference} reference A reference to check.
+ * @returns {boolean} `true` if the variable is a class declaration.
+ */
+function isOuterClass(variable, reference) {
+    return (
+        variable.defs[0].type === "ClassName" &&
+        variable.scope.variableScope !== reference.from.variableScope
+    );
+}
+
+/**
+ * Checks whether or not a given variable is a variable declaration in an upper function scope.
+ * @param {eslint-scope.Variable} variable A variable to check.
+ * @param {eslint-scope.Reference} reference A reference to check.
+ * @returns {boolean} `true` if the variable is a variable declaration.
+ */
+function isOuterVariable(variable, reference) {
+    return (
+        variable.defs[0].type === "Variable" &&
+        variable.scope.variableScope !== reference.from.variableScope
+    );
+}
+
+/**
+ * Checks whether or not a given location is inside of the range of a given node.
+ * @param {ASTNode} node An node to check.
+ * @param {number} location A location to check.
+ * @returns {boolean} `true` if the location is inside of the range of the node.
+ */
+function isInRange(node, location) {
+    return node && node.range[0] <= location && location <= node.range[1];
+}
+
+/**
+ * Checks whether or not a given reference is inside of the initializers of a given variable.
+ *
+ * This returns `true` in the following cases:
+ *
+ *     var a = a
+ *     var [a = a] = list
+ *     var {a = a} = obj
+ *     for (var a in a) {}
+ *     for (var a of a) {}
+ * @param {Variable} variable A variable to check.
+ * @param {Reference} reference A reference to check.
+ * @returns {boolean} `true` if the reference is inside of the initializers.
+ */
+function isInInitializer(variable, reference) {
+    if (variable.scope !== reference.from) {
+        return false;
+    }
+
+    let node = variable.identifiers[0].parent;
+    const location = reference.identifier.range[1];
+
+    while (node) {
+        if (node.type === "VariableDeclarator") {
+            if (isInRange(node.init, location)) {
+                return true;
+            }
+            if (FOR_IN_OF_TYPE.test(node.parent.parent.type) &&
+                isInRange(node.parent.parent.right, location)
+            ) {
+                return true;
+            }
+            break;
+        } else if (node.type === "AssignmentPattern") {
+            if (isInRange(node.right, location)) {
+                return true;
+            }
+        } else if (SENTINEL_TYPE.test(node.type)) {
+            break;
+        }
+
+        node = node.parent;
+    }
+
+    return false;
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = {
+    meta: {
+        type: "problem",
+
+        docs: {
+            description: "disallow the use of variables before they are defined",
+            category: "Variables",
+            recommended: false,
+            url: "https://eslint.org/docs/rules/no-use-before-define"
+        },
+
+        schema: [
+            {
+                oneOf: [
+                    {
+                        enum: ["nofunc"]
+                    },
+                    {
+                        type: "object",
+                        properties: {
+                            functions: { type: "boolean" },
+                            classes: { type: "boolean" },
+                            variables: { type: "boolean" }
+                        },
+                        additionalProperties: false
+                    }
+                ]
+            }
+        ]
+    },
+
+    create(context) {
+        const options = parseOptions(context.options[0]);
+
+        /**
+         * Determines whether a given use-before-define case should be reported according to the options.
+         * @param {eslint-scope.Variable} variable The variable that gets used before being defined
+         * @param {eslint-scope.Reference} reference The reference to the variable
+         * @returns {boolean} `true` if the usage should be reported
+         */
+        function isForbidden(variable, reference) {
+            if (isFunction(variable)) {
+                return options.functions;
+            }
+            if (isOuterClass(variable, reference)) {
+                return options.classes;
+            }
+            if (isOuterVariable(variable, reference)) {
+                return options.variables;
+            }
+            return true;
+        }
+
+        /**
+         * Finds and validates all variables in a given scope.
+         * @param {Scope} scope The scope object.
+         * @returns {void}
+         * @private
+         */
+        function findVariablesInScope(scope) {
+            scope.references.forEach(reference => {
+                const variable = reference.resolved;
+
+                /*
+                 * Skips when the reference is:
+                 * - initialization's.
+                 * - referring to an undefined variable.
+                 * - referring to a global environment variable (there're no identifiers).
+                 * - located preceded by the variable (except in initializers).
+                 * - allowed by options.
+                 */
+                if (reference.init ||
+                    !variable ||
+                    variable.identifiers.length === 0 ||
+                    (variable.identifiers[0].range[1] < reference.identifier.range[1] && !isInInitializer(variable, reference)) ||
+                    !isForbidden(variable, reference)
+                ) {
+                    return;
+                }
+
+                // Reports.
+                context.report({
+                    node: reference.identifier,
+                    message: "'{{name}}' was used before it was defined.",
+                    data: reference.identifier
+                });
+            });
+
+            scope.childScopes.forEach(findVariablesInScope);
+        }
+
+        return {
+            Program() {
+                findVariablesInScope(context.getScope());
+            }
+        };
+    }
+};