function addDeclaredGlobals(
	globalScope,
	configGlobals = {},
	inlineGlobals = {},
) {
	// Define configured global variables.
	for (const id of new Set([
		...Object.keys(configGlobals),
		...Object.keys(inlineGlobals),
	])) {
		/*
		 * `normalizeConfigGlobal` will throw an error if a configured global value is invalid. However, these errors would
		 * typically be caught when validating a config anyway (validity for inline global comments is checked separately).
		 */
		const configValue =
			configGlobals[id] === void 0
				? void 0
				: normalizeConfigGlobal(configGlobals[id]);
		const commentValue = inlineGlobals[id] && inlineGlobals[id].value;
		const value = commentValue || configValue;
		const sourceComments = inlineGlobals[id] && inlineGlobals[id].comments;

		if (value === "off") {
			continue;
		}

		let variable = globalScope.set.get(id);

		if (!variable) {
			variable = new eslintScope.Variable(id, globalScope);

			globalScope.variables.push(variable);
			globalScope.set.set(id, variable);
		}

		variable.eslintImplicitGlobalSetting = configValue;
		variable.eslintExplicitGlobal = sourceComments !== void 0;
		variable.eslintExplicitGlobalComments = sourceComments;
		variable.writeable = value === "writable";
	}

	/*
	 * "through" contains all references which definitions cannot be found.
	 * Since we augment the global scope using configuration, we need to update
	 * references and remove the ones that were added by configuration.
	 */
	globalScope.through = globalScope.through.filter(reference => {
		const name = reference.identifier.name;
		const variable = globalScope.set.get(name);

		if (variable) {
			/*
			 * Links the variable and the reference.
			 * And this reference is removed from `Scope#through`.
			 */
			reference.resolved = variable;
			variable.references.push(reference);

			return false;
		}

		return true;
	});

	/*
	 * "implicit" contains information about implicit global variables (those created
	 * implicitly by assigning values to undeclared variables in non-strict code).
	 * Since we augment the global scope using configuration, we need to remove
	 * the ones that were added by configuration, as they are either built-in
	 * or declared elsewhere, therefore not implicit.
	 * Since the "implicit" property was not documented, first we'll check if it exists
	 * because it's possible that not all custom scope managers create this property.
	 * If it exists, we assume it has properties `variables` and `set`. Property
	 * `left` is considered optional (for example, typescript-eslint's scope manage
	 * has this property named `leftToBeResolved`).
	 */
	const { implicit } = globalScope;
	if (typeof implicit === "object" && implicit !== null) {
		implicit.variables = implicit.variables.filter(variable => {
			const name = variable.name;
			if (globalScope.set.has(name)) {
				implicit.set.delete(name);
				return false;
			}
			return true;
		});

		if (implicit.left) {
			implicit.left = implicit.left.filter(
				reference => !globalScope.set.has(reference.identifier.name),
			);
		}
	}
}
Ensures that variables representing built-in properties of the Global Object,
and any globals declared by special block comments, are present in the global
scope.
@param {Scope} globalScope The global scope.
@param {Object|undefined} configGlobals The globals declared in configuration
@param {Object|undefined} inlineGlobals The globals declared in the source code
@returns {void}