function lint( options, clbk ) {
	var opts;
	var err;
	var dir;
	var cb;

	opts = {};
	if ( arguments.length > 1 ) {
		cb = clbk;
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	} else {
		cb = options;
	}
	if ( !isFunction( cb ) ) {
		throw new TypeError( format( 'invalid argument. Last argument must be a function. Value: `%s`.', cb ) );
	}
	debug( 'Options: %s', JSON.stringify( opts ) );

	dir = getRoot( opts.dir || '' );
	debug( 'Base directory: %s', dir );

	debug( 'Resolving namespaces...' );
	namespaces( opts, onList );

	/**
	* Callback invoked upon resolving a list of namespaces.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {(EmptyArray|StringArray)} list - list of namespaces
	* @returns {void}
	*/
	function onList( error, list ) {
		if ( error ) {
			debug( 'Encountered an error when resolving namespaces: %s', error.message );
			return done( error );
		}
		if ( list.length === 0 ) {
			debug( 'Unable to resolve any namespaces.' );
			return done( null, [] );
		}
		debug( 'Successfully resolved %d namespaces: %s', list.length, list.join( ',' ) );

		debug( 'Resolving main entry points...' );
		resolve( list, dir, onResolve );
	}

	/**
	* Callback invoked upon resolving package entry points.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {ObjectArray} pkgs - results
	* @returns {void}
	*/
	function onResolve( error, pkgs ) {
		if ( error ) {
			debug( 'Encountered an error when resolving namespace main entry points: %s', error.message );
			return done( error );
		}
		debug( 'Successfully resolved main entry points.' );

		debug( 'Linting namespace aliases...' );
		linter( pkgs, onLint );
	}

	/**
	* Callback invoked upon lint completion.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {(EmptyArray|ObjectArray)} results - lint errors
	* @returns {void}
	*/
	function onLint( error, results ) {
		if ( error ) {
			debug( 'Encountered an error when linting namespaces: %s', error.message );
			return done( error );
		}
		debug( 'Finished linting namespaces.' );
		debug( 'Found %d lint errors.', results.length );
		debug( 'Lint errors: %s', JSON.stringify( results ) );

		done( null, results );
	}

	/**
	* Callback invoked upon completion.
	*
	* @private
	* @param {(Error|null)} error - error object
	* @param {(EmptyArray|ObjectArray)} results - lint errors
	* @returns {void}
	*/
	function done( error, results ) {
		if ( error ) {
			return cb( error );
		}
		cb( null, results );
	}
}
Asynchronously lints namespace aliases.

@param {Options} [options] - function options
@param {string} [options.dir] - root directory from which to search for namespaces
@param {Callback} clbk - callback to invoke upon completion
@throws {TypeError} options argument must be an object
@throws {TypeError} must provide valid options
@throws {TypeError} last argument must be a function

@example
lint( onLint );

function onLint( error, errs ) {
    if ( error ) {
        throw error;
    }
    if ( errs.length ) {
        console.error( JSON.stringify( errs ) );
    } else {
        console.error( 'No detected errors.' );
    }
}