pax_global_header 0000666 0000000 0000000 00000000064 13176265700 0014521 g ustar 00root root 0000000 0000000 52 comment=51ebbd9ea96455a075d304ad7fbb9701ba9955a0
snapdragon-util-4.0.0/ 0000775 0000000 0000000 00000000000 13176265700 0014631 5 ustar 00root root 0000000 0000000 snapdragon-util-4.0.0/.editorconfig 0000664 0000000 0000000 00000000441 13176265700 0017305 0 ustar 00root root 0000000 0000000 # http://editorconfig.org/
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[{**/{actual,fixtures,expected,templates}/**,*.md}]
trim_trailing_whitespace = false
insert_final_newline = false
snapdragon-util-4.0.0/.eslintrc.json 0000664 0000000 0000000 00000006775 13176265700 0017444 0 ustar 00root root 0000000 0000000 {
"env": {
"browser": false,
"es6": true,
"node": true,
"mocha": true
},
"globals": {
"document": false,
"navigator": false,
"window": false
},
"rules": {
"accessor-pairs": 2,
"arrow-spacing": [2, { "before": true, "after": true }],
"block-spacing": [2, "always"],
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"comma-dangle": [2, "never"],
"comma-spacing": [2, { "before": false, "after": true }],
"comma-style": [2, "last"],
"constructor-super": 2,
"curly": [2, "multi-line"],
"dot-location": [2, "property"],
"eol-last": 2,
"eqeqeq": [2, "allow-null"],
"generator-star-spacing": [2, { "before": true, "after": true }],
"handle-callback-err": [2, "^(err|error)$" ],
"indent": [2, 2, { "SwitchCase": 1 }],
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
"keyword-spacing": [2, { "before": true, "after": true }],
"new-cap": [2, { "newIsCap": true, "capIsNew": false }],
"new-parens": 2,
"no-array-constructor": 2,
"no-caller": 2,
"no-class-assign": 2,
"no-cond-assign": 2,
"no-const-assign": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-dupe-args": 2,
"no-dupe-class-members": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty-character-class": 2,
"no-eval": 2,
"no-ex-assign": 2,
"no-extend-native": 2,
"no-extra-bind": 2,
"no-extra-boolean-cast": 2,
"no-extra-parens": [2, "functions"],
"no-fallthrough": 2,
"no-floating-decimal": 2,
"no-func-assign": 2,
"no-implied-eval": 2,
"no-inner-declarations": [2, "functions"],
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-iterator": 2,
"no-label-var": 2,
"no-labels": 2,
"no-lone-blocks": 2,
"no-mixed-spaces-and-tabs": 2,
"no-multi-spaces": 2,
"no-multi-str": 2,
"no-multiple-empty-lines": [2, { "max": 1 }],
"no-native-reassign": 0,
"no-negated-in-lhs": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-object": 2,
"no-new-require": 2,
"no-new-wrappers": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-proto": 0,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-return-assign": 2,
"no-self-compare": 2,
"no-sequences": 2,
"no-shadow-restricted-names": 2,
"no-spaced-func": 2,
"no-sparse-arrays": 2,
"no-this-before-super": 2,
"no-throw-literal": 2,
"no-trailing-spaces": 0,
"no-undef": 2,
"no-undef-init": 2,
"no-unexpected-multiline": 2,
"no-unneeded-ternary": [2, { "defaultAssignment": false }],
"no-unreachable": 2,
"no-unused-vars": [2, { "vars": "all", "args": "none" }],
"no-useless-call": 0,
"no-with": 2,
"one-var": [0, { "initialized": "never" }],
"operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }],
"padded-blocks": [0, "never"],
"quotes": [2, "single", "avoid-escape"],
"radix": 2,
"semi": [2, "always"],
"semi-spacing": [2, { "before": false, "after": true }],
"space-before-blocks": [2, "always"],
"space-before-function-paren": [2, "never"],
"space-in-parens": [2, "never"],
"space-infix-ops": 2,
"space-unary-ops": [2, { "words": true, "nonwords": false }],
"spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
"use-isnan": 2,
"valid-typeof": 2,
"wrap-iife": [2, "any"],
"yoda": [2, "never"]
}
}
snapdragon-util-4.0.0/.gitattributes 0000664 0000000 0000000 00000000200 13176265700 0017514 0 ustar 00root root 0000000 0000000 # Enforce Unix newlines
* text eol=lf
# binaries
*.ai binary
*.psd binary
*.jpg binary
*.gif binary
*.png binary
*.jpeg binary
snapdragon-util-4.0.0/.github/ 0000775 0000000 0000000 00000000000 13176265700 0016171 5 ustar 00root root 0000000 0000000 snapdragon-util-4.0.0/.github/contributing.md 0000664 0000000 0000000 00000006341 13176265700 0021226 0 ustar 00root root 0000000 0000000 # Contributing to snapdragon-util
First and foremost, thank you! We appreciate that you want to contribute to snapdragon-util, your time is valuable, and your contributions mean a lot to us.
**What does "contributing" mean?**
Creating an issue is the simplest form of contributing to a project. But there are many ways to contribute, including the following:
- Updating or correcting documentation
- Feature requests
- Bug reports
If you'd like to learn more about contributing in general, the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing) has a lot of useful information.
**Showing support for snapdragon-util**
Please keep in mind that open source software is built by people like you, who spend their free time creating things the rest the community can use.
Don't have time to contribute? No worries, here are some other ways to show your support for snapdragon-util:
- star the [project](https://github.com/jonschlinkert/snapdragon-util)
- tweet your support for snapdragon-util
## Issues
### Before creating an issue
Please try to determine if the issue is caused by an underlying library, and if so, create the issue there. Sometimes this is difficult to know. We only ask that you attempt to give a reasonable attempt to find out. Oftentimes the readme will have advice about where to go to create issues.
Try to follow these guidelines
- **Investigate the issue**:
- **Check the readme** - oftentimes you will find notes about creating issues, and where to go depending on the type of issue.
- Create the issue in the appropriate repository.
### Creating an issue
Please be as descriptive as possible when creating an issue. Give us the information we need to successfully answer your question or address your issue by answering the following in your issue:
- **version**: please note the version of snapdragon-util are you using
- **extensions, plugins, helpers, etc** (if applicable): please list any extensions you're using
- **error messages**: please paste any error messages into the issue, or a [gist](https://gist.github.com/)
## Above and beyond
Here are some tips for creating idiomatic issues. Taking just a little bit extra time will make your issue easier to read, easier to resolve, more likely to be found by others who have the same or similar issue in the future.
- read the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing)
- take some time to learn basic markdown. This [markdown cheatsheet](https://gist.github.com/jonschlinkert/5854601) is super helpful, as is the GitHub guide to [basic markdown](https://help.github.com/articles/markdown-basics/).
- Learn about [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown/). And if you want to really go above and beyond, read [mastering markdown](https://guides.github.com/features/mastering-markdown/).
- use backticks to wrap code. This ensures that code will retain its format, making it much more readable to others
- use syntax highlighting by adding the correct language name after the first "code fence"
[node-glob]: https://github.com/isaacs/node-glob
[micromatch]: https://github.com/jonschlinkert/micromatch
[so]: http://stackoverflow.com/questions/tagged/snapdragon-util snapdragon-util-4.0.0/.gitignore 0000664 0000000 0000000 00000000446 13176265700 0016625 0 ustar 00root root 0000000 0000000 # always ignore files
*.DS_Store
.idea
*.sublime-*
# test related, or directories generated by tests
test/actual
actual
coverage
.nyc*
# npm
node_modules
npm-debug.log
# yarn
yarn.lock
yarn-error.log
# misc
_gh_pages
_draft
_drafts
bower_components
vendor
temp
tmp
TODO.md
package-lock.json snapdragon-util-4.0.0/.travis.yml 0000664 0000000 0000000 00000000226 13176265700 0016742 0 ustar 00root root 0000000 0000000 sudo: false
os:
- linux
- osx
language: node_js
node_js:
- node
- '9'
- '8'
- '7'
- '6'
- '5'
- '4.7'
- '4'
- '0.12'
- '0.10'
snapdragon-util-4.0.0/.verb.md 0000664 0000000 0000000 00000002307 13176265700 0016171 0 ustar 00root root 0000000 0000000 ## Usage
```js
var util = require('snapdragon-util');
```
## API
{%= apidocs("index.js") %}
## Release history
Changelog entries are classified using the following labels from [keep-a-changelog][]:
* `added`: for new features
* `changed`: for changes in existing functionality
* `deprecated`: for once-stable features removed in upcoming releases
* `removed`: for deprecated features removed in this release
* `fixed`: for any bug fixes
Custom labels used in this changelog:
* `dependencies`: bumps dependencies
* `housekeeping`: code re-organization, minor edits, or other changes that don't fit in one of the other categories.
### [4.0.0] - 2017-11-01
**Dependencies**
- Updated `kind-of` to version 6.0
### [3.0.0] - 2017-05-01
**Changed**
- `.emit` was renamed to [.append](#append)
- `.addNode` was renamed to [.pushNode](#pushNode)
- `.getNode` was renamed to [.findNode](#findNode)
- `.isEmptyNodes` was renamed to [.isEmpty](#isEmpty): also now works with `node.nodes` and/or `node.val`
**Added**
- [.identity](#identity)
- [.removeNode](#removeNode)
- [.shiftNode](#shiftNode)
- [.popNode](#popNode)
### [0.1.0]
First release.
[keep-a-changelog]: https://github.com/olivierlacan/keep-a-changelog
snapdragon-util-4.0.0/LICENSE 0000664 0000000 0000000 00000002073 13176265700 0015640 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2017, Jon Schlinkert.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
snapdragon-util-4.0.0/README.md 0000664 0000000 0000000 00000052304 13176265700 0016114 0 ustar 00root root 0000000 0000000 # snapdragon-util [](https://www.npmjs.com/package/snapdragon-util) [](https://npmjs.org/package/snapdragon-util) [](https://npmjs.org/package/snapdragon-util) [](https://travis-ci.org/jonschlinkert/snapdragon-util)
> Utilities for the snapdragon parser/compiler.
Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.
## Install
Install with [npm](https://www.npmjs.com/):
```sh
$ npm install --save snapdragon-util
```
## Usage
```js
var util = require('snapdragon-util');
```
## API
### [.isNode](index.js#L20)
Returns true if the given value is a node.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var node = new Node({type: 'foo'});
console.log(utils.isNode(node)); //=> true
console.log(utils.isNode({})); //=> false
```
### [.noop](index.js#L36)
Emit an empty string for the given `node`.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{undefined}**
**Example**
```js
// do nothing for beginning-of-string
snapdragon.compiler.set('bos', utils.noop);
```
### [.identity](index.js#L52)
Appdend `node.val` to `compiler.output`, exactly as it was created by the parser.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{undefined}**
**Example**
```js
snapdragon.compiler.set('text', utils.identity);
```
### [.append](index.js#L75)
Previously named `.emit`, this method appends the given `val` to `compiler.output` for the given node. Useful when you know what value should be appended advance, regardless of the actual value of `node.val`.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Function}**: Returns a compiler middleware function.
**Example**
```js
snapdragon.compiler
.set('i', function(node) {
this.mapVisit(node);
})
.set('i.open', utils.append(''))
.set('i.close', utils.append(''))
```
### [.toNoop](index.js#L98)
Used in compiler middleware, this onverts an AST node into an empty `text` node and deletes `node.nodes` if it exists. The advantage of this method is that, as opposed to completely removing the node, indices will not need to be re-calculated in sibling nodes, and nothing is appended to the output.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `nodes` **{Array}**: Optionally pass a new `nodes` value, to replace the existing `node.nodes` array.
**Example**
```js
utils.toNoop(node);
// convert `node.nodes` to the given value instead of deleting it
utils.toNoop(node, []);
```
### [.visit](index.js#L127)
Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon automatically calls registered compilers, this allows you to pass a visitor function.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `fn` **{Function}**
* `returns` **{Object}**: returns the node after recursively visiting all child nodes.
**Example**
```js
snapdragon.compiler.set('i', function(node) {
utils.visit(node, function(childNode) {
// do stuff with "childNode"
return childNode;
});
});
```
### [.mapVisit](index.js#L154)
Map [visit](#visit) the given `fn` over `node.nodes`. This is called by [visit](#visit), use this method if you do not want `fn` to be called on the first node.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `options` **{Object}**
* `fn` **{Function}**
* `returns` **{Object}**: returns the node
**Example**
```js
snapdragon.compiler.set('i', function(node) {
utils.mapVisit(node, function(childNode) {
// do stuff with "childNode"
return childNode;
});
});
```
### [.addOpen](index.js#L193)
Unshift an `*.open` node onto `node.nodes`.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `Node` **{Function}**: (required) Node constructor function from [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node).
* `filter` **{Function}**: Optionaly specify a filter function to exclude the node.
* `returns` **{Object}**: Returns the created opening node.
**Example**
```js
var Node = require('snapdragon-node');
snapdragon.parser.set('brace', function(node) {
var match = this.match(/^{/);
if (match) {
var parent = new Node({type: 'brace'});
utils.addOpen(parent, Node);
console.log(parent.nodes[0]):
// { type: 'brace.open', val: '' };
// push the parent "brace" node onto the stack
this.push(parent);
// return the parent node, so it's also added to the AST
return brace;
}
});
```
### [.addClose](index.js#L243)
Push a `*.close` node onto `node.nodes`.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `Node` **{Function}**: (required) Node constructor function from [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node).
* `filter` **{Function}**: Optionaly specify a filter function to exclude the node.
* `returns` **{Object}**: Returns the created closing node.
**Example**
```js
var Node = require('snapdragon-node');
snapdragon.parser.set('brace', function(node) {
var match = this.match(/^}/);
if (match) {
var parent = this.parent();
if (parent.type !== 'brace') {
throw new Error('missing opening: ' + '}');
}
utils.addClose(parent, Node);
console.log(parent.nodes[parent.nodes.length - 1]):
// { type: 'brace.close', val: '' };
// no need to return a node, since the parent
// was already added to the AST
return;
}
});
```
### [.wrapNodes](index.js#L273)
Wraps the given `node` with `*.open` and `*.close` nodes.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `Node` **{Function}**: (required) Node constructor function from [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node).
* `filter` **{Function}**: Optionaly specify a filter function to exclude the node.
* `returns` **{Object}**: Returns the node
### [.pushNode](index.js#L298)
Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent.
**Params**
* `parent` **{Object}**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Object}**: Returns the child node
**Example**
```js
var parent = new Node({type: 'foo'});
var node = new Node({type: 'bar'});
utils.pushNode(parent, node);
console.log(parent.nodes[0].type) // 'bar'
console.log(node.parent.type) // 'foo'
```
### [.unshiftNode](index.js#L324)
Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent.
**Params**
* `parent` **{Object}**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{undefined}**
**Example**
```js
var parent = new Node({type: 'foo'});
var node = new Node({type: 'bar'});
utils.unshiftNode(parent, node);
console.log(parent.nodes[0].type) // 'bar'
console.log(node.parent.type) // 'foo'
```
### [.popNode](index.js#L353)
Pop the last `node` off of `parent.nodes`. The advantage of using this method is that it checks for `node.nodes` and works with any version of `snapdragon-node`.
**Params**
* `parent` **{Object}**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Number|Undefined}**: Returns the length of `node.nodes` or undefined.
**Example**
```js
var parent = new Node({type: 'foo'});
utils.pushNode(parent, new Node({type: 'foo'}));
utils.pushNode(parent, new Node({type: 'bar'}));
utils.pushNode(parent, new Node({type: 'baz'}));
console.log(parent.nodes.length); //=> 3
utils.popNode(parent);
console.log(parent.nodes.length); //=> 2
```
### [.shiftNode](index.js#L381)
Shift the first `node` off of `parent.nodes`. The advantage of using this method is that it checks for `node.nodes` and works with any version of `snapdragon-node`.
**Params**
* `parent` **{Object}**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Number|Undefined}**: Returns the length of `node.nodes` or undefined.
**Example**
```js
var parent = new Node({type: 'foo'});
utils.pushNode(parent, new Node({type: 'foo'}));
utils.pushNode(parent, new Node({type: 'bar'}));
utils.pushNode(parent, new Node({type: 'baz'}));
console.log(parent.nodes.length); //=> 3
utils.shiftNode(parent);
console.log(parent.nodes.length); //=> 2
```
### [.removeNode](index.js#L408)
Remove the specified `node` from `parent.nodes`.
**Params**
* `parent` **{Object}**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Object|undefined}**: Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`.
**Example**
```js
var parent = new Node({type: 'abc'});
var foo = new Node({type: 'foo'});
utils.pushNode(parent, foo);
utils.pushNode(parent, new Node({type: 'bar'}));
utils.pushNode(parent, new Node({type: 'baz'}));
console.log(parent.nodes.length); //=> 3
utils.removeNode(parent, foo);
console.log(parent.nodes.length); //=> 2
```
### [.isType](index.js#L442)
Returns true if `node.type` matches the given `type`. Throws a `TypeError` if `node` is not an instance of `Node`.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `type` **{String}**
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var node = new Node({type: 'foo'});
console.log(utils.isType(node, 'foo')); // false
console.log(utils.isType(node, 'bar')); // true
```
### [.hasType](index.js#L485)
Returns true if the given `node` has the given `type` in `node.nodes`. Throws a `TypeError` if `node` is not an instance of `Node`.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `type` **{String}**
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var node = new Node({
type: 'foo',
nodes: [
new Node({type: 'bar'}),
new Node({type: 'baz'})
]
});
console.log(utils.hasType(node, 'xyz')); // false
console.log(utils.hasType(node, 'baz')); // true
```
### [.firstOfType](index.js#L518)
Returns the first node from `node.nodes` of the given `type`
**Params**
* `nodes` **{Array}**
* `type` **{String}**
* `returns` **{Object|undefined}**: Returns the first matching node or undefined.
**Example**
```js
var node = new Node({
type: 'foo',
nodes: [
new Node({type: 'text', val: 'abc'}),
new Node({type: 'text', val: 'xyz'})
]
});
var textNode = utils.firstOfType(node.nodes, 'text');
console.log(textNode.val);
//=> 'abc'
```
### [.findNode](index.js#L555)
Returns the node at the specified index, or the first node of the given `type` from `node.nodes`.
**Params**
* `nodes` **{Array}**
* `type` **{String|Number}**: Node type or index.
* `returns` **{Object}**: Returns a node or undefined.
**Example**
```js
var node = new Node({
type: 'foo',
nodes: [
new Node({type: 'text', val: 'abc'}),
new Node({type: 'text', val: 'xyz'})
]
});
var nodeOne = utils.findNode(node.nodes, 'text');
console.log(nodeOne.val);
//=> 'abc'
var nodeTwo = utils.findNode(node.nodes, 1);
console.log(nodeTwo.val);
//=> 'xyz'
```
### [.isOpen](index.js#L583)
Returns true if the given node is an "*.open" node.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var close = new Node({type: 'brace.close'});
console.log(utils.isOpen(brace)); // false
console.log(utils.isOpen(open)); // true
console.log(utils.isOpen(close)); // false
```
### [.isClose](index.js#L606)
Returns true if the given node is a "*.close" node.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var close = new Node({type: 'brace.close'});
console.log(utils.isClose(brace)); // false
console.log(utils.isClose(open)); // false
console.log(utils.isClose(close)); // true
```
### [.hasOpen](index.js#L632)
Returns true if `node.nodes` **has** an `.open` node
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var brace = new Node({
type: 'brace',
nodes: []
});
var open = new Node({type: 'brace.open'});
console.log(utils.hasOpen(brace)); // false
brace.pushNode(open);
console.log(utils.hasOpen(brace)); // true
```
### [.hasClose](index.js#L662)
Returns true if `node.nodes` **has** a `.close` node
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var brace = new Node({
type: 'brace',
nodes: []
});
var close = new Node({type: 'brace.close'});
console.log(utils.hasClose(brace)); // false
brace.pushNode(close);
console.log(utils.hasClose(brace)); // true
```
### [.hasOpenAndClose](index.js#L696)
Returns true if `node.nodes` has both `.open` and `.close` nodes
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Boolean}**
**Example**
```js
var Node = require('snapdragon-node');
var brace = new Node({
type: 'brace',
nodes: []
});
var open = new Node({type: 'brace.open'});
var close = new Node({type: 'brace.close'});
console.log(utils.hasOpen(brace)); // false
console.log(utils.hasClose(brace)); // false
brace.pushNode(open);
brace.pushNode(close);
console.log(utils.hasOpen(brace)); // true
console.log(utils.hasClose(brace)); // true
```
### [.addType](index.js#L718)
Push the given `node` onto the `state.inside` array for the given type. This array is used as a specialized "stack" for only the given `node.type`.
**Params**
* `state` **{Object}**: The `compiler.state` object or custom state object.
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Array}**: Returns the `state.inside` stack for the given type.
**Example**
```js
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
console.log(state.inside);
//=> { brace: [{type: 'brace'}] }
```
### [.removeType](index.js#L758)
Remove the given `node` from the `state.inside` array for the given type. This array is used as a specialized "stack" for only the given `node.type`.
**Params**
* `state` **{Object}**: The `compiler.state` object or custom state object.
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `returns` **{Array}**: Returns the `state.inside` stack for the given type.
**Example**
```js
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
console.log(state.inside);
//=> { brace: [{type: 'brace'}] }
utils.removeType(state, node);
//=> { brace: [] }
```
### [.isEmpty](index.js#L787)
Returns true if `node.val` is an empty string, or `node.nodes` does not contain any non-empty text nodes.
**Params**
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `fn` **{Function}**
* `returns` **{Boolean}**
**Example**
```js
var node = new Node({type: 'text'});
utils.isEmpty(node); //=> true
node.val = 'foo';
utils.isEmpty(node); //=> false
```
### [.isInsideType](index.js#L832)
Returns true if the `state.inside` stack for the given type exists and has one or more nodes on it.
**Params**
* `state` **{Object}**
* `type` **{String}**
* `returns` **{Boolean}**
**Example**
```js
var state = { inside: {}};
var node = new Node({type: 'brace'});
console.log(utils.isInsideType(state, 'brace')); //=> false
utils.addType(state, node);
console.log(utils.isInsideType(state, 'brace')); //=> true
utils.removeType(state, node);
console.log(utils.isInsideType(state, 'brace')); //=> false
```
### [.isInside](index.js#L866)
Returns true if `node` is either a child or grand-child of the given `type`, or `state.inside[type]` is a non-empty array.
**Params**
* `state` **{Object}**: Either the `compiler.state` object, if it exists, or a user-supplied state object.
* `node` **{Object}**: Instance of [snapdragon-node](https://github.com/jonschlinkert/snapdragon-node)
* `type` **{String}**: The `node.type` to check for.
* `returns` **{Boolean}**
**Example**
```js
var state = { inside: {}};
var node = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
console.log(utils.isInside(state, open, 'brace')); //=> false
utils.pushNode(node, open);
console.log(utils.isInside(state, open, 'brace')); //=> true
```
### [.last](index.js#L914)
Get the last `n` element from the given `array`. Used for getting
a node from `node.nodes.`
**Params**
* `array` **{Array}**
* `n` **{Number}**
* `returns` **{undefined}**
### [.arrayify](index.js#L934)
Cast the given `val` to an array.
**Params**
* `val` **{any}**
* `returns` **{Array}**
**Example**
```js
console.log(utils.arrayify(''));
//=> []
console.log(utils.arrayify('foo'));
//=> ['foo']
console.log(utils.arrayify(['foo']));
//=> ['foo']
```
### [.stringify](index.js#L953)
Convert the given `val` to a string by joining with `,`. Useful
for creating a cheerio/CSS/DOM-style selector from a list of strings.
**Params**
* `val` **{any}**
* `returns` **{Array}**
### [.trim](index.js#L966)
Ensure that the given value is a string and call `.trim()` on it,
or return an empty string.
**Params**
* `str` **{String}**
* `returns` **{String}**
## Release history
Changelog entries are classified using the following labels from [keep-a-changelog](https://github.com/olivierlacan/keep-a-changelog):
* `added`: for new features
* `changed`: for changes in existing functionality
* `deprecated`: for once-stable features removed in upcoming releases
* `removed`: for deprecated features removed in this release
* `fixed`: for any bug fixes
Custom labels used in this changelog:
* `dependencies`: bumps dependencies
* `housekeeping`: code re-organization, minor edits, or other changes that don't fit in one of the other categories.
### [4.0.0] - 2017-11-01
**Dependencies**
* Updated `kind-of` to version 6.0
### [3.0.0] - 2017-05-01
**Changed**
* `.emit` was renamed to [.append](#append)
* `.addNode` was renamed to [.pushNode](#pushNode)
* `.getNode` was renamed to [.findNode](#findNode)
* `.isEmptyNodes` was renamed to [.isEmpty](#isEmpty): also now works with `node.nodes` and/or `node.val`
**Added**
* [.identity](#identity)
* [.removeNode](#removeNode)
* [.shiftNode](#shiftNode)
* [.popNode](#popNode)
### [0.1.0]
First release.
## About
Contributing
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
Please read the [contributing guide](.github/contributing.md) for advice on opening issues, pull requests, and coding standards.
Running Tests
Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:
```sh
$ npm install && npm test
```
Building docs
_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_
To generate the readme, run the following command:
```sh
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```
### Contributors
| **Commits** | **Contributor** |
| --- | --- |
| 40 | [jonschlinkert](https://github.com/jonschlinkert) |
| 2 | [realityking](https://github.com/realityking) |
### Author
**Jon Schlinkert**
* [github/jonschlinkert](https://github.com/jonschlinkert)
* [twitter/jonschlinkert](https://twitter.com/jonschlinkert)
### License
Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).
***
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on November 01, 2017._ snapdragon-util-4.0.0/gulpfile.js 0000664 0000000 0000000 00000001137 13176265700 0017000 0 ustar 00root root 0000000 0000000 'use strict';
var gulp = require('gulp');
var mocha = require('gulp-mocha');
var istanbul = require('gulp-istanbul');
var eslint = require('gulp-eslint');
gulp.task('coverage', function() {
return gulp.src('index.js')
.pipe(istanbul())
.pipe(istanbul.hookRequire());
});
gulp.task('test', ['coverage'], function() {
return gulp.src('test/*.js')
.pipe(mocha({reporter: 'spec'}))
.pipe(istanbul.writeReports());
});
gulp.task('lint', function() {
return gulp.src(['index.js', 'test/*.js'])
.pipe(eslint())
.pipe(eslint.format());
});
gulp.task('default', ['test', 'lint']);
snapdragon-util-4.0.0/index.js 0000664 0000000 0000000 00000064261 13176265700 0016307 0 ustar 00root root 0000000 0000000 'use strict';
var typeOf = require('kind-of');
var utils = module.exports;
/**
* Returns true if the given value is a node.
*
* ```js
* var Node = require('snapdragon-node');
* var node = new Node({type: 'foo'});
* console.log(utils.isNode(node)); //=> true
* console.log(utils.isNode({})); //=> false
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @returns {Boolean}
* @api public
*/
utils.isNode = function(node) {
return typeOf(node) === 'object' && node.isNode === true;
};
/**
* Emit an empty string for the given `node`.
*
* ```js
* // do nothing for beginning-of-string
* snapdragon.compiler.set('bos', utils.noop);
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @returns {undefined}
* @api public
*/
utils.noop = function(node) {
append(this, '', node);
};
/**
* Appdend `node.val` to `compiler.output`, exactly as it was created
* by the parser.
*
* ```js
* snapdragon.compiler.set('text', utils.identity);
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @returns {undefined}
* @api public
*/
utils.identity = function(node) {
append(this, node.val, node);
};
/**
* Previously named `.emit`, this method appends the given `val`
* to `compiler.output` for the given node. Useful when you know
* what value should be appended advance, regardless of the actual
* value of `node.val`.
*
* ```js
* snapdragon.compiler
* .set('i', function(node) {
* this.mapVisit(node);
* })
* .set('i.open', utils.append(''))
* .set('i.close', utils.append(''))
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @returns {Function} Returns a compiler middleware function.
* @api public
*/
utils.append = function(val) {
return function(node) {
append(this, val, node);
};
};
/**
* Used in compiler middleware, this onverts an AST node into
* an empty `text` node and deletes `node.nodes` if it exists.
* The advantage of this method is that, as opposed to completely
* removing the node, indices will not need to be re-calculated
* in sibling nodes, and nothing is appended to the output.
*
* ```js
* utils.toNoop(node);
* // convert `node.nodes` to the given value instead of deleting it
* utils.toNoop(node, []);
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {Array} `nodes` Optionally pass a new `nodes` value, to replace the existing `node.nodes` array.
* @api public
*/
utils.toNoop = function(node, nodes) {
if (nodes) {
node.nodes = nodes;
} else {
delete node.nodes;
node.type = 'text';
node.val = '';
}
};
/**
* Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon
* automatically calls registered compilers, this allows you to pass a visitor
* function.
*
* ```js
* snapdragon.compiler.set('i', function(node) {
* utils.visit(node, function(childNode) {
* // do stuff with "childNode"
* return childNode;
* });
* });
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {Function} `fn`
* @return {Object} returns the node after recursively visiting all child nodes.
* @api public
*/
utils.visit = function(node, fn) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isFunction(fn), 'expected a visitor function');
fn(node);
return node.nodes ? utils.mapVisit(node, fn) : node;
};
/**
* Map [visit](#visit) the given `fn` over `node.nodes`. This is called by
* [visit](#visit), use this method if you do not want `fn` to be called on
* the first node.
*
* ```js
* snapdragon.compiler.set('i', function(node) {
* utils.mapVisit(node, function(childNode) {
* // do stuff with "childNode"
* return childNode;
* });
* });
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {Object} `options`
* @param {Function} `fn`
* @return {Object} returns the node
* @api public
*/
utils.mapVisit = function(node, fn) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isArray(node.nodes), 'expected node.nodes to be an array');
assert(isFunction(fn), 'expected a visitor function');
for (var i = 0; i < node.nodes.length; i++) {
utils.visit(node.nodes[i], fn);
}
return node;
};
/**
* Unshift an `*.open` node onto `node.nodes`.
*
* ```js
* var Node = require('snapdragon-node');
* snapdragon.parser.set('brace', function(node) {
* var match = this.match(/^{/);
* if (match) {
* var parent = new Node({type: 'brace'});
* utils.addOpen(parent, Node);
* console.log(parent.nodes[0]):
* // { type: 'brace.open', val: '' };
*
* // push the parent "brace" node onto the stack
* this.push(parent);
*
* // return the parent node, so it's also added to the AST
* return brace;
* }
* });
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {Function} `Node` (required) Node constructor function from [snapdragon-node][].
* @param {Function} `filter` Optionaly specify a filter function to exclude the node.
* @return {Object} Returns the created opening node.
* @api public
*/
utils.addOpen = function(node, Node, val, filter) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isFunction(Node), 'expected Node to be a constructor function');
if (typeof val === 'function') {
filter = val;
val = '';
}
if (typeof filter === 'function' && !filter(node)) return;
var open = new Node({ type: node.type + '.open', val: val});
var unshift = node.unshift || node.unshiftNode;
if (typeof unshift === 'function') {
unshift.call(node, open);
} else {
utils.unshiftNode(node, open);
}
return open;
};
/**
* Push a `*.close` node onto `node.nodes`.
*
* ```js
* var Node = require('snapdragon-node');
* snapdragon.parser.set('brace', function(node) {
* var match = this.match(/^}/);
* if (match) {
* var parent = this.parent();
* if (parent.type !== 'brace') {
* throw new Error('missing opening: ' + '}');
* }
*
* utils.addClose(parent, Node);
* console.log(parent.nodes[parent.nodes.length - 1]):
* // { type: 'brace.close', val: '' };
*
* // no need to return a node, since the parent
* // was already added to the AST
* return;
* }
* });
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {Function} `Node` (required) Node constructor function from [snapdragon-node][].
* @param {Function} `filter` Optionaly specify a filter function to exclude the node.
* @return {Object} Returns the created closing node.
* @api public
*/
utils.addClose = function(node, Node, val, filter) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isFunction(Node), 'expected Node to be a constructor function');
if (typeof val === 'function') {
filter = val;
val = '';
}
if (typeof filter === 'function' && !filter(node)) return;
var close = new Node({ type: node.type + '.close', val: val});
var push = node.push || node.pushNode;
if (typeof push === 'function') {
push.call(node, close);
} else {
utils.pushNode(node, close);
}
return close;
};
/**
* Wraps the given `node` with `*.open` and `*.close` nodes.
*
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {Function} `Node` (required) Node constructor function from [snapdragon-node][].
* @param {Function} `filter` Optionaly specify a filter function to exclude the node.
* @return {Object} Returns the node
* @api public
*/
utils.wrapNodes = function(node, Node, filter) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isFunction(Node), 'expected Node to be a constructor function');
utils.addOpen(node, Node, filter);
utils.addClose(node, Node, filter);
return node;
};
/**
* Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent.
*
* ```js
* var parent = new Node({type: 'foo'});
* var node = new Node({type: 'bar'});
* utils.pushNode(parent, node);
* console.log(parent.nodes[0].type) // 'bar'
* console.log(node.parent.type) // 'foo'
* ```
* @param {Object} `parent`
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Object} Returns the child node
* @api public
*/
utils.pushNode = function(parent, node) {
assert(utils.isNode(parent), 'expected parent node to be an instance of Node');
assert(utils.isNode(node), 'expected node to be an instance of Node');
node.define('parent', parent);
parent.nodes = parent.nodes || [];
parent.nodes.push(node);
return node;
};
/**
* Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent.
*
* ```js
* var parent = new Node({type: 'foo'});
* var node = new Node({type: 'bar'});
* utils.unshiftNode(parent, node);
* console.log(parent.nodes[0].type) // 'bar'
* console.log(node.parent.type) // 'foo'
* ```
* @param {Object} `parent`
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {undefined}
* @api public
*/
utils.unshiftNode = function(parent, node) {
assert(utils.isNode(parent), 'expected parent node to be an instance of Node');
assert(utils.isNode(node), 'expected node to be an instance of Node');
node.define('parent', parent);
parent.nodes = parent.nodes || [];
parent.nodes.unshift(node);
};
/**
* Pop the last `node` off of `parent.nodes`. The advantage of
* using this method is that it checks for `node.nodes` and works
* with any version of `snapdragon-node`.
*
* ```js
* var parent = new Node({type: 'foo'});
* utils.pushNode(parent, new Node({type: 'foo'}));
* utils.pushNode(parent, new Node({type: 'bar'}));
* utils.pushNode(parent, new Node({type: 'baz'}));
* console.log(parent.nodes.length); //=> 3
* utils.popNode(parent);
* console.log(parent.nodes.length); //=> 2
* ```
* @param {Object} `parent`
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Number|Undefined} Returns the length of `node.nodes` or undefined.
* @api public
*/
utils.popNode = function(node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
if (typeof node.pop === 'function') {
return node.pop();
}
return node.nodes && node.nodes.pop();
};
/**
* Shift the first `node` off of `parent.nodes`. The advantage of
* using this method is that it checks for `node.nodes` and works
* with any version of `snapdragon-node`.
*
* ```js
* var parent = new Node({type: 'foo'});
* utils.pushNode(parent, new Node({type: 'foo'}));
* utils.pushNode(parent, new Node({type: 'bar'}));
* utils.pushNode(parent, new Node({type: 'baz'}));
* console.log(parent.nodes.length); //=> 3
* utils.shiftNode(parent);
* console.log(parent.nodes.length); //=> 2
* ```
* @param {Object} `parent`
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Number|Undefined} Returns the length of `node.nodes` or undefined.
* @api public
*/
utils.shiftNode = function(node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
if (typeof node.shift === 'function') {
return node.shift();
}
return node.nodes && node.nodes.shift();
};
/**
* Remove the specified `node` from `parent.nodes`.
*
* ```js
* var parent = new Node({type: 'abc'});
* var foo = new Node({type: 'foo'});
* utils.pushNode(parent, foo);
* utils.pushNode(parent, new Node({type: 'bar'}));
* utils.pushNode(parent, new Node({type: 'baz'}));
* console.log(parent.nodes.length); //=> 3
* utils.removeNode(parent, foo);
* console.log(parent.nodes.length); //=> 2
* ```
* @param {Object} `parent`
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Object|undefined} Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`.
* @api public
*/
utils.removeNode = function(parent, node) {
assert(utils.isNode(parent), 'expected parent.node to be an instance of Node');
assert(utils.isNode(node), 'expected node to be an instance of Node');
if (!parent.nodes) {
return null;
}
if (typeof parent.remove === 'function') {
return parent.remove(node);
}
var idx = parent.nodes.indexOf(node);
if (idx !== -1) {
return parent.nodes.splice(idx, 1);
}
};
/**
* Returns true if `node.type` matches the given `type`. Throws a
* `TypeError` if `node` is not an instance of `Node`.
*
* ```js
* var Node = require('snapdragon-node');
* var node = new Node({type: 'foo'});
* console.log(utils.isType(node, 'foo')); // false
* console.log(utils.isType(node, 'bar')); // true
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {String} `type`
* @return {Boolean}
* @api public
*/
utils.isType = function(node, type) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
switch (typeOf(type)) {
case 'array':
var types = type.slice();
for (var i = 0; i < types.length; i++) {
if (utils.isType(node, types[i])) {
return true;
}
}
return false;
case 'string':
return node.type === type;
case 'regexp':
return type.test(node.type);
default: {
throw new TypeError('expected "type" to be an array, string or regexp');
}
}
};
/**
* Returns true if the given `node` has the given `type` in `node.nodes`.
* Throws a `TypeError` if `node` is not an instance of `Node`.
*
* ```js
* var Node = require('snapdragon-node');
* var node = new Node({
* type: 'foo',
* nodes: [
* new Node({type: 'bar'}),
* new Node({type: 'baz'})
* ]
* });
* console.log(utils.hasType(node, 'xyz')); // false
* console.log(utils.hasType(node, 'baz')); // true
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {String} `type`
* @return {Boolean}
* @api public
*/
utils.hasType = function(node, type) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
if (!Array.isArray(node.nodes)) return false;
for (var i = 0; i < node.nodes.length; i++) {
if (utils.isType(node.nodes[i], type)) {
return true;
}
}
return false;
};
/**
* Returns the first node from `node.nodes` of the given `type`
*
* ```js
* var node = new Node({
* type: 'foo',
* nodes: [
* new Node({type: 'text', val: 'abc'}),
* new Node({type: 'text', val: 'xyz'})
* ]
* });
*
* var textNode = utils.firstOfType(node.nodes, 'text');
* console.log(textNode.val);
* //=> 'abc'
* ```
* @param {Array} `nodes`
* @param {String} `type`
* @return {Object|undefined} Returns the first matching node or undefined.
* @api public
*/
utils.firstOfType = function(nodes, type) {
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (utils.isType(node, type)) {
return node;
}
}
};
/**
* Returns the node at the specified index, or the first node of the
* given `type` from `node.nodes`.
*
* ```js
* var node = new Node({
* type: 'foo',
* nodes: [
* new Node({type: 'text', val: 'abc'}),
* new Node({type: 'text', val: 'xyz'})
* ]
* });
*
* var nodeOne = utils.findNode(node.nodes, 'text');
* console.log(nodeOne.val);
* //=> 'abc'
*
* var nodeTwo = utils.findNode(node.nodes, 1);
* console.log(nodeTwo.val);
* //=> 'xyz'
* ```
*
* @param {Array} `nodes`
* @param {String|Number} `type` Node type or index.
* @return {Object} Returns a node or undefined.
* @api public
*/
utils.findNode = function(nodes, type) {
if (!Array.isArray(nodes)) {
return null;
}
if (typeof type === 'number') {
return nodes[type];
}
return utils.firstOfType(nodes, type);
};
/**
* Returns true if the given node is an "*.open" node.
*
* ```js
* var Node = require('snapdragon-node');
* var brace = new Node({type: 'brace'});
* var open = new Node({type: 'brace.open'});
* var close = new Node({type: 'brace.close'});
*
* console.log(utils.isOpen(brace)); // false
* console.log(utils.isOpen(open)); // true
* console.log(utils.isOpen(close)); // false
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Boolean}
* @api public
*/
utils.isOpen = function(node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
return node.type.slice(-5) === '.open';
};
/**
* Returns true if the given node is a "*.close" node.
*
* ```js
* var Node = require('snapdragon-node');
* var brace = new Node({type: 'brace'});
* var open = new Node({type: 'brace.open'});
* var close = new Node({type: 'brace.close'});
*
* console.log(utils.isClose(brace)); // false
* console.log(utils.isClose(open)); // false
* console.log(utils.isClose(close)); // true
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Boolean}
* @api public
*/
utils.isClose = function(node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
return node.type.slice(-6) === '.close';
};
/**
* Returns true if `node.nodes` **has** an `.open` node
*
* ```js
* var Node = require('snapdragon-node');
* var brace = new Node({
* type: 'brace',
* nodes: []
* });
*
* var open = new Node({type: 'brace.open'});
* console.log(utils.hasOpen(brace)); // false
*
* brace.pushNode(open);
* console.log(utils.hasOpen(brace)); // true
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Boolean}
* @api public
*/
utils.hasOpen = function(node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
var first = node.first || node.nodes ? node.nodes[0] : null;
if (utils.isNode(first)) {
return first.type === node.type + '.open';
}
return false;
};
/**
* Returns true if `node.nodes` **has** a `.close` node
*
* ```js
* var Node = require('snapdragon-node');
* var brace = new Node({
* type: 'brace',
* nodes: []
* });
*
* var close = new Node({type: 'brace.close'});
* console.log(utils.hasClose(brace)); // false
*
* brace.pushNode(close);
* console.log(utils.hasClose(brace)); // true
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Boolean}
* @api public
*/
utils.hasClose = function(node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
var last = node.last || node.nodes ? node.nodes[node.nodes.length - 1] : null;
if (utils.isNode(last)) {
return last.type === node.type + '.close';
}
return false;
};
/**
* Returns true if `node.nodes` has both `.open` and `.close` nodes
*
* ```js
* var Node = require('snapdragon-node');
* var brace = new Node({
* type: 'brace',
* nodes: []
* });
*
* var open = new Node({type: 'brace.open'});
* var close = new Node({type: 'brace.close'});
* console.log(utils.hasOpen(brace)); // false
* console.log(utils.hasClose(brace)); // false
*
* brace.pushNode(open);
* brace.pushNode(close);
* console.log(utils.hasOpen(brace)); // true
* console.log(utils.hasClose(brace)); // true
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Boolean}
* @api public
*/
utils.hasOpenAndClose = function(node) {
return utils.hasOpen(node) && utils.hasClose(node);
};
/**
* Push the given `node` onto the `state.inside` array for the
* given type. This array is used as a specialized "stack" for
* only the given `node.type`.
*
* ```js
* var state = { inside: {}};
* var node = new Node({type: 'brace'});
* utils.addType(state, node);
* console.log(state.inside);
* //=> { brace: [{type: 'brace'}] }
* ```
* @param {Object} `state` The `compiler.state` object or custom state object.
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Array} Returns the `state.inside` stack for the given type.
* @api public
*/
utils.addType = function(state, node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isObject(state), 'expected state to be an object');
var type = node.parent
? node.parent.type
: node.type.replace(/\.open$/, '');
if (!state.hasOwnProperty('inside')) {
state.inside = {};
}
if (!state.inside.hasOwnProperty(type)) {
state.inside[type] = [];
}
var arr = state.inside[type];
arr.push(node);
return arr;
};
/**
* Remove the given `node` from the `state.inside` array for the
* given type. This array is used as a specialized "stack" for
* only the given `node.type`.
*
* ```js
* var state = { inside: {}};
* var node = new Node({type: 'brace'});
* utils.addType(state, node);
* console.log(state.inside);
* //=> { brace: [{type: 'brace'}] }
* utils.removeType(state, node);
* //=> { brace: [] }
* ```
* @param {Object} `state` The `compiler.state` object or custom state object.
* @param {Object} `node` Instance of [snapdragon-node][]
* @return {Array} Returns the `state.inside` stack for the given type.
* @api public
*/
utils.removeType = function(state, node) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isObject(state), 'expected state to be an object');
var type = node.parent
? node.parent.type
: node.type.replace(/\.close$/, '');
if (state.inside.hasOwnProperty(type)) {
return state.inside[type].pop();
}
};
/**
* Returns true if `node.val` is an empty string, or `node.nodes` does
* not contain any non-empty text nodes.
*
* ```js
* var node = new Node({type: 'text'});
* utils.isEmpty(node); //=> true
* node.val = 'foo';
* utils.isEmpty(node); //=> false
* ```
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {Function} `fn`
* @return {Boolean}
* @api public
*/
utils.isEmpty = function(node, fn) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
if (!Array.isArray(node.nodes)) {
if (node.type !== 'text') {
return true;
}
if (typeof fn === 'function') {
return fn(node, node.parent);
}
return !utils.trim(node.val);
}
for (var i = 0; i < node.nodes.length; i++) {
var child = node.nodes[i];
if (utils.isOpen(child) || utils.isClose(child)) {
continue;
}
if (!utils.isEmpty(child, fn)) {
return false;
}
}
return true;
};
/**
* Returns true if the `state.inside` stack for the given type exists
* and has one or more nodes on it.
*
* ```js
* var state = { inside: {}};
* var node = new Node({type: 'brace'});
* console.log(utils.isInsideType(state, 'brace')); //=> false
* utils.addType(state, node);
* console.log(utils.isInsideType(state, 'brace')); //=> true
* utils.removeType(state, node);
* console.log(utils.isInsideType(state, 'brace')); //=> false
* ```
* @param {Object} `state`
* @param {String} `type`
* @return {Boolean}
* @api public
*/
utils.isInsideType = function(state, type) {
assert(isObject(state), 'expected state to be an object');
assert(isString(type), 'expected type to be a string');
if (!state.hasOwnProperty('inside')) {
return false;
}
if (!state.inside.hasOwnProperty(type)) {
return false;
}
return state.inside[type].length > 0;
};
/**
* Returns true if `node` is either a child or grand-child of the given `type`,
* or `state.inside[type]` is a non-empty array.
*
* ```js
* var state = { inside: {}};
* var node = new Node({type: 'brace'});
* var open = new Node({type: 'brace.open'});
* console.log(utils.isInside(state, open, 'brace')); //=> false
* utils.pushNode(node, open);
* console.log(utils.isInside(state, open, 'brace')); //=> true
* ```
* @param {Object} `state` Either the `compiler.state` object, if it exists, or a user-supplied state object.
* @param {Object} `node` Instance of [snapdragon-node][]
* @param {String} `type` The `node.type` to check for.
* @return {Boolean}
* @api public
*/
utils.isInside = function(state, node, type) {
assert(utils.isNode(node), 'expected node to be an instance of Node');
assert(isObject(state), 'expected state to be an object');
if (Array.isArray(type)) {
for (var i = 0; i < type.length; i++) {
if (utils.isInside(state, node, type[i])) {
return true;
}
}
return false;
}
var parent = node.parent;
if (typeof type === 'string') {
return (parent && parent.type === type) || utils.isInsideType(state, type);
}
if (typeOf(type) === 'regexp') {
if (parent && parent.type && type.test(parent.type)) {
return true;
}
var keys = Object.keys(state.inside);
var len = keys.length;
var idx = -1;
while (++idx < len) {
var key = keys[idx];
var val = state.inside[key];
if (Array.isArray(val) && val.length !== 0 && type.test(key)) {
return true;
}
}
}
return false;
};
/**
* Get the last `n` element from the given `array`. Used for getting
* a node from `node.nodes.`
*
* @param {Array} `array`
* @param {Number} `n`
* @return {undefined}
* @api public
*/
utils.last = function(arr, n) {
return arr[arr.length - (n || 1)];
};
/**
* Cast the given `val` to an array.
*
* ```js
* console.log(utils.arrayify(''));
* //=> []
* console.log(utils.arrayify('foo'));
* //=> ['foo']
* console.log(utils.arrayify(['foo']));
* //=> ['foo']
* ```
* @param {any} `val`
* @return {Array}
* @api public
*/
utils.arrayify = function(val) {
if (typeof val === 'string' && val !== '') {
return [val];
}
if (!Array.isArray(val)) {
return [];
}
return val;
};
/**
* Convert the given `val` to a string by joining with `,`. Useful
* for creating a cheerio/CSS/DOM-style selector from a list of strings.
*
* @param {any} `val`
* @return {Array}
* @api public
*/
utils.stringify = function(val) {
return utils.arrayify(val).join(',');
};
/**
* Ensure that the given value is a string and call `.trim()` on it,
* or return an empty string.
*
* @param {String} `str`
* @return {String}
* @api public
*/
utils.trim = function(str) {
return typeof str === 'string' ? str.trim() : '';
};
/**
* Return true if val is an object
*/
function isObject(val) {
return typeOf(val) === 'object';
}
/**
* Return true if val is a string
*/
function isString(val) {
return typeof val === 'string';
}
/**
* Return true if val is a function
*/
function isFunction(val) {
return typeof val === 'function';
}
/**
* Return true if val is an array
*/
function isArray(val) {
return Array.isArray(val);
}
/**
* Shim to ensure the `.append` methods work with any version of snapdragon
*/
function append(compiler, val, node) {
if (typeof compiler.append !== 'function') {
return compiler.emit(val, node);
}
return compiler.append(val, node);
}
/**
* Simplified assertion. Throws an error is `val` is falsey.
*/
function assert(val, message) {
if (!val) throw new Error(message);
}
snapdragon-util-4.0.0/package.json 0000664 0000000 0000000 00000002617 13176265700 0017125 0 ustar 00root root 0000000 0000000 {
"name": "snapdragon-util",
"description": "Utilities for the snapdragon parser/compiler.",
"version": "4.0.0",
"homepage": "https://github.com/jonschlinkert/snapdragon-util",
"author": "Jon Schlinkert (https://github.com/jonschlinkert)",
"contributors": [
"Jon Schlinkert (http://twitter.com/jonschlinkert)",
"Rouven Weßling (www.rouvenwessling.de)"
],
"repository": "jonschlinkert/snapdragon-util",
"bugs": {
"url": "https://github.com/jonschlinkert/snapdragon-util/issues"
},
"license": "MIT",
"files": [
"index.js"
],
"main": "index.js",
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "mocha"
},
"dependencies": {
"kind-of": "^6.0.0"
},
"devDependencies": {
"define-property": "^1.0.0",
"gulp": "^3.9.1",
"gulp-eslint": "^4.0.0",
"gulp-format-md": "^1.0.0",
"gulp-istanbul": "^1.1.2",
"gulp-mocha": "^3.0.1",
"isobject": "^3.0.1",
"mocha": "^3.5.3",
"snapdragon": "^0.11.0",
"snapdragon-node": "^2.1.1"
},
"keywords": [
"capture",
"compile",
"compiler",
"convert",
"match",
"parse",
"parser",
"plugin",
"render",
"snapdragon",
"snapdragonplugin",
"transform",
"util"
],
"verb": {
"layout": "default",
"tasks": [
"readme"
],
"plugins": [
"gulp-format-md"
],
"lint": {
"reflinks": true
}
}
}
snapdragon-util-4.0.0/test/ 0000775 0000000 0000000 00000000000 13176265700 0015610 5 ustar 00root root 0000000 0000000 snapdragon-util-4.0.0/test/support/ 0000775 0000000 0000000 00000000000 13176265700 0017324 5 ustar 00root root 0000000 0000000 snapdragon-util-4.0.0/test/support/index.js 0000664 0000000 0000000 00000006624 13176265700 0021001 0 ustar 00root root 0000000 0000000 'use strict';
var assert = require('assert');
var isObject = require('isobject');
var define = require('define-property');
var getters = ['siblings', 'index', 'first', 'last', 'prev', 'next'];
/**
* This is a shim used in the unit tests
* to ensure that snapdragon-util works with
* older and newer versions of snapdragon-node
*/
function isNode(node) {
return isObject(node) && node.isNode === true;
}
module.exports = function(node) {
/**
* Define a non-enumberable property on the node instance.
*
* ```js
* var node = new Node();
* node.define('foo', 'something non-enumerable');
* ```
* @param {String} `name`
* @param {any} `val`
* @return {Object} returns the node instance
* @api public
*/
node.define = function(name, val) {
define(this, name, val);
return this;
};
/**
* Given node `foo` and node `bar`, push node `bar` onto `foo.nodes`, and
* set `foo` as `bar.parent`.
*
* ```js
* var foo = new Node({type: 'foo'});
* var bar = new Node({type: 'bar'});
* foo.push(bar);
* ```
* @param {Object} `node`
* @return {Number} Returns the length of `node.nodes`
* @api public
*/
node.push = function(node) {
assert(isNode(node), 'expected node to be an instance of Node');
define(node, 'parent', this);
this.nodes = this.nodes || [];
return this.nodes.push(node);
};
/**
* Given node `foo` and node `bar`, unshift node `bar` onto `foo.nodes`, and
* set `foo` as `bar.parent`.
*
* ```js
* var foo = new Node({type: 'foo'});
* var bar = new Node({type: 'bar'});
* foo.unshift(bar);
* ```
* @param {Object} `node`
* @return {Number} Returns the length of `node.nodes`
* @api public
*/
node.unshift = function(node) {
assert(isNode(node), 'expected node to be an instance of Node');
define(node, 'parent', this);
this.nodes = this.nodes || [];
return this.nodes.unshift(node);
};
/**
* Pop a node from `node.nodes`.
*
* ```js
* var node = new Node({type: 'foo'});
* node.push(new Node({type: 'a'}));
* node.push(new Node({type: 'b'}));
* node.push(new Node({type: 'c'}));
* node.push(new Node({type: 'd'}));
* console.log(node.nodes.length);
* //=> 4
* node.pop();
* console.log(node.nodes.length);
* //=> 3
* ```
* @return {Number} Returns the popped `node`
* @api public
*/
node.pop = function() {
return this.nodes && this.nodes.pop();
};
/**
* Shift a node from `node.nodes`.
*
* ```js
* var node = new Node({type: 'foo'});
* node.push(new Node({type: 'a'}));
* node.push(new Node({type: 'b'}));
* node.push(new Node({type: 'c'}));
* node.push(new Node({type: 'd'}));
* console.log(node.nodes.length);
* //=> 4
* node.shift();
* console.log(node.nodes.length);
* //=> 3
* ```
* @return {Object} Returns the shifted `node`
* @api public
*/
node.shift = function() {
return this.nodes && this.nodes.shift();
};
/**
* Remove `node` from `node.nodes`.
*
* ```js
* node.remove(childNode);
* ```
* @param {Object} `node`
* @return {Object} Returns the removed node.
* @api public
*/
node.remove = function(node) {
assert(isNode(node), 'expected node to be an instance of Node');
this.nodes = this.nodes || [];
var idx = node.index;
if (idx !== -1) {
return this.nodes.splice(idx, 1);
}
return null;
};
};
snapdragon-util-4.0.0/test/test.js 0000664 0000000 0000000 00000112435 13176265700 0017133 0 ustar 00root root 0000000 0000000 'use strict';
require('mocha');
var assert = require('assert');
var Parser = require('snapdragon/lib/parser');
var Compiler = require('snapdragon/lib/compiler');
var Node = require('snapdragon-node');
var decorate = require('./support');
var utils = require('..');
var parser;
var ast;
describe('snapdragon-node', function() {
beforeEach(function() {
parser = new Parser({Node: Node})
.set('text', function() {
var match = this.match(/^[a-z]+/);
if (match) {
return this.node(match[0]);
}
})
.set('slash', function() {
var match = this.match(/^\//);
if (match) {
return this.node(match[0]);
}
})
.set('star', function() {
var match = this.match(/^\*/);
if (match) {
return this.node(match[0]);
}
})
ast = parser.parse('a/*/c');
ast.isNode = true;
});
describe('.arrayify', function() {
it('should cast a string to an array', function() {
assert.deepEqual(utils.arrayify('foo'), ['foo']);
});
it('should return an array', function() {
assert.deepEqual(utils.arrayify(['foo']), ['foo']);
});
it('should return an empty array when not a string or array', function() {
assert.deepEqual(utils.arrayify(), []);
});
});
describe('.stringify', function() {
it('should return a string', function() {
assert.equal(utils.stringify('foo'), 'foo');
});
it('should stringify an array', function() {
assert.equal(utils.stringify(['foo', 'bar']), 'foo,bar');
});
});
describe('.identity', function() {
it('should return node.val as it was created by the parser', function() {
var res = new Compiler()
.set('star', utils.identity)
.set('slash', utils.identity)
.set('text', utils.identity)
.compile(ast);
assert.equal(res.output, 'a/*/c');
});
});
describe('.noop', function() {
it('should make a node an empty text node', function() {
var res = new Compiler()
.set('star', utils.noop)
.set('slash', utils.identity)
.set('text', utils.identity)
.compile(ast);
assert.equal(res.output, 'a//c');
});
});
describe('.append', function() {
it('should append the specified text', function() {
var res = new Compiler()
.set('star', utils.append('@'))
.set('slash', utils.append('\\'))
.set('text', utils.identity)
.compile(ast);
assert.equal(res.output, 'a\\@\\c');
});
it('should use compiler.append method when it exists', function() {
var compiler = new Compiler()
compiler.append = compiler.emit.bind(compiler);
var res = compiler.set('star', utils.append('@'))
.set('slash', utils.append('\\'))
.set('text', utils.identity)
.compile(ast);
assert.equal(res.output, 'a\\@\\c');
});
});
describe('.toNoop', function() {
it('should throw an error when node is not a node', function() {
assert.throws(function() {
utils.toNoop();
});
});
it('should convert a node to a noop node', function() {
utils.toNoop(ast);
assert(!ast.nodes);
});
it('should convert a node to a noop with the given nodes value', function() {
utils.toNoop(ast, []);
assert.equal(ast.nodes.length, 0);
});
});
describe('.visit', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.visit();
});
});
it('should throw an error when node.nodes is not an array', function() {
assert.throws(function() {
utils.visit(new Node({type: 'foo', val: ''}));
});
});
it('should visit a node with the given function', function() {
var type = null;
utils.visit(ast, function(node) {
if (type === null) {
type = node.type;
}
});
assert.equal(type, 'root');
});
});
describe('.mapVisit', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.mapVisit();
});
});
it('should throw an error when node.nodes is not an array', function() {
assert.throws(function() {
utils.mapVisit(new Node({type: 'foo', val: ''}));
});
});
it('should map "visit" over node.nodes', function() {
var type = null;
utils.mapVisit(ast, function(node) {
if (type === null && node.parent && node.parent.type === 'root') {
type = node.type;
}
});
assert.equal(type, 'bos');
});
});
describe('.pushNode', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.pushNode();
});
});
it('should add a node to the end of node.nodes', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
});
it('should work when node.push is not a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
node.pushNode = null;
node.push = null;
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
});
});
describe('.unshiftNode', function() {
it('should throw an error when parent is not a node', function() {
assert.throws(function() {
utils.unshiftNode();
});
});
it('should throw an error when node is not a node', function() {
assert.throws(function() {
utils.unshiftNode(new Node({type: 'foo'}));
});
});
it('should add a node to the beginning of node.nodes', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
utils.unshiftNode(node, a);
utils.unshiftNode(node, b);
assert.equal(node.nodes[1].type, 'a');
assert.equal(node.nodes[0].type, 'b');
});
it('should work when node.unshift is not a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
node.unshiftNode = null;
node.unshift = null;
utils.unshiftNode(node, a);
utils.unshiftNode(node, b);
assert.equal(node.nodes[1].type, 'a');
assert.equal(node.nodes[0].type, 'b');
});
});
describe('.popNode', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.popNode();
});
});
it('should pop a node from node.nodes', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.popNode(node);
utils.popNode(node);
assert.equal(node.nodes.length, 0);
});
it('should work when node.pop is not a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
node.popNode = null;
node.pop = null;
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.popNode(node);
utils.popNode(node);
assert.equal(node.nodes.length, 0);
});
it('should work when node.pop is a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
decorate(node);
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.popNode(node);
utils.popNode(node);
assert.equal(node.nodes.length, 0);
});
});
describe('.shiftNode', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.shiftNode();
});
});
it('should shift a node from node.nodes', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.shiftNode(node);
utils.shiftNode(node);
assert.equal(node.nodes.length, 0);
});
it('should work when node.shift is not a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
node.shiftNode = null;
node.shift = null;
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.shiftNode(node);
utils.shiftNode(node);
assert.equal(node.nodes.length, 0);
});
it('should work when node.shift is a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
decorate(node);
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.shiftNode(node);
utils.shiftNode(node);
assert.equal(node.nodes.length, 0);
});
});
describe('.removeNode', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.removeNode();
});
});
it('should remove a node from node.nodes', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.removeNode(node, a);
assert.equal(node.nodes.length, 1);
utils.removeNode(node, b);
assert.equal(node.nodes.length, 0);
});
it('should work when node.remove is not a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
node.removeNode = null;
node.remove = null;
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.removeNode(node, a);
assert.equal(node.nodes.length, 1);
utils.removeNode(node, b);
assert.equal(node.nodes.length, 0);
});
it('should work when node.remove is a function', function() {
var node = new Node({type: 'brace'});
var a = new Node({type: 'a', val: 'foo'});
var b = new Node({type: 'b', val: 'foo'});
decorate(node);
utils.pushNode(node, a);
utils.pushNode(node, b);
assert.equal(node.nodes[0].type, 'a');
assert.equal(node.nodes[1].type, 'b');
utils.removeNode(node, a);
utils.removeNode(node, b);
assert.equal(node.nodes.length, 0);
});
it('should return when node.nodes does not exist', function() {
assert.doesNotThrow(function() {
var node = new Node({type: 'brace'});
utils.removeNode(node, node);
});
assert.doesNotThrow(function() {
var node = new Node({type: 'brace'});
node.removeNode = null;
node.remove = null;
utils.removeNode(node, node);
});
});
it('should return when the given node is not in node.nodes', function() {
assert.doesNotThrow(function() {
var node = new Node({type: 'brace'});
var foo = new Node({type: 'foo'});
var bar = new Node({type: 'bar'});
utils.pushNode(node, bar);
utils.removeNode(node, foo);
});
assert.doesNotThrow(function() {
var node = new Node({type: 'brace'});
var foo = new Node({type: 'foo'});
var bar = new Node({type: 'bar'});
node.removeNode = null;
node.remove = null;
utils.pushNode(node, bar);
utils.removeNode(node, foo);
});
});
});
describe('.addOpen', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.addOpen();
});
});
it('should add an open node', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.addOpen(node, Node);
assert.equal(node.nodes[0].type, 'brace.open');
});
it('should work when node.unshift is a function', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
decorate(node);
utils.addOpen(node, Node);
assert.equal(node.nodes[0].type, 'brace.open');
});
it('should work when node.unshift is not a function', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
node.unshiftNode = null;
node.unshift = null;
utils.addOpen(node, Node);
assert.equal(node.nodes[0].type, 'brace.open');
});
it('should take a filter function', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.addOpen(node, Node, function(node) {
return node.type !== 'brace';
});
assert(!node.nodes);
});
it('should use the given value on the open node', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.addOpen(node, Node, '{');
assert.equal(node.nodes[0].val, '{');
});
});
describe('.addClose', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.addClose();
});
});
it('should add a close node', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.pushNode(node, text);
utils.addClose(node, Node);
assert.equal(node.nodes[0].type, 'text');
assert.equal(node.nodes[1].type, 'brace.close');
});
it('should work when node.push is not a function', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
node.pushNode = null;
node.push = null;
utils.pushNode(node, text);
utils.addClose(node, Node);
assert.equal(node.nodes[0].type, 'text');
assert.equal(node.nodes[1].type, 'brace.close');
});
it('should work when node.push is a function', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
decorate(node);
utils.pushNode(node, text);
utils.addClose(node, Node);
assert.equal(node.nodes[0].type, 'text');
assert.equal(node.nodes[1].type, 'brace.close');
});
it('should take a filter function', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.addClose(node, Node, function(node) {
return node.type !== 'brace';
});
assert(!node.nodes);
});
it('should use the given value on the close node', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.addClose(node, Node, '}');
assert.equal(node.nodes[0].val, '}');
});
});
describe('.wrapNodes', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.wrapNodes();
});
});
it('should add an open node', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.wrapNodes(node, Node);
assert.equal(node.nodes[0].type, 'brace.open');
});
it('should add a close node', function() {
var node = new Node({type: 'brace'});
var text = new Node({type: 'text', val: 'foo'});
utils.pushNode(node, text);
utils.wrapNodes(node, Node);
assert.equal(node.nodes[0].type, 'brace.open');
assert.equal(node.nodes[1].type, 'text');
assert.equal(node.nodes[2].type, 'brace.close');
});
});
describe('.isEmpty', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.isEmpty();
});
});
it('should return true node.val is an empty string', function() {
assert(utils.isEmpty(new Node({type: 'text', val: ''})));
});
it('should return true node.val is undefined', function() {
assert(utils.isEmpty(new Node({type: 'text'})));
});
it('should return true when node.nodes is empty', function() {
var foo = new Node({type: 'foo'});
var bar = new Node({type: 'text', val: 'bar'});
utils.pushNode(foo, bar);
assert(!utils.isEmpty(foo));
utils.shiftNode(foo);
assert(utils.isEmpty(foo));
});
it('should return true when node.nodes is all non-text nodes', function() {
var node = new Node({type: 'parent'});
var foo = new Node({type: 'foo'});
var bar = new Node({type: 'bar'});
var baz = new Node({type: 'baz'});
utils.pushNode(node, foo);
utils.pushNode(node, bar);
utils.pushNode(node, baz);
assert(utils.isEmpty(foo));
});
it('should return call a custom function if only one node exists', function() {
var foo = new Node({type: 'foo'});
var text = new Node({type: 'text', val: ''});
utils.pushNode(foo, text);
assert(utils.isEmpty(foo, function(node) {
return node.type === 'text' && !node.val.trim();
}));
});
it('should return true when only open and close nodes exist', function() {
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var close = new Node({type: 'brace.close'});
utils.pushNode(brace, open);
utils.pushNode(brace, close);
assert(utils.isEmpty(brace));
});
it('should call a custom function on "middle" nodes (1)', function() {
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var text = new Node({type: 'text', val: ''});
var close = new Node({type: 'brace.close'});
utils.pushNode(brace, open);
utils.pushNode(brace, text);
utils.pushNode(brace, text);
utils.pushNode(brace, text);
utils.pushNode(brace, close);
assert(utils.isEmpty(brace, function(node) {
if (node.type !== 'text') {
return false;
}
return node.val.trim() === '';
}));
});
it('should call a custom function on "middle" nodes (2)', function() {
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var text = new Node({type: 'text', val: ''});
var close = new Node({type: 'brace.close'});
utils.pushNode(brace, open);
utils.pushNode(brace, text);
utils.pushNode(brace, text);
utils.pushNode(brace, text);
utils.pushNode(brace, close);
assert(!utils.isEmpty(brace, function(node, parent) {
return parent.nodes.length === 0;
}));
});
it('should call a custom function on "middle" nodes (3)', function() {
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var text = new Node({type: 'text', val: 'foo'});
var close = new Node({type: 'brace.close'});
utils.pushNode(brace, open);
utils.pushNode(brace, text);
utils.pushNode(brace, close);
assert(!utils.isEmpty(brace, function(node) {
if (node.type !== 'text') {
return false;
}
return node.val.trim() === '';
}));
});
it('should call a custom function on "middle" nodes (4)', function() {
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var empty = new Node({type: 'text', val: ''});
var text = new Node({type: 'text', val: 'foo'});
var close = new Node({type: 'brace.close'});
utils.pushNode(brace, open);
utils.pushNode(brace, empty);
utils.pushNode(brace, empty);
utils.pushNode(brace, empty);
utils.pushNode(brace, empty);
utils.pushNode(brace, text);
utils.pushNode(brace, close);
assert(!utils.isEmpty(brace, function(node) {
if (node.type !== 'text') {
return false;
}
return node.val.trim() === '';
}));
});
});
describe('.isType', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.isType();
});
});
it('should throw an error when matcher is invalid', function() {
assert.throws(function() {
utils.isType(new Node({type: 'foo'}));
});
});
it('should return true if the node is the given type', function() {
assert(utils.isType(ast, 'root'));
assert(utils.isType(ast.last, 'eos'));
});
});
describe('.isInsideType', function() {
it('should throw an error when parent is not a node', function() {
assert.throws(function() {
utils.isInsideType();
});
});
it('should throw an error when child not a node', function() {
assert.throws(function() {
utils.isInsideType(new Node({type: 'foo'}));
});
});
it('should return false when state.inside is not an object', function() {
var state = {};
var node = new Node({type: 'brace'});
assert(!utils.isInsideType(state, 'brace'));
});
it('should return false when state.inside[type] is not an object', function() {
var state = {inside: {}};
var node = new Node({type: 'brace'});
assert(!utils.isInsideType(state, 'brace'));
});
it('should return true when state has the given type', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(utils.isInsideType(state, 'brace'));
});
it('should return false when state does not have the given type', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(utils.isInsideType(state, 'brace'));
utils.removeType(state, node);
assert(!utils.isInsideType(state, 'brace'));
});
});
describe('.isInside', function() {
it('should throw an error when parent is not a node', function() {
assert.throws(function() {
utils.isInside();
});
});
it('should throw an error when child not a node', function() {
assert.throws(function() {
utils.isInside(new Node({type: 'foo'}));
});
});
it('should return false when state.inside is not an object', function() {
var state = {};
var node = new Node({type: 'brace'});
assert(!utils.isInside(state, node, 'brace'));
});
it('should return false when state.inside[type] is not an object', function() {
var state = {inside: {}};
var node = new Node({type: 'brace'});
assert(!utils.isInside(state, node, 'brace'));
});
it('should return true when state has the given type', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(utils.isInside(state, node, 'brace'));
});
it('should return true when state has one of the given types', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(utils.isInside(state, node, ['foo', 'brace']));
});
it('should return false when state does not have one of the given types', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(!utils.isInside(state, node, ['foo', 'bar']));
});
it('should return true when a regex matches a type', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(utils.isInside(state, node, /(foo|brace)/));
});
it('should return true when the type matches parent.type', function() {
var state = {};
var brace = new Node({type: 'brace'});
var node = new Node({type: 'brace.open'});
utils.pushNode(brace, node);
assert(utils.isInside(state, node, 'brace'));
});
it('should return true when regex matches parent.type', function() {
var state = {};
var brace = new Node({type: 'brace'});
var node = new Node({type: 'brace.open'});
utils.pushNode(brace, node);
assert(utils.isInside(state, node, /(foo|brace)/));
});
it('should return false when a regex does not match a type', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(!utils.isInside(state, node, /(foo|bar)/));
});
it('should return false when type is invalie', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(!utils.isInside(state, node, null));
});
it('should return false when state does not have the given type', function() {
var state = { inside: {}};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(utils.isInside(state, node, 'brace'));
utils.removeType(state, node);
assert(!utils.isInside(state, node, 'brace'));
});
});
describe('.hasType', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.hasType();
});
});
it('should return true if node.nodes has the given type', function() {
assert(utils.hasType(ast, 'text'));
assert(!utils.hasType(ast, 'foo'));
});
it('should return false when node.nodes does not exist', function() {
assert(!utils.hasType(new Node({type: 'foo'})));
});
});
describe('.firstOfType', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.firstOfType();
});
});
it('should get the first node of the given type', function() {
var node = utils.firstOfType(ast.nodes, 'text');
assert.equal(node.type, 'text');
});
});
describe('.last', function() {
it('should get the last node', function() {
assert.equal(utils.last(ast.nodes).type, 'eos');
});
});
describe('.findNode', function() {
it('should get the node with the given type', function() {
var text = utils.findNode(ast.nodes, 'text');
assert.equal(text.type, 'text');
});
it('should get the node matching the given regex', function() {
var text = utils.findNode(ast.nodes, /text/);
assert.equal(text.type, 'text');
});
it('should get the first matching node', function() {
var node = utils.findNode(ast.nodes, [/text/, 'bos']);
assert.equal(node.type, 'bos');
node = utils.findNode(ast.nodes, [/text/]);
assert.equal(node.type, 'text');
});
it('should get the node at the given index', function() {
var bos = utils.findNode(ast.nodes, 0);
assert.equal(bos.type, 'bos');
var text = utils.findNode(ast.nodes, 1);
assert.equal(text.type, 'text');
});
it('should return null when node does not exist', function() {
assert.equal(utils.findNode(new Node({type: 'foo'})), null);
});
});
describe('.removeNode', function() {
it('should throw an error when parent is not a node', function() {
assert.throws(function() {
utils.removeNode();
});
});
it('should throw an error when child is not a node', function() {
assert.throws(function() {
utils.removeNode(new Node({type: 'foo'}));
});
});
it('should remove a node from parent.nodes', function() {
var brace = new Node({type: 'brace'});
var open = new Node({type: 'brace.open'});
var foo = new Node({type: 'foo'});
var bar = new Node({type: 'bar'});
var baz = new Node({type: 'baz'});
var qux = new Node({type: 'qux'});
var close = new Node({type: 'brace.close'});
utils.pushNode(brace, open);
utils.pushNode(brace, foo);
utils.pushNode(brace, bar);
utils.pushNode(brace, baz);
utils.pushNode(brace, qux);
utils.pushNode(brace, close);
assert.equal(brace.nodes.length, 6);
assert.equal(brace.nodes[0].type, 'brace.open');
assert.equal(brace.nodes[1].type, 'foo');
assert.equal(brace.nodes[2].type, 'bar');
assert.equal(brace.nodes[3].type, 'baz');
assert.equal(brace.nodes[4].type, 'qux');
assert.equal(brace.nodes[5].type, 'brace.close');
// remove node
utils.removeNode(brace, bar);
assert.equal(brace.nodes.length, 5);
assert.equal(brace.nodes[0].type, 'brace.open');
assert.equal(brace.nodes[1].type, 'foo');
assert.equal(brace.nodes[2].type, 'baz');
assert.equal(brace.nodes[3].type, 'qux');
assert.equal(brace.nodes[4].type, 'brace.close');
});
});
describe('.isOpen', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.isOpen();
});
});
it('should be true if node is an ".open" node', function() {
var node = new Node({type: 'foo.open'});
assert(utils.isOpen(node));
});
it('should be false if node is not an ".open" node', function() {
var node = new Node({type: 'foo'});
assert(!utils.isOpen(node));
});
});
describe('.isClose', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.isClose();
});
});
it('should be true if node is a ".close" node', function() {
var node = new Node({type: 'foo.close'});
assert(utils.isClose(node));
});
it('should be false if node is not a ".close" node', function() {
var node = new Node({type: 'foo'});
assert(!utils.isClose(node));
});
});
describe('.hasOpen', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.hasOpen();
});
});
it('should be true if node has an ".open" node', function() {
var parent = new Node({type: 'foo'});
var node = new Node({type: 'foo.open'});
utils.pushNode(parent, node);
assert(utils.hasOpen(parent));
});
it('should be false if does not have an ".open" node', function() {
var parent = new Node({type: 'foo'});
assert(!utils.hasOpen(parent));
});
});
describe('.hasClose', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.hasClose();
});
});
it('should be true if node has a ".close" node', function() {
var parent = new Node({type: 'foo'});
var open = new Node({type: 'foo.open'});
var close = new Node({type: 'foo.close'});
utils.pushNode(parent, open);
utils.pushNode(parent, close);
assert(utils.hasClose(parent));
});
it('should be false if does not have a ".close" node', function() {
var parent = new Node({type: 'foo'});
assert(!utils.hasClose(parent));
});
});
describe('.hasOpenAndClose', function() {
it('should throw an error when not a node', function() {
assert.throws(function() {
utils.hasOpenAndClose();
});
});
it('should be true if node has ".open" and ".close" nodes', function() {
var parent = new Node({type: 'foo'});
var open = new Node({type: 'foo.open'});
var close = new Node({type: 'foo.close'});
utils.pushNode(parent, open);
utils.pushNode(parent, close);
assert(utils.hasOpenAndClose(parent));
});
it('should be false if does not have a ".close" node', function() {
var parent = new Node({type: 'foo'});
var open = new Node({type: 'foo.open'});
utils.pushNode(parent, open);
assert(!utils.hasOpenAndClose(parent));
});
it('should be false if does not have an ".open" node', function() {
var parent = new Node({type: 'foo'});
var close = new Node({type: 'foo.close'});
utils.pushNode(parent, close);
assert(!utils.hasOpenAndClose(parent));
});
});
describe('.pushNode', function() {
it('should throw an error when parent is not a node', function() {
assert.throws(function() {
utils.pushNode();
});
});
it('should throw an error when child is not a node', function() {
assert.throws(function() {
utils.pushNode(new Node({type: 'foo'}));
});
});
it('should add a node to `node.nodes`', function() {
var node = new Node({type: 'foo'});
utils.pushNode(ast, node);
assert.equal(ast.last.type, 'foo');
});
it('should set the parent on the given node', function() {
var node = new Node({type: 'foo'});
utils.pushNode(ast, node);
assert.equal(node.parent.type, 'root');
});
it('should set the parent.nodes as `.siblings` on the given node', function() {
var node = new Node({type: 'foo'});
assert.equal(node.siblings, null);
utils.pushNode(ast, node);
assert.equal(node.siblings.length, 8);
});
});
describe('.addType', function() {
it('should throw an error when state is not given', function() {
assert.throws(function() {
utils.addType();
});
});
it('should throw an error when a node is not passed', function() {
assert.throws(function() {
utils.addType({});
});
});
it('should add the type to the state.inside array', function() {
var state = {};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(state.inside);
assert(state.inside.brace);
assert.equal(state.inside.brace.length, 1);
});
it('should add the type based on parent.type', function() {
var state = {};
var parent = new Node({type: 'brace'});
var node = new Node({type: 'brace.open'});
utils.pushNode(parent, node);
utils.addType(state, node);
assert(state.inside);
assert(state.inside.brace);
assert.equal(state.inside.brace.length, 1);
});
});
describe('.removeType', function() {
it('should throw an error when state is not given', function() {
assert.throws(function() {
utils.removeType();
});
});
it('should throw an error when a node is not passed', function() {
assert.throws(function() {
utils.removeType({});
});
});
it('should add a state.inside object', function() {
var state = {};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(state.inside);
});
it('should add a type array to the state.inside object', function() {
var state = {};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(state.inside);
assert(Array.isArray(state.inside.brace));
});
it('should add the node to the state.inside type array', function() {
var state = {};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(state.inside);
assert(state.inside.brace);
assert.equal(state.inside.brace.length, 1);
utils.removeType(state, node);
assert.equal(state.inside.brace.length, 0);
});
it('should use a type array if it already exists', function() {
var state = { inside: { brace: [new Node({type: 'brace.open'})] }};
var node = new Node({type: 'brace'});
utils.addType(state, node);
assert(state.inside);
assert(state.inside.brace);
assert.equal(state.inside.brace.length, 2);
utils.removeType(state, node);
assert.equal(state.inside.brace.length, 1);
});
it('should remove the type based on parent.type', function() {
var state = { inside: { brace: [new Node({type: 'brace.open'})] }};
var parent = new Node({type: 'brace'});
var node = new Node({type: 'brace.open'});
utils.pushNode(parent, node);
utils.addType(state, node);
assert(state.inside);
assert(state.inside.brace);
assert.equal(state.inside.brace.length, 2);
utils.removeType(state, node);
assert.equal(state.inside.brace.length, 1);
});
it('should throw an error when state.inside does not exist', function() {
var state = {};
var node = new Node({type: 'brace'});
assert.throws(function() {
utils.removeType(state, node);
});
});
it('should just return when state.inside type does not exist', function() {
var state = {inside: {}};
var node = new Node({type: 'brace'});
utils.removeType(state, node);
});
});
});