text: /**
  * @license Apache-2.0
  *
  * Copyright (c) 2018 The Stdlib Authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *    http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
  
  'use strict';
  
  // MODULES //
  
  var copy = require( '@stdlib/utils/copy' );
  var hasOwnProp = require( '@stdlib/assert/has-own-property' );
  var DEFAULTS = require( './defaults.json' );
  
  
  // VARIABLES //
  
  var rule;
  
  
  // FUNCTIONS //
  
  /**
  * Rule to enforce that specified global variables are explicitly required before invocation.
  *
  * @param {Object} context - ESLint context
  * @returns {Object} validators
  */
  function main( context ) {
  	var options;
  	var opts;
  
  	opts = copy( DEFAULTS );
  	options = context.options[ 0 ];
  	if ( hasOwnProp( options, 'globals' ) ) {
  		opts.globals = options.globals;
  	}
  	/**
  	* Reports the error message.
  	*
  	* @private
  	* @param {ASTNode} node - node to report
  	* @param {string} name - name of global variable
  	*/
  	function report( node, name ) {
  		context.report({
  			'node': node,
  			'message': name+' is used without loading it beforehand via require()'
  		});
  	}
  
  	/**
  	* Checks whether a global is loaded via `require()` before invocation.
  	*
  	* @private
  	* @param {ASTNode} node - node to examine
  	* @returns {void}
  	*/
  	function validate( node ) {
  		var scope;
  		var name;
  		var i;
  
  		// Skip when the identifier refers to the key of an object:
  		if ( node.parent.type === 'MemberExpression' ) {
  			return void 0;
  		}
  
  		scope = context.getScope( node );
  		for ( i = 0; i < opts.globals.length; i++ ) {
  			name = opts.globals[ i ];
  			if ( node.name === name ) {
  				if ( !searchScopes( scope, name ) ) {
  					report( node, name );
  				}
  				break;
  			}
  		}
  	}
  
  	/**
  	* Traverses the parent scopes searching for a variable declaration of the given global variable.
  	*
  	* @private
  	* @param {Object} scope - scope to examine
  	* @param {string} name - name of the global variable
  	* @returns {boolean} boolean indicating whether a variable declaration for the given global was found
  	*/
  	function searchScopes( scope, name ) {
  		if ( !scope ) {
  			return false;
  		}
  		if ( scope.set.has( name ) ) {
  			// Check whether the definition is due to an implicit global or not:
  			return scope.set.get( name ).defs.length > 0;
  		}
  		return searchScopes( scope.upper, name );
  	}
  
  	return {
  		'Identifier': validate
  	};
  }
  
  
  // MAIN //
  
  rule = {
  	'meta': {
  		'docs': {
  			'description': 'enforce that specified globals are explicitly required before invocation'
  		},
  		'schema': [
  			{
  				'type': 'object',
  				'properties': {
  					'globals': {
  						'type': 'array'
  					}
  				},
  				'additionalProperties': false
  			}
  		]
  	},
  	'create': main
  };
  
  
  // EXPORTS //
  
  module.exports = rule;
  