source: imaps-frontend/node_modules/css-tree/lib/walker/create.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 7.6 KB
Line 
1var hasOwnProperty = Object.prototype.hasOwnProperty;
2var noop = function() {};
3
4function ensureFunction(value) {
5 return typeof value === 'function' ? value : noop;
6}
7
8function invokeForType(fn, type) {
9 return function(node, item, list) {
10 if (node.type === type) {
11 fn.call(this, node, item, list);
12 }
13 };
14}
15
16function getWalkersFromStructure(name, nodeType) {
17 var structure = nodeType.structure;
18 var walkers = [];
19
20 for (var key in structure) {
21 if (hasOwnProperty.call(structure, key) === false) {
22 continue;
23 }
24
25 var fieldTypes = structure[key];
26 var walker = {
27 name: key,
28 type: false,
29 nullable: false
30 };
31
32 if (!Array.isArray(structure[key])) {
33 fieldTypes = [structure[key]];
34 }
35
36 for (var i = 0; i < fieldTypes.length; i++) {
37 var fieldType = fieldTypes[i];
38 if (fieldType === null) {
39 walker.nullable = true;
40 } else if (typeof fieldType === 'string') {
41 walker.type = 'node';
42 } else if (Array.isArray(fieldType)) {
43 walker.type = 'list';
44 }
45 }
46
47 if (walker.type) {
48 walkers.push(walker);
49 }
50 }
51
52 if (walkers.length) {
53 return {
54 context: nodeType.walkContext,
55 fields: walkers
56 };
57 }
58
59 return null;
60}
61
62function getTypesFromConfig(config) {
63 var types = {};
64
65 for (var name in config.node) {
66 if (hasOwnProperty.call(config.node, name)) {
67 var nodeType = config.node[name];
68
69 if (!nodeType.structure) {
70 throw new Error('Missed `structure` field in `' + name + '` node type definition');
71 }
72
73 types[name] = getWalkersFromStructure(name, nodeType);
74 }
75 }
76
77 return types;
78}
79
80function createTypeIterator(config, reverse) {
81 var fields = config.fields.slice();
82 var contextName = config.context;
83 var useContext = typeof contextName === 'string';
84
85 if (reverse) {
86 fields.reverse();
87 }
88
89 return function(node, context, walk, walkReducer) {
90 var prevContextValue;
91
92 if (useContext) {
93 prevContextValue = context[contextName];
94 context[contextName] = node;
95 }
96
97 for (var i = 0; i < fields.length; i++) {
98 var field = fields[i];
99 var ref = node[field.name];
100
101 if (!field.nullable || ref) {
102 if (field.type === 'list') {
103 var breakWalk = reverse
104 ? ref.reduceRight(walkReducer, false)
105 : ref.reduce(walkReducer, false);
106
107 if (breakWalk) {
108 return true;
109 }
110 } else if (walk(ref)) {
111 return true;
112 }
113 }
114 }
115
116 if (useContext) {
117 context[contextName] = prevContextValue;
118 }
119 };
120}
121
122function createFastTraveralMap(iterators) {
123 return {
124 Atrule: {
125 StyleSheet: iterators.StyleSheet,
126 Atrule: iterators.Atrule,
127 Rule: iterators.Rule,
128 Block: iterators.Block
129 },
130 Rule: {
131 StyleSheet: iterators.StyleSheet,
132 Atrule: iterators.Atrule,
133 Rule: iterators.Rule,
134 Block: iterators.Block
135 },
136 Declaration: {
137 StyleSheet: iterators.StyleSheet,
138 Atrule: iterators.Atrule,
139 Rule: iterators.Rule,
140 Block: iterators.Block,
141 DeclarationList: iterators.DeclarationList
142 }
143 };
144}
145
146module.exports = function createWalker(config) {
147 var types = getTypesFromConfig(config);
148 var iteratorsNatural = {};
149 var iteratorsReverse = {};
150 var breakWalk = Symbol('break-walk');
151 var skipNode = Symbol('skip-node');
152
153 for (var name in types) {
154 if (hasOwnProperty.call(types, name) && types[name] !== null) {
155 iteratorsNatural[name] = createTypeIterator(types[name], false);
156 iteratorsReverse[name] = createTypeIterator(types[name], true);
157 }
158 }
159
160 var fastTraversalIteratorsNatural = createFastTraveralMap(iteratorsNatural);
161 var fastTraversalIteratorsReverse = createFastTraveralMap(iteratorsReverse);
162
163 var walk = function(root, options) {
164 function walkNode(node, item, list) {
165 var enterRet = enter.call(context, node, item, list);
166
167 if (enterRet === breakWalk) {
168 debugger;
169 return true;
170 }
171
172 if (enterRet === skipNode) {
173 return false;
174 }
175
176 if (iterators.hasOwnProperty(node.type)) {
177 if (iterators[node.type](node, context, walkNode, walkReducer)) {
178 return true;
179 }
180 }
181
182 if (leave.call(context, node, item, list) === breakWalk) {
183 return true;
184 }
185
186 return false;
187 }
188
189 var walkReducer = (ret, data, item, list) => ret || walkNode(data, item, list);
190 var enter = noop;
191 var leave = noop;
192 var iterators = iteratorsNatural;
193 var context = {
194 break: breakWalk,
195 skip: skipNode,
196
197 root: root,
198 stylesheet: null,
199 atrule: null,
200 atrulePrelude: null,
201 rule: null,
202 selector: null,
203 block: null,
204 declaration: null,
205 function: null
206 };
207
208 if (typeof options === 'function') {
209 enter = options;
210 } else if (options) {
211 enter = ensureFunction(options.enter);
212 leave = ensureFunction(options.leave);
213
214 if (options.reverse) {
215 iterators = iteratorsReverse;
216 }
217
218 if (options.visit) {
219 if (fastTraversalIteratorsNatural.hasOwnProperty(options.visit)) {
220 iterators = options.reverse
221 ? fastTraversalIteratorsReverse[options.visit]
222 : fastTraversalIteratorsNatural[options.visit];
223 } else if (!types.hasOwnProperty(options.visit)) {
224 throw new Error('Bad value `' + options.visit + '` for `visit` option (should be: ' + Object.keys(types).join(', ') + ')');
225 }
226
227 enter = invokeForType(enter, options.visit);
228 leave = invokeForType(leave, options.visit);
229 }
230 }
231
232 if (enter === noop && leave === noop) {
233 throw new Error('Neither `enter` nor `leave` walker handler is set or both aren\'t a function');
234 }
235
236 walkNode(root);
237 };
238
239 walk.break = breakWalk;
240 walk.skip = skipNode;
241
242 walk.find = function(ast, fn) {
243 var found = null;
244
245 walk(ast, function(node, item, list) {
246 if (fn.call(this, node, item, list)) {
247 found = node;
248 return breakWalk;
249 }
250 });
251
252 return found;
253 };
254
255 walk.findLast = function(ast, fn) {
256 var found = null;
257
258 walk(ast, {
259 reverse: true,
260 enter: function(node, item, list) {
261 if (fn.call(this, node, item, list)) {
262 found = node;
263 return breakWalk;
264 }
265 }
266 });
267
268 return found;
269 };
270
271 walk.findAll = function(ast, fn) {
272 var found = [];
273
274 walk(ast, function(node, item, list) {
275 if (fn.call(this, node, item, list)) {
276 found.push(node);
277 }
278 });
279
280 return found;
281 };
282
283 return walk;
284};
Note: See TracBrowser for help on using the repository browser.