2024-08-09 12:04:48 +00:00
/ * *
* @ fileoverview Rule to check for implicit global variables , functions and classes .
* @ author Joshua Peek
* /
"use strict" ;
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
2024-08-21 06:34:30 +00:00
/** @type {import('../shared/types').Rule} */
2024-08-09 12:04:48 +00:00
module . exports = {
meta : {
type : "suggestion" ,
docs : {
2024-08-21 06:34:30 +00:00
description : "Disallow declarations in the global scope" ,
2024-08-09 12:04:48 +00:00
recommended : false ,
2024-08-21 06:34:30 +00:00
url : "https://eslint.org/docs/latest/rules/no-implicit-globals"
2024-08-09 12:04:48 +00:00
} ,
schema : [ {
type : "object" ,
properties : {
lexicalBindings : {
type : "boolean" ,
default : false
}
} ,
additionalProperties : false
} ] ,
messages : {
globalNonLexicalBinding : "Unexpected {{kind}} declaration in the global scope, wrap in an IIFE for a local variable, assign as global property for a global variable." ,
globalLexicalBinding : "Unexpected {{kind}} declaration in the global scope, wrap in a block or in an IIFE." ,
globalVariableLeak : "Global variable leak, declare the variable if it is intended to be local." ,
assignmentToReadonlyGlobal : "Unexpected assignment to read-only global variable." ,
redeclarationOfReadonlyGlobal : "Unexpected redeclaration of read-only global variable."
}
} ,
create ( context ) {
const checkLexicalBindings = context . options [ 0 ] && context . options [ 0 ] . lexicalBindings === true ;
2024-08-21 06:34:30 +00:00
const sourceCode = context . sourceCode ;
2024-08-09 12:04:48 +00:00
/ * *
* Reports the node .
* @ param { ASTNode } node Node to report .
* @ param { string } messageId Id of the message to report .
* @ param { string | undefined } kind Declaration kind , can be 'var' , 'const' , 'let' , function or class .
* @ returns { void }
* /
function report ( node , messageId , kind ) {
context . report ( {
node ,
messageId ,
data : {
kind
}
} ) ;
}
return {
2024-08-21 06:34:30 +00:00
Program ( node ) {
const scope = sourceCode . getScope ( node ) ;
2024-08-09 12:04:48 +00:00
scope . variables . forEach ( variable => {
// Only ESLint global variables have the `writable` key.
const isReadonlyEslintGlobalVariable = variable . writeable === false ;
const isWritableEslintGlobalVariable = variable . writeable === true ;
if ( isWritableEslintGlobalVariable ) {
// Everything is allowed with writable ESLint global variables.
return ;
}
2024-08-21 06:34:30 +00:00
// Variables exported by "exported" block comments
if ( variable . eslintExported ) {
return ;
}
2024-08-09 12:04:48 +00:00
variable . defs . forEach ( def => {
const defNode = def . node ;
if ( def . type === "FunctionName" || ( def . type === "Variable" && def . parent . kind === "var" ) ) {
if ( isReadonlyEslintGlobalVariable ) {
report ( defNode , "redeclarationOfReadonlyGlobal" ) ;
} else {
report (
defNode ,
"globalNonLexicalBinding" ,
def . type === "FunctionName" ? "function" : ` ' ${ def . parent . kind } ' `
) ;
}
}
if ( checkLexicalBindings ) {
if ( def . type === "ClassName" ||
( def . type === "Variable" && ( def . parent . kind === "let" || def . parent . kind === "const" ) ) ) {
if ( isReadonlyEslintGlobalVariable ) {
report ( defNode , "redeclarationOfReadonlyGlobal" ) ;
} else {
report (
defNode ,
"globalLexicalBinding" ,
def . type === "ClassName" ? "class" : ` ' ${ def . parent . kind } ' `
) ;
}
}
}
} ) ;
} ) ;
// Undeclared assigned variables.
scope . implicit . variables . forEach ( variable => {
const scopeVariable = scope . set . get ( variable . name ) ;
let messageId ;
if ( scopeVariable ) {
// ESLint global variable
if ( scopeVariable . writeable ) {
return ;
}
messageId = "assignmentToReadonlyGlobal" ;
} else {
// Reference to an unknown variable, possible global leak.
messageId = "globalVariableLeak" ;
}
// def.node is an AssignmentExpression, ForInStatement or ForOfStatement.
variable . defs . forEach ( def => {
report ( def . node , messageId ) ;
} ) ;
} ) ;
}
} ;
}
} ;