'use strict';

exports.__esModule = true;
exports.parseWithoutProcessing = parseWithoutProcessing;
exports.parse = parse;
// istanbul ignore next

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }

// istanbul ignore next

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

var _parser = require('./parser');

var _parser2 = _interopRequireDefault(_parser);

var _whitespaceControl = require('./whitespace-control');

var _whitespaceControl2 = _interopRequireDefault(_whitespaceControl);

var _helpers = require('./helpers');

var Helpers = _interopRequireWildcard(_helpers);

var _exception = require('../exception');

var _exception2 = _interopRequireDefault(_exception);

var _utils = require('../utils');

exports.parser = _parser2['default'];

var yy = {};
_utils.extend(yy, Helpers);

function parseWithoutProcessing(input, options) {
  // Just return if an already-compiled AST was passed in.
  if (input.type === 'Program') {
    // When a pre-parsed AST is passed in, validate all node values to prevent
    // code injection via type-confused literals.
    validateInputAst(input);
    return input;
  }

  _parser2['default'].yy = yy;

  // Altering the shared object here, but this is ok as parser is a sync operation
  yy.locInfo = function (locInfo) {
    return new yy.SourceLocation(options && options.srcName, locInfo);
  };

  var ast = _parser2['default'].parse(input);

  return ast;
}

function parse(input, options) {
  var ast = parseWithoutProcessing(input, options);
  var strip = new _whitespaceControl2['default'](options);

  return strip.accept(ast);
}

function validateInputAst(ast) {
  validateAstNode(ast);
}

function validateAstNode(node) {
  if (node == null) {
    return;
  }

  if (Array.isArray(node)) {
    node.forEach(validateAstNode);
    return;
  }

  if (typeof node !== 'object') {
    return;
  }

  if (node.type === 'PathExpression') {
    if (!isValidDepth(node.depth)) {
      throw new _exception2['default']('Invalid AST: PathExpression.depth must be an integer');
    }
    if (!Array.isArray(node.parts)) {
      throw new _exception2['default']('Invalid AST: PathExpression.parts must be an array');
    }
    for (var i = 0; i < node.parts.length; i++) {
      if (typeof node.parts[i] !== 'string') {
        throw new _exception2['default']('Invalid AST: PathExpression.parts must only contain strings');
      }
    }
  } else if (node.type === 'NumberLiteral') {
    if (typeof node.value !== 'number' || !isFinite(node.value)) {
      throw new _exception2['default']('Invalid AST: NumberLiteral.value must be a number');
    }
  } else if (node.type === 'BooleanLiteral') {
    if (typeof node.value !== 'boolean') {
      throw new _exception2['default']('Invalid AST: BooleanLiteral.value must be a boolean');
    }
  }

  Object.keys(node).forEach(function (propertyName) {
    if (propertyName === 'loc') {
      return;
    }
    validateAstNode(node[propertyName]);
  });
}

function isValidDepth(depth) {
  return typeof depth === 'number' && isFinite(depth) && Math.floor(depth) === depth && depth >= 0;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 6528 characters]
