| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 | 
							- var hasOwnProperty = Object.prototype.hasOwnProperty;
 
- var noop = function() {};
 
- function ensureFunction(value) {
 
-     return typeof value === 'function' ? value : noop;
 
- }
 
- function invokeForType(fn, type) {
 
-     return function(node, item, list) {
 
-         if (node.type === type) {
 
-             fn.call(this, node, item, list);
 
-         }
 
-     };
 
- }
 
- function getWalkersFromStructure(name, nodeType) {
 
-     var structure = nodeType.structure;
 
-     var walkers = [];
 
-     for (var key in structure) {
 
-         if (hasOwnProperty.call(structure, key) === false) {
 
-             continue;
 
-         }
 
-         var fieldTypes = structure[key];
 
-         var walker = {
 
-             name: key,
 
-             type: false,
 
-             nullable: false
 
-         };
 
-         if (!Array.isArray(structure[key])) {
 
-             fieldTypes = [structure[key]];
 
-         }
 
-         for (var i = 0; i < fieldTypes.length; i++) {
 
-             var fieldType = fieldTypes[i];
 
-             if (fieldType === null) {
 
-                 walker.nullable = true;
 
-             } else if (typeof fieldType === 'string') {
 
-                 walker.type = 'node';
 
-             } else if (Array.isArray(fieldType)) {
 
-                 walker.type = 'list';
 
-             }
 
-         }
 
-         if (walker.type) {
 
-             walkers.push(walker);
 
-         }
 
-     }
 
-     if (walkers.length) {
 
-         return {
 
-             context: nodeType.walkContext,
 
-             fields: walkers
 
-         };
 
-     }
 
-     return null;
 
- }
 
- function getTypesFromConfig(config) {
 
-     var types = {};
 
-     for (var name in config.node) {
 
-         if (hasOwnProperty.call(config.node, name)) {
 
-             var nodeType = config.node[name];
 
-             if (!nodeType.structure) {
 
-                 throw new Error('Missed `structure` field in `' + name + '` node type definition');
 
-             }
 
-             types[name] = getWalkersFromStructure(name, nodeType);
 
-         }
 
-     }
 
-     return types;
 
- }
 
- function createTypeIterator(config, reverse) {
 
-     var fields = config.fields.slice();
 
-     var contextName = config.context;
 
-     var useContext = typeof contextName === 'string';
 
-     if (reverse) {
 
-         fields.reverse();
 
-     }
 
-     return function(node, context, walk, walkReducer) {
 
-         var prevContextValue;
 
-         if (useContext) {
 
-             prevContextValue = context[contextName];
 
-             context[contextName] = node;
 
-         }
 
-         for (var i = 0; i < fields.length; i++) {
 
-             var field = fields[i];
 
-             var ref = node[field.name];
 
-             if (!field.nullable || ref) {
 
-                 if (field.type === 'list') {
 
-                     var breakWalk = reverse
 
-                         ? ref.reduceRight(walkReducer, false)
 
-                         : ref.reduce(walkReducer, false);
 
-                     if (breakWalk) {
 
-                         return true;
 
-                     }
 
-                 } else if (walk(ref)) {
 
-                     return true;
 
-                 }
 
-             }
 
-         }
 
-         if (useContext) {
 
-             context[contextName] = prevContextValue;
 
-         }
 
-     };
 
- }
 
- function createFastTraveralMap(iterators) {
 
-     return {
 
-         Atrule: {
 
-             StyleSheet: iterators.StyleSheet,
 
-             Atrule: iterators.Atrule,
 
-             Rule: iterators.Rule,
 
-             Block: iterators.Block
 
-         },
 
-         Rule: {
 
-             StyleSheet: iterators.StyleSheet,
 
-             Atrule: iterators.Atrule,
 
-             Rule: iterators.Rule,
 
-             Block: iterators.Block
 
-         },
 
-         Declaration: {
 
-             StyleSheet: iterators.StyleSheet,
 
-             Atrule: iterators.Atrule,
 
-             Rule: iterators.Rule,
 
-             Block: iterators.Block,
 
-             DeclarationList: iterators.DeclarationList
 
-         }
 
-     };
 
- }
 
- module.exports = function createWalker(config) {
 
-     var types = getTypesFromConfig(config);
 
-     var iteratorsNatural = {};
 
-     var iteratorsReverse = {};
 
-     var breakWalk = Symbol('break-walk');
 
-     var skipNode = Symbol('skip-node');
 
-     for (var name in types) {
 
-         if (hasOwnProperty.call(types, name) && types[name] !== null) {
 
-             iteratorsNatural[name] = createTypeIterator(types[name], false);
 
-             iteratorsReverse[name] = createTypeIterator(types[name], true);
 
-         }
 
-     }
 
-     var fastTraversalIteratorsNatural = createFastTraveralMap(iteratorsNatural);
 
-     var fastTraversalIteratorsReverse = createFastTraveralMap(iteratorsReverse);
 
-     var walk = function(root, options) {
 
-         function walkNode(node, item, list) {
 
-             var enterRet = enter.call(context, node, item, list);
 
-             if (enterRet === breakWalk) {
 
-                 debugger;
 
-                 return true;
 
-             }
 
-             if (enterRet === skipNode) {
 
-                 return false;
 
-             }
 
-             if (iterators.hasOwnProperty(node.type)) {
 
-                 if (iterators[node.type](node, context, walkNode, walkReducer)) {
 
-                     return true;
 
-                 }
 
-             }
 
-             if (leave.call(context, node, item, list) === breakWalk) {
 
-                 return true;
 
-             }
 
-             return false;
 
-         }
 
-         var walkReducer = (ret, data, item, list) => ret || walkNode(data, item, list);
 
-         var enter = noop;
 
-         var leave = noop;
 
-         var iterators = iteratorsNatural;
 
-         var context = {
 
-             break: breakWalk,
 
-             skip: skipNode,
 
-             root: root,
 
-             stylesheet: null,
 
-             atrule: null,
 
-             atrulePrelude: null,
 
-             rule: null,
 
-             selector: null,
 
-             block: null,
 
-             declaration: null,
 
-             function: null
 
-         };
 
-         if (typeof options === 'function') {
 
-             enter = options;
 
-         } else if (options) {
 
-             enter = ensureFunction(options.enter);
 
-             leave = ensureFunction(options.leave);
 
-             if (options.reverse) {
 
-                 iterators = iteratorsReverse;
 
-             }
 
-             if (options.visit) {
 
-                 if (fastTraversalIteratorsNatural.hasOwnProperty(options.visit)) {
 
-                     iterators = options.reverse
 
-                         ? fastTraversalIteratorsReverse[options.visit]
 
-                         : fastTraversalIteratorsNatural[options.visit];
 
-                 } else if (!types.hasOwnProperty(options.visit)) {
 
-                     throw new Error('Bad value `' + options.visit + '` for `visit` option (should be: ' + Object.keys(types).join(', ') + ')');
 
-                 }
 
-                 enter = invokeForType(enter, options.visit);
 
-                 leave = invokeForType(leave, options.visit);
 
-             }
 
-         }
 
-         if (enter === noop && leave === noop) {
 
-             throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function');
 
-         }
 
-         walkNode(root);
 
-     };
 
-     walk.break = breakWalk;
 
-     walk.skip = skipNode;
 
-     walk.find = function(ast, fn) {
 
-         var found = null;
 
-         walk(ast, function(node, item, list) {
 
-             if (fn.call(this, node, item, list)) {
 
-                 found = node;
 
-                 return breakWalk;
 
-             }
 
-         });
 
-         return found;
 
-     };
 
-     walk.findLast = function(ast, fn) {
 
-         var found = null;
 
-         walk(ast, {
 
-             reverse: true,
 
-             enter: function(node, item, list) {
 
-                 if (fn.call(this, node, item, list)) {
 
-                     found = node;
 
-                     return breakWalk;
 
-                 }
 
-             }
 
-         });
 
-         return found;
 
-     };
 
-     walk.findAll = function(ast, fn) {
 
-         var found = [];
 
-         walk(ast, function(node, item, list) {
 
-             if (fn.call(this, node, item, list)) {
 
-                 found.push(node);
 
-             }
 
-         });
 
-         return found;
 
-     };
 
-     return walk;
 
- };
 
 
  |