| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 | 'use strict';var use = require('use');var define = require('define-property');var debug = require('debug')('snapdragon:compiler');var utils = require('./utils');/** * Create a new `Compiler` with the given `options`. * @param {Object} `options` */function Compiler(options, state) {  debug('initializing', __filename);  this.options = utils.extend({source: 'string'}, options);  this.state = state || {};  this.compilers = {};  this.output = '';  this.set('eos', function(node) {    return this.emit(node.val, node);  });  this.set('noop', function(node) {    return this.emit(node.val, node);  });  this.set('bos', function(node) {    return this.emit(node.val, node);  });  use(this);}/** * Prototype methods */Compiler.prototype = {  /**   * Throw an error message with details including the cursor position.   * @param {String} `msg` Message to use in the Error.   */  error: function(msg, node) {    var pos = node.position || {start: {column: 0}};    var message = this.options.source + ' column:' + pos.start.column + ': ' + msg;    var err = new Error(message);    err.reason = msg;    err.column = pos.start.column;    err.source = this.pattern;    if (this.options.silent) {      this.errors.push(err);    } else {      throw err;    }  },  /**   * Define a non-enumberable property on the `Compiler` instance.   *   * ```js   * compiler.define('foo', 'bar');   * ```   * @name .define   * @param {String} `key` propery name   * @param {any} `val` property value   * @return {Object} Returns the Compiler instance for chaining.   * @api public   */  define: function(key, val) {    define(this, key, val);    return this;  },  /**   * Emit `node.val`   */  emit: function(str, node) {    this.output += str;    return str;  },  /**   * Add a compiler `fn` with the given `name`   */  set: function(name, fn) {    this.compilers[name] = fn;    return this;  },  /**   * Get compiler `name`.   */  get: function(name) {    return this.compilers[name];  },  /**   * Get the previous AST node.   */  prev: function(n) {    return this.ast.nodes[this.idx - (n || 1)] || { type: 'bos', val: '' };  },  /**   * Get the next AST node.   */  next: function(n) {    return this.ast.nodes[this.idx + (n || 1)] || { type: 'eos', val: '' };  },  /**   * Visit `node`.   */  visit: function(node, nodes, i) {    var fn = this.compilers[node.type];    this.idx = i;    if (typeof fn !== 'function') {      throw this.error('compiler "' + node.type + '" is not registered', node);    }    return fn.call(this, node, nodes, i);  },  /**   * Map visit over array of `nodes`.   */  mapVisit: function(nodes) {    if (!Array.isArray(nodes)) {      throw new TypeError('expected an array');    }    var len = nodes.length;    var idx = -1;    while (++idx < len) {      this.visit(nodes[idx], nodes, idx);    }    return this;  },  /**   * Compile `ast`.   */  compile: function(ast, options) {    var opts = utils.extend({}, this.options, options);    this.ast = ast;    this.parsingErrors = this.ast.errors;    this.output = '';    // source map support    if (opts.sourcemap) {      var sourcemaps = require('./source-maps');      sourcemaps(this);      this.mapVisit(this.ast.nodes);      this.applySourceMaps();      this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON();      return this;    }    this.mapVisit(this.ast.nodes);    return this;  }};/** * Expose `Compiler` */module.exports = Compiler;
 |