All files / src/util ast-config.js

100% Statements 4/4
100% Branches 8/8
100% Functions 1/1
100% Lines 4/4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115                    1x 1x                                                                   18x   18x                                                                                                                                      
/**
 * This file defines an object controlling AST-Query object for simpler config.
 *
 * AST-Query is still a little rough and hard to use. This makes grabbing and
 * setting a specific configuration object a little easier. Configuration being
 * something like an object sent out in `module.exports` or the Grunt config
 * object.
 */
 
// Require dependencies
import util from 'util';
import astQuery from 'ast-query';
 
export default class Config {
	/**
	 * Constructor for the Config object, wrapping an AST-Query object.
	 *
	 * `contents` is the contents that will be passed to the AST constructor.
	 * It will typically be a string of JS, such as you could run through
	 * something like `eval()` and have it work. But the JS will be stringified
	 * even if a raw object is passed as an example.
	 *
	 * `options` is a little more tricky. With options there is control over
	 * what the deafult object is, as well as basic control over formatting.
	 *
	 * To control the default location in the AST, you can pass a `query`,
	 * `queryMethod`, and `filter` function. These work to call methods on the
	 * AST-Query object to fetch a certain item location from the structured
	 * AST object. `queryMethod` defines what type of query is executed against
	 * the AST. `query` corresponds with the value passed to the query method.
	 * Finally after recieving the results from the query, filter allows the
	 * walking the returned object to the specific item desired. All of this
	 * makes use of the methods available in the AST Query package. See the
	 * [AST Query Docs]{@link https://github.com/SBoudrias/AST-query} for more
	 * more information.
	 *
	 * `formatOpts` allows defining the formatting options that will be passed
	 * to the AST query object and takes effect when it is turned into a string.
	 * This options object is formatted for and passed to
	 * [ESCodeGen]{@link https://github.com/estools/escodegen/wiki/API#options}
	 *
	 * @param  {String} contents The string contents of a JS file.
	 * @param  {Object} opts     Controls default queries and basic formatting.
	 * @return {Object}          The Config object.
	 */
	constructor ( contents, opts, ast = astQuery ) {
		// Set up options with defaults.
		const options = Object.assign(
			{
				type: 'module',
				query: 'module.exports',
				queryMethod: 'assignment',
				formatOpts: {
					format: {
						indent: {
							style: '\t',
							adjustMultilineComment: true
						}
					}
				}
			},
			opts || {}
		);
 
		// Set up object values.
		this.type = options.type;
		this.query = options.query;
		this.queryMethod = options.queryMethod;
		if ( options.filter && typeof options.filter === 'function' ) {
			this.filter = options.filter;
		} else {
			this.filter = val => val;
		}
		this.ast = ast( String( contents ), options.formatOpts, {
			sourceType: 'module'
		} );
	}
 
	/**
	 * Gets the defined default location inside the AST and returns it.
	 *
	 * @return {mixed} An AST object, type can vary.
	 */
	getDefault () {
		return this.filter( this.ast[ this.queryMethod ]( this.query ) );
	}
 
	/**
	 * Sets the defined default location to the new passed value.
	 *
	 * The passed value will be stringified and assigned into the AST at the
	 * default location.
	 *
	 * @param {mixed} options The item to return to the AST, usually a string.
	 * @return {void}
	 */
	setDefault ( newVal ) {
		// Stringify what was sent if needed.
		if ( typeof newVal !== 'string' ) {
			newVal = util.inspect( newVal, { depth: null } );
		}
		// Set the default value to the new string.
		this.getDefault().value( newVal );
	}
 
	/**
	 * Turns the AST object into into a JS code string.
	 *
	 * @return {String} The stringified JS code.
	 */
	toString () {
		return this.ast.toString();
	}
}