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 parse = require( 'acorn' ).parse;
  var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
  var isBuffer = require( '@stdlib/assert/is-buffer' );
  var copy = require( '@stdlib/utils/copy' );
  var RE_EOL = require( '@stdlib/regexp/eol' );
  var DEFAULTS = require( './defaults.json' );
  var resultsObject = require( './results.js' );
  var whitespace = require( './whitespace.js' );
  var analyze = require( './analyze.js' );
  
  
  // VARIABLES //
  
  var RE_NON_WHITESPACE = /\S/;
  var RE_JSDOC = /^\/\*\*$/; // Note: this is strict!
  
  
  // MAIN //
  
  /**
  * Generates a summary of a JavaScript program.
  *
  * @param {(string|Buffer)} input - source code input
  * @throws {TypeError} must provide either a string or Buffer
  * @returns {Object} summary
  *
  * @example
  * var str = '"use strict";\n\nconsole.log( "beep" );\n';
  *
  * var out = summary( str );
  * // returns {...}
  */
  function summary( input ) {
  	var comments;
  	var results;
  	var lines;
  	var opts;
  	var ast;
  
  	if ( !isString( input ) && !isBuffer( input ) ) {
  		throw new TypeError( 'invalid argument. Must provide either a string or a Buffer. Value: `' + input + '`.' );
  	}
  	// Ensure that provided input is a `string`:
  	input = input.toString();
  
  	// Split the input into individual lines:
  	lines = input.split( RE_EOL );
  
  	// Initialize a results object:
  	results = resultsObject();
  
  	// Initialize a comments array:
  	comments = [];
  
  	// Parse the source code input into an Abstract Syntax Tree (AST):
  	opts = copy( DEFAULTS );
  	opts.onComment = onComment;
  	ast = parse( input, opts );
  
  	// Analyze the AST:
  	results = analyze( results, ast, input, comments, 0, 0 );
  
  	// Return the summary results:
  	return results;
  
  	/**
  	* Callback invoked upon encountering a comment.
  	*
  	* @private
  	* @param {boolean} block - boolean indicating whether a comment is a block comment
  	* @param {string} text - comment text
  	* @param {NonNegativeInteger} start - character offset for comment start
  	* @param {NonNegativeInteger} end - character offset for comment end
  	* @param {Object} pos1 - start location
  	* @param {Object} pos2 - end location
  	*/
  	function onComment( block, text, start, end, pos1, pos2 ) {
  		var inline;
  		var wchars;
  		var jsdoc;
  		var line;
  		var key;
  		var len;
  		var obj;
  		var N;
  
  		// Determine the number of lines:
  		N = pos2.line - pos1.line + 1;
  
  		// Determine the comment length:
  		len = end - start;
  
  		// Determine the number of whitespace characters:
  		wchars = whitespace( text );
  
  		// Determine if the comment is inline...
  		if ( N === 1 ) {
  			line = lines[ pos1.line-1 ];
  			line = line.substring( 0, pos1.column );
  			inline = RE_NON_WHITESPACE.test( line );
  		} else {
  			inline = false;
  		}
  		inline = ( inline ) ? 1 : 0;
  
  		// Determine if the comment is a JSDoc block comment...
  		if ( block ) {
  			line = lines[ pos1.line-1 ];
  			line = line.substring( pos1.column, pos1.column+3 ); // only the first 3 chars are needed
  			jsdoc = RE_JSDOC.test( line );
  		}
  		// Update sub-comment totals:
  		if ( block ) {
  			key = 'block';
  		} else {
  			key = 'line';
  		}
  		results.comments[ key ].count += 1;
  		results.comments[ key ].length += len;
  		results.comments[ key ].whitespace += wchars;
  		results.comments[ key ].lines += N;
  		results.comments[ key ].inline += inline;
  
  		if ( jsdoc ) {
  			results.comments.jsdoc.count += 1;
  			results.comments.jsdoc.length += len;
  			results.comments.jsdoc.whitespace += wchars;
  			results.comments.jsdoc.lines += N;
  			results.comments.jsdoc.inline += inline;
  		}
  		// Update total comment totals:
  		results.comments.count += 1;
  		results.comments.length += len;
  		results.comments.whitespace += wchars;
  		results.comments.lines += N;
  		results.comments.inline += inline;
  
  		// Append a comment summary:
  		obj = {
  			'type': key,
  			'length': len,
  			'whitespace': wchars,
  			'lines': N,
  			'inline': !!inline,
  			'jsdoc': !!jsdoc
  		};
  		results.comments.data.push( obj );
  
  		// Cache the comment data:
  		comments.push({
  			'start': start,
  			'end': end,
  			'summary': obj
  		});
  	}
  }
  
  
  // EXPORTS //
  
  module.exports = summary;
  