123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- import Exception from './exception';
- function Visitor() {
- this.parents = [];
- }
- Visitor.prototype = {
- constructor: Visitor,
- mutating: false,
- // Visits a given value. If mutating, will replace the value if necessary.
- acceptKey: function(node, name) {
- let value = this.accept(node[name]);
- if (this.mutating) {
- // Hacky sanity check: This may have a few false positives for type for the helper
- // methods but will generally do the right thing without a lot of overhead.
- if (value && !Visitor.prototype[value.type]) {
- throw new Exception(
- 'Unexpected node type "' +
- value.type +
- '" found when accepting ' +
- name +
- ' on ' +
- node.type
- );
- }
- node[name] = value;
- }
- },
- // Performs an accept operation with added sanity check to ensure
- // required keys are not removed.
- acceptRequired: function(node, name) {
- this.acceptKey(node, name);
- if (!node[name]) {
- throw new Exception(node.type + ' requires ' + name);
- }
- },
- // Traverses a given array. If mutating, empty respnses will be removed
- // for child elements.
- acceptArray: function(array) {
- for (let i = 0, l = array.length; i < l; i++) {
- this.acceptKey(array, i);
- if (!array[i]) {
- array.splice(i, 1);
- i--;
- l--;
- }
- }
- },
- accept: function(object) {
- if (!object) {
- return;
- }
- /* istanbul ignore next: Sanity code */
- if (!this[object.type]) {
- throw new Exception('Unknown type: ' + object.type, object);
- }
- if (this.current) {
- this.parents.unshift(this.current);
- }
- this.current = object;
- let ret = this[object.type](object);
- this.current = this.parents.shift();
- if (!this.mutating || ret) {
- return ret;
- } else if (ret !== false) {
- return object;
- }
- },
- Program: function(program) {
- this.acceptArray(program.body);
- },
- MustacheStatement: visitSubExpression,
- Decorator: visitSubExpression,
- BlockStatement: visitBlock,
- DecoratorBlock: visitBlock,
- PartialStatement: visitPartial,
- PartialBlockStatement: function(partial) {
- visitPartial.call(this, partial);
- this.acceptKey(partial, 'program');
- },
- ContentStatement: function(/* content */) {},
- CommentStatement: function(/* comment */) {},
- SubExpression: visitSubExpression,
- PathExpression: function(/* path */) {},
- StringLiteral: function(/* string */) {},
- NumberLiteral: function(/* number */) {},
- BooleanLiteral: function(/* bool */) {},
- UndefinedLiteral: function(/* literal */) {},
- NullLiteral: function(/* literal */) {},
- Hash: function(hash) {
- this.acceptArray(hash.pairs);
- },
- HashPair: function(pair) {
- this.acceptRequired(pair, 'value');
- }
- };
- function visitSubExpression(mustache) {
- this.acceptRequired(mustache, 'path');
- this.acceptArray(mustache.params);
- this.acceptKey(mustache, 'hash');
- }
- function visitBlock(block) {
- visitSubExpression.call(this, block);
- this.acceptKey(block, 'program');
- this.acceptKey(block, 'inverse');
- }
- function visitPartial(partial) {
- this.acceptRequired(partial, 'name');
- this.acceptArray(partial.params);
- this.acceptKey(partial, 'hash');
- }
- export default Visitor;
|