Source: lib/compiler.js

"use strict"

var f = require('util').format,
  fs = require('fs'),
  jsfmt = require('jsfmt'),
  cc = require('closure-compiler'),
  M = require('mstring'),
  utils = require('./utils'),
  Optimizer = require('./optimizer'),
  Mark = require("markup-js");

var clone = require('./utils').clone,
  decorate = require('./utils').decorate;

var ObjectNode = require('./object');

/**
 * @fileOverview Contains the standard Compiler and ClosureCompiler classes
 */

/**
 * Validation error returned from validators
 *
 * @method
 * @param {string} message error validation
 * @param {array} path array of strings representing the element in the object that caused the error
 * @param {object} rule the vitesse object that caused the validation error
 * @param {object} value the value of the object that caused the failure
 * @param {array} errors all the failed child errors associated with the validation errors (allOf, oneOf, etc.)
 * @return {ValidationError}
 */
var ValidationError = function(message, path, rule, value, errors) {
  this.message = message;
  this.path = path;
  this.rule = rule;
  this.value = value;
  this.errors = errors;
}

// Wrap in validation method
var syncTemplate = M(function(){/***
  var ValidationError = function(message, path, rule, value, errors) {
    this.message = message;
    this.path = path;
    this.rule = rule;
    this.value = value;
    this.errors = errors;
  }

  var validate = function(object, context) {
    var context = context == null ? {} : context;
    var errors = [];
    var path = ['object'];

    {{functions}}

    {{statements}}

    return errors;
  };

  func = validate;
***/});

var generate = function(ast, options) {
  options = options || {};
  options = clone(options);

  // Reset count
  utils.resetId();

  // Total generation context
  var context = {
    functions: [],
    functionCalls: [],
    rules: options.rules,
    custom: options.custom,
    regexps: options.regexps,
    optimize: options.optimize
  }

  // Decorate the context
  decorate(context);

  // Generate the code
  ast.generate(context);

  // Generate final code
  var source = Mark.up(syncTemplate, {
    functions: context.functions.join('\n'),
    statements: context.functionCalls.map(function(x) {
      return x.replace('object.object', 'object');
    }).join('\n')
  });

  // Transform the source code
  if(options.optimize) {
    source = new Optimizer(options).optimize(source, ast);
  }

  // We enabled debugging, print the generated source
  if(options.debug) {
    // Format the final code
    var source = jsfmt.format(source);
    source = source.replace(/\n\n/g, "\n");
    // Output the source
    console.log(source);
  }

  return source;
}

/**
 * The Compiler class
 * 
 * @class
 * @return {Compiler} a Compiler instance.
 */
var Compiler = function() {
}

/**
 * compile a AST into a validator function
 *
 * @method
 * @param {object} ast AST of validation nodes
 * @param {object} [options.optimize=true] optimize enable/disable basic optimizations for the generated code
 * @return {object} returns the object containing the validator function
 */
Compiler.prototype.compile = function(ast, options) {
  options = options ? clone(options) : {};
  // Variables used in the eval
  var rules = [];
  var regexps = {};
  var custom = {};
  var func = null;
  // Add to the options
  options.regexps = regexps;
  options.rules = rules;
  options.custom = custom;
  options.optimize = typeof options.optimize == 'boolean'
    ? options.optimize : true;

  // Generate the source
  var source = generate(ast, options);

  // Compile the function
  eval(source)

  // Return the validation function
  return {
    validate: func
  }
}

/**
 * The ClosureCompiler class that wraps the Google closure compiler
 * 
 * @class
 * @return {ClosureCompiler} a ClosureCompiler instance.
 */
var ClosureCompiler = function() {}

/**
 * compile a AST into a validator function
 *
 * @method
 * @param {object} ast AST of validation nodes
 * @param {object} options compiler options
 * @param {function} callback returns the validation function
 */
ClosureCompiler.prototype.compile = function(ast, options, callback) {
  if(typeof options == 'function') callback = options; options = {};
  options = options ? clone(options) : {};
  // Variables used in the eval
  var rules = [];
  var regexps = {};
  var custom = {};
  var func = null;
  // Add to the options
  options.regexps = regexps;
  options.rules = rules;
  options.custom = custom;
  // Generate the source code
  var source = generate(ast, options);
  // Run closure compiler on the result
  // Compiler flags
  var compilerFlags = {
  };

  // Handle closure compiler result
  var done = function(err, stdout, stderr) {
    if(err) return callback(err);
    // Get the transformed source
    var source = stdout;
    // Compile the function
    eval(source)
    // Return the validation function
    callback(null, {
      validate: func
    });
  }

  // Execute the closure compiler
  cc.compile(source, compilerFlags, done);
}


module.exports = {
  Compiler: Compiler, ClosureCompiler: ClosureCompiler
}
comments powered by Disqus