source: trip-planner-front/node_modules/snapdragon-node/index.js@ eed0bf8

Last change on this file since eed0bf8 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 11.0 KB
RevLine 
[6a3a178]1'use strict';
2
3var isObject = require('isobject');
4var define = require('define-property');
5var utils = require('snapdragon-util');
6var ownNames;
7
8/**
9 * Create a new AST `Node` with the given `val` and `type`.
10 *
11 * ```js
12 * var node = new Node('*', 'Star');
13 * var node = new Node({type: 'star', val: '*'});
14 * ```
15 * @name Node
16 * @param {String|Object} `val` Pass a matched substring, or an object to merge onto the node.
17 * @param {String} `type` The node type to use when `val` is a string.
18 * @return {Object} node instance
19 * @api public
20 */
21
22function Node(val, type, parent) {
23 if (typeof type !== 'string') {
24 parent = type;
25 type = null;
26 }
27
28 define(this, 'parent', parent);
29 define(this, 'isNode', true);
30 define(this, 'expect', null);
31
32 if (typeof type !== 'string' && isObject(val)) {
33 lazyKeys();
34 var keys = Object.keys(val);
35 for (var i = 0; i < keys.length; i++) {
36 var key = keys[i];
37 if (ownNames.indexOf(key) === -1) {
38 this[key] = val[key];
39 }
40 }
41 } else {
42 this.type = type;
43 this.val = val;
44 }
45}
46
47/**
48 * Returns true if the given value is a node.
49 *
50 * ```js
51 * var Node = require('snapdragon-node');
52 * var node = new Node({type: 'foo'});
53 * console.log(Node.isNode(node)); //=> true
54 * console.log(Node.isNode({})); //=> false
55 * ```
56 * @param {Object} `node`
57 * @returns {Boolean}
58 * @api public
59 */
60
61Node.isNode = function(node) {
62 return utils.isNode(node);
63};
64
65/**
66 * Define a non-enumberable property on the node instance.
67 * Useful for adding properties that shouldn't be extended
68 * or visible during debugging.
69 *
70 * ```js
71 * var node = new Node();
72 * node.define('foo', 'something non-enumerable');
73 * ```
74 * @param {String} `name`
75 * @param {any} `val`
76 * @return {Object} returns the node instance
77 * @api public
78 */
79
80Node.prototype.define = function(name, val) {
81 define(this, name, val);
82 return this;
83};
84
85/**
86 * Returns true if `node.val` is an empty string, or `node.nodes` does
87 * not contain any non-empty text nodes.
88 *
89 * ```js
90 * var node = new Node({type: 'text'});
91 * node.isEmpty(); //=> true
92 * node.val = 'foo';
93 * node.isEmpty(); //=> false
94 * ```
95 * @param {Function} `fn` (optional) Filter function that is called on `node` and/or child nodes. `isEmpty` will return false immediately when the filter function returns false on any nodes.
96 * @return {Boolean}
97 * @api public
98 */
99
100Node.prototype.isEmpty = function(fn) {
101 return utils.isEmpty(this, fn);
102};
103
104/**
105 * Given node `foo` and node `bar`, push node `bar` onto `foo.nodes`, and
106 * set `foo` as `bar.parent`.
107 *
108 * ```js
109 * var foo = new Node({type: 'foo'});
110 * var bar = new Node({type: 'bar'});
111 * foo.push(bar);
112 * ```
113 * @param {Object} `node`
114 * @return {Number} Returns the length of `node.nodes`
115 * @api public
116 */
117
118Node.prototype.push = function(node) {
119 assert(Node.isNode(node), 'expected node to be an instance of Node');
120 define(node, 'parent', this);
121
122 this.nodes = this.nodes || [];
123 return this.nodes.push(node);
124};
125
126/**
127 * Given node `foo` and node `bar`, unshift node `bar` onto `foo.nodes`, and
128 * set `foo` as `bar.parent`.
129 *
130 * ```js
131 * var foo = new Node({type: 'foo'});
132 * var bar = new Node({type: 'bar'});
133 * foo.unshift(bar);
134 * ```
135 * @param {Object} `node`
136 * @return {Number} Returns the length of `node.nodes`
137 * @api public
138 */
139
140Node.prototype.unshift = function(node) {
141 assert(Node.isNode(node), 'expected node to be an instance of Node');
142 define(node, 'parent', this);
143
144 this.nodes = this.nodes || [];
145 return this.nodes.unshift(node);
146};
147
148/**
149 * Pop a node from `node.nodes`.
150 *
151 * ```js
152 * var node = new Node({type: 'foo'});
153 * node.push(new Node({type: 'a'}));
154 * node.push(new Node({type: 'b'}));
155 * node.push(new Node({type: 'c'}));
156 * node.push(new Node({type: 'd'}));
157 * console.log(node.nodes.length);
158 * //=> 4
159 * node.pop();
160 * console.log(node.nodes.length);
161 * //=> 3
162 * ```
163 * @return {Number} Returns the popped `node`
164 * @api public
165 */
166
167Node.prototype.pop = function() {
168 return this.nodes && this.nodes.pop();
169};
170
171/**
172 * Shift a node from `node.nodes`.
173 *
174 * ```js
175 * var node = new Node({type: 'foo'});
176 * node.push(new Node({type: 'a'}));
177 * node.push(new Node({type: 'b'}));
178 * node.push(new Node({type: 'c'}));
179 * node.push(new Node({type: 'd'}));
180 * console.log(node.nodes.length);
181 * //=> 4
182 * node.shift();
183 * console.log(node.nodes.length);
184 * //=> 3
185 * ```
186 * @return {Object} Returns the shifted `node`
187 * @api public
188 */
189
190Node.prototype.shift = function() {
191 return this.nodes && this.nodes.shift();
192};
193
194/**
195 * Remove `node` from `node.nodes`.
196 *
197 * ```js
198 * node.remove(childNode);
199 * ```
200 * @param {Object} `node`
201 * @return {Object} Returns the removed node.
202 * @api public
203 */
204
205Node.prototype.remove = function(node) {
206 assert(Node.isNode(node), 'expected node to be an instance of Node');
207 this.nodes = this.nodes || [];
208 var idx = node.index;
209 if (idx !== -1) {
210 node.index = -1;
211 return this.nodes.splice(idx, 1);
212 }
213 return null;
214};
215
216/**
217 * Get the first child node from `node.nodes` that matches the given `type`.
218 * If `type` is a number, the child node at that index is returned.
219 *
220 * ```js
221 * var child = node.find(1); //<= index of the node to get
222 * var child = node.find('foo'); //<= node.type of a child node
223 * var child = node.find(/^(foo|bar)$/); //<= regex to match node.type
224 * var child = node.find(['foo', 'bar']); //<= array of node.type(s)
225 * ```
226 * @param {String} `type`
227 * @return {Object} Returns a child node or undefined.
228 * @api public
229 */
230
231Node.prototype.find = function(type) {
232 return utils.findNode(this.nodes, type);
233};
234
235/**
236 * Return true if the node is the given `type`.
237 *
238 * ```js
239 * var node = new Node({type: 'bar'});
240 * cosole.log(node.isType('foo')); // false
241 * cosole.log(node.isType(/^(foo|bar)$/)); // true
242 * cosole.log(node.isType(['foo', 'bar'])); // true
243 * ```
244 * @param {String} `type`
245 * @return {Boolean}
246 * @api public
247 */
248
249Node.prototype.isType = function(type) {
250 return utils.isType(this, type);
251};
252
253/**
254 * Return true if the `node.nodes` has the given `type`.
255 *
256 * ```js
257 * var foo = new Node({type: 'foo'});
258 * var bar = new Node({type: 'bar'});
259 * foo.push(bar);
260 *
261 * cosole.log(foo.hasType('qux')); // false
262 * cosole.log(foo.hasType(/^(qux|bar)$/)); // true
263 * cosole.log(foo.hasType(['qux', 'bar'])); // true
264 * ```
265 * @param {String} `type`
266 * @return {Boolean}
267 * @api public
268 */
269
270Node.prototype.hasType = function(type) {
271 return utils.hasType(this, type);
272};
273
274/**
275 * Get the siblings array, or `null` if it doesn't exist.
276 *
277 * ```js
278 * var foo = new Node({type: 'foo'});
279 * var bar = new Node({type: 'bar'});
280 * var baz = new Node({type: 'baz'});
281 * foo.push(bar);
282 * foo.push(baz);
283 *
284 * console.log(bar.siblings.length) // 2
285 * console.log(baz.siblings.length) // 2
286 * ```
287 * @return {Array}
288 * @api public
289 */
290
291Object.defineProperty(Node.prototype, 'siblings', {
292 set: function() {
293 throw new Error('node.siblings is a getter and cannot be defined');
294 },
295 get: function() {
296 return this.parent ? this.parent.nodes : null;
297 }
298});
299
300/**
301 * Get the node's current index from `node.parent.nodes`.
302 * This should always be correct, even when the parent adds nodes.
303 *
304 * ```js
305 * var foo = new Node({type: 'foo'});
306 * var bar = new Node({type: 'bar'});
307 * var baz = new Node({type: 'baz'});
308 * var qux = new Node({type: 'qux'});
309 * foo.push(bar);
310 * foo.push(baz);
311 * foo.unshift(qux);
312 *
313 * console.log(bar.index) // 1
314 * console.log(baz.index) // 2
315 * console.log(qux.index) // 0
316 * ```
317 * @return {Number}
318 * @api public
319 */
320
321Object.defineProperty(Node.prototype, 'index', {
322 set: function(index) {
323 define(this, 'idx', index);
324 },
325 get: function() {
326 if (!Array.isArray(this.siblings)) {
327 return -1;
328 }
329 var tok = this.idx !== -1 ? this.siblings[this.idx] : null;
330 if (tok !== this) {
331 this.idx = this.siblings.indexOf(this);
332 }
333 return this.idx;
334 }
335});
336
337/**
338 * Get the previous node from the siblings array or `null`.
339 *
340 * ```js
341 * var foo = new Node({type: 'foo'});
342 * var bar = new Node({type: 'bar'});
343 * var baz = new Node({type: 'baz'});
344 * foo.push(bar);
345 * foo.push(baz);
346 *
347 * console.log(baz.prev.type) // 'bar'
348 * ```
349 * @return {Object}
350 * @api public
351 */
352
353Object.defineProperty(Node.prototype, 'prev', {
354 set: function() {
355 throw new Error('node.prev is a getter and cannot be defined');
356 },
357 get: function() {
358 if (Array.isArray(this.siblings)) {
359 return this.siblings[this.index - 1] || this.parent.prev;
360 }
361 return null;
362 }
363});
364
365/**
366 * Get the siblings array, or `null` if it doesn't exist.
367 *
368 * ```js
369 * var foo = new Node({type: 'foo'});
370 * var bar = new Node({type: 'bar'});
371 * var baz = new Node({type: 'baz'});
372 * foo.push(bar);
373 * foo.push(baz);
374 *
375 * console.log(bar.siblings.length) // 2
376 * console.log(baz.siblings.length) // 2
377 * ```
378 * @return {Object}
379 * @api public
380 */
381
382Object.defineProperty(Node.prototype, 'next', {
383 set: function() {
384 throw new Error('node.next is a getter and cannot be defined');
385 },
386 get: function() {
387 if (Array.isArray(this.siblings)) {
388 return this.siblings[this.index + 1] || this.parent.next;
389 }
390 return null;
391 }
392});
393
394/**
395 * Get the first node from `node.nodes`.
396 *
397 * ```js
398 * var foo = new Node({type: 'foo'});
399 * var bar = new Node({type: 'bar'});
400 * var baz = new Node({type: 'baz'});
401 * var qux = new Node({type: 'qux'});
402 * foo.push(bar);
403 * foo.push(baz);
404 * foo.push(qux);
405 *
406 * console.log(foo.first.type) // 'bar'
407 * ```
408 * @return {Object} The first node, or undefiend
409 * @api public
410 */
411
412Object.defineProperty(Node.prototype, 'first', {
413 get: function() {
414 return this.nodes ? this.nodes[0] : null;
415 }
416});
417
418/**
419 * Get the last node from `node.nodes`.
420 *
421 * ```js
422 * var foo = new Node({type: 'foo'});
423 * var bar = new Node({type: 'bar'});
424 * var baz = new Node({type: 'baz'});
425 * var qux = new Node({type: 'qux'});
426 * foo.push(bar);
427 * foo.push(baz);
428 * foo.push(qux);
429 *
430 * console.log(foo.last.type) // 'qux'
431 * ```
432 * @return {Object} The last node, or undefiend
433 * @api public
434 */
435
436Object.defineProperty(Node.prototype, 'last', {
437 get: function() {
438 return this.nodes ? utils.last(this.nodes) : null;
439 }
440});
441
442/**
443 * Get the last node from `node.nodes`.
444 *
445 * ```js
446 * var foo = new Node({type: 'foo'});
447 * var bar = new Node({type: 'bar'});
448 * var baz = new Node({type: 'baz'});
449 * var qux = new Node({type: 'qux'});
450 * foo.push(bar);
451 * foo.push(baz);
452 * foo.push(qux);
453 *
454 * console.log(foo.last.type) // 'qux'
455 * ```
456 * @return {Object} The last node, or undefiend
457 * @api public
458 */
459
460Object.defineProperty(Node.prototype, 'scope', {
461 get: function() {
462 if (this.isScope !== true) {
463 return this.parent ? this.parent.scope : this;
464 }
465 return this;
466 }
467});
468
469/**
470 * Get own property names from Node prototype, but only the
471 * first time `Node` is instantiated
472 */
473
474function lazyKeys() {
475 if (!ownNames) {
476 ownNames = Object.getOwnPropertyNames(Node.prototype);
477 }
478}
479
480/**
481 * Simplified assertion. Throws an error is `val` is falsey.
482 */
483
484function assert(val, message) {
485 if (!val) throw new Error(message);
486}
487
488/**
489 * Expose `Node`
490 */
491
492exports = module.exports = Node;
Note: See TracBrowser for help on using the repository browser.