mdast-util-heading-range
Advanced tools
Comparing version 2.0.1 to 2.0.2
242
index.js
@@ -1,188 +0,116 @@ | ||
/** | ||
* @author Titus Wormer | ||
* @copyright 2015 Titus Wormer | ||
* @license MIT | ||
* @module mdast:util:heading-range | ||
* @fileoverview Markdown heading as ranges in mdast. | ||
*/ | ||
'use strict'; | ||
/* eslint-env commonjs */ | ||
/* | ||
* Dependencies. | ||
*/ | ||
/* Dependencies. */ | ||
var toString = require('mdast-util-to-string'); | ||
/* | ||
* Methods. | ||
*/ | ||
/* Expose. */ | ||
module.exports = headingRange; | ||
/* Methods. */ | ||
var splice = [].splice; | ||
/** | ||
* Transform a string into an applicable expression. | ||
* | ||
* @param {string} value - Value to transform. | ||
* @return {RegExp} - Expression. | ||
*/ | ||
function toExpression(value) { | ||
return new RegExp('^(' + value + ')$', 'i'); | ||
} | ||
/* Search `node` for `heading` and invoke `callback`. */ | ||
function headingRange(node, heading, callback) { | ||
var test = heading; | ||
/** | ||
* Wrap an expression into an assertion function. | ||
* | ||
* @param {RegExp} expression - Expression to test. | ||
* @return {Function} - Assertion. | ||
*/ | ||
function wrapExpression(expression) { | ||
/** | ||
* Assert `value` matches the bound `expression`. | ||
* | ||
* @param {string} value - Value to check. | ||
* @return {boolean} - Whether `value` matches. | ||
*/ | ||
function assertion(value) { | ||
return expression.test(value); | ||
} | ||
if (typeof test === 'string') { | ||
test = toExpression(test); | ||
} | ||
return assertion; | ||
} | ||
if ('test' in test) { | ||
test = wrapExpression(test); | ||
} | ||
/** | ||
* Check if `node` is a heading. | ||
* | ||
* @param {Node} node - Node to check. | ||
* @return {boolean} - Whether `node` is a heading. | ||
*/ | ||
function isHeading(node) { | ||
return node && node.type === 'heading'; | ||
search(node, test, callback); | ||
} | ||
/** | ||
* Check if `node` is the main heading. | ||
* | ||
* @param {Node} node - Node to check. | ||
* @param {number?} depth - Depth to search for. | ||
* @param {function(string): boolean} test - Tester. | ||
* @return {boolean} - Whether `node` is an opening | ||
* heading. | ||
*/ | ||
function isOpeningHeading(node, depth, test) { | ||
return depth === null && isHeading(node) && test(toString(node), node); | ||
} | ||
/** | ||
* Check if `node` is the next heading. | ||
* | ||
* @param {Node} node - Node to check. | ||
* @param {number?} depth - Depth of the opening heading. | ||
* @return {boolean} - Whether `node` is a closing | ||
* heading. | ||
*/ | ||
function isClosingHeading(node, depth) { | ||
return depth && isHeading(node) && node.depth <= depth; | ||
} | ||
/** | ||
* Search a node for heading range. | ||
* | ||
* @param {Node} root - Node to search. | ||
* @param {Function} test - Assertion. | ||
* @param {Function} callback - Callback invoked when | ||
* found. | ||
*/ | ||
/* Search a node for heading range. */ | ||
function search(root, test, callback) { | ||
var index = -1; | ||
var children = root.children; | ||
var length = children.length; | ||
var depth = null; | ||
var start = null; | ||
var end = null; | ||
var nodes; | ||
var clean; | ||
var child; | ||
var index = -1; | ||
var children = root.children; | ||
var length = children.length; | ||
var depth = null; | ||
var start = null; | ||
var end = null; | ||
var nodes; | ||
var clean; | ||
var child; | ||
while (++index < length) { | ||
child = children[index]; | ||
while (++index < length) { | ||
child = children[index]; | ||
if (isClosingHeading(child, depth)) { | ||
end = index; | ||
break; | ||
} | ||
if (isClosingHeading(child, depth)) { | ||
end = index; | ||
break; | ||
} | ||
if (isOpeningHeading(child, depth, test)) { | ||
start = index; | ||
depth = child.depth; | ||
} | ||
if (isOpeningHeading(child, depth, test)) { | ||
start = index; | ||
depth = child.depth; | ||
} | ||
} | ||
if (start !== null) { | ||
if (end === null) { | ||
end = length + 1; | ||
} | ||
if (start !== null) { | ||
if (end === null) { | ||
end = length + 1; | ||
} | ||
nodes = callback( | ||
children[start], | ||
children.slice(start + 1, end), | ||
children[end], | ||
{ | ||
'parent': root, | ||
'start': start, | ||
'end': end in children ? end : null | ||
} | ||
); | ||
nodes = callback( | ||
children[start], | ||
children.slice(start + 1, end), | ||
children[end], | ||
{ | ||
parent: root, | ||
start: start, | ||
end: end in children ? end : null | ||
} | ||
); | ||
clean = []; | ||
index = -1; | ||
length = nodes && nodes.length; | ||
clean = []; | ||
index = -1; | ||
length = nodes && nodes.length; | ||
/* | ||
* Ensure no empty nodes are inserted. This could | ||
* be the case if `end` is in `nodes` but no `end` | ||
* node exists. | ||
*/ | ||
/* Ensure no empty nodes are inserted. This could | ||
* be the case if `end` is in `nodes` but no `end` | ||
* node exists. */ | ||
while (++index < length) { | ||
if (nodes[index]) { | ||
clean.push(nodes[index]); | ||
} | ||
} | ||
while (++index < length) { | ||
if (nodes[index]) { | ||
clean.push(nodes[index]); | ||
} | ||
} | ||
if (nodes) { | ||
splice.apply(children, [start, end - start + 1].concat(clean)); | ||
} | ||
if (nodes) { | ||
splice.apply(children, [start, end - start + 1].concat(clean)); | ||
} | ||
} | ||
} | ||
/** | ||
* Search `node` for `heading` and invoke `callback`. | ||
* | ||
* @param {Node} node - Node to search in. | ||
* @param {string|RegExp|Function} heading - Heading to | ||
* search for. | ||
* @param {Function} callback - Callback invoked when | ||
* found. | ||
*/ | ||
function headingRange(node, heading, callback) { | ||
var test = heading; | ||
/* Transform a string into an applicable expression. */ | ||
function toExpression(value) { | ||
return new RegExp('^(' + value + ')$', 'i'); | ||
} | ||
if (typeof test === 'string') { | ||
test = toExpression(test); | ||
} | ||
/* Wrap an expression into an assertion function. */ | ||
function wrapExpression(expression) { | ||
return assertion; | ||
if ('test' in test) { | ||
test = wrapExpression(test); | ||
} | ||
/* Assert `value` matches the bound `expression`. */ | ||
function assertion(value) { | ||
return expression.test(value); | ||
} | ||
} | ||
search(node, test, callback); | ||
/* Check if `node` is a heading. */ | ||
function isHeading(node) { | ||
return node && node.type === 'heading'; | ||
} | ||
/* | ||
* Expose. | ||
*/ | ||
/* Check if `node` is the main heading. */ | ||
function isOpeningHeading(node, depth, test) { | ||
return depth === null && isHeading(node) && test(toString(node), node); | ||
} | ||
module.exports = headingRange; | ||
/* Check if `node` is the next heading. */ | ||
function isClosingHeading(node, depth) { | ||
return depth && isHeading(node) && node.depth <= depth; | ||
} |
{ | ||
"name": "mdast-util-heading-range", | ||
"version": "2.0.1", | ||
"version": "2.0.2", | ||
"description": "Markdown heading as ranges in mdast", | ||
@@ -12,10 +12,4 @@ "license": "MIT", | ||
], | ||
"dependencies": { | ||
"mdast-util-to-string": "^1.0.0" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/wooorm/mdast-util-heading-range.git" | ||
}, | ||
"bugs": "https://github.com/wooorm/mdast-util-heading-range/issues", | ||
"repository": "https://github.com/syntax-tree/mdast-util-heading-range", | ||
"bugs": "https://github.com/syntax-tree/mdast-util-heading-range/issues", | ||
"author": "Titus Wormer <tituswormer@gmail.com> (http://wooorm.com)", | ||
@@ -28,31 +22,43 @@ "contributors": [ | ||
], | ||
"dependencies": { | ||
"mdast-util-to-string": "^1.0.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^13.0.0", | ||
"eslint": "^2.0.0", | ||
"browserify": "^14.0.0", | ||
"esmangle": "^1.0.0", | ||
"istanbul": "^0.4.0", | ||
"jscs": "^3.0.0", | ||
"jscs-jsdoc": "^2.0.0", | ||
"remark": "^5.0.0", | ||
"remark-cli": "^1.0.0", | ||
"remark-comment-config": "^4.0.0", | ||
"remark-github": "^5.0.0", | ||
"remark-lint": "^4.0.0", | ||
"remark-toc": "^3.0.0", | ||
"remark-usage": "^4.0.0", | ||
"remark-validate-links": "^4.0.0", | ||
"tape": "^4.4.0" | ||
"nyc": "^11.0.0", | ||
"remark": "^7.0.0", | ||
"remark-cli": "^3.0.0", | ||
"remark-preset-wooorm": "^3.0.0", | ||
"tape": "^4.4.0", | ||
"xo": "^0.18.0" | ||
}, | ||
"scripts": { | ||
"build-md": "remark . --quiet --frail", | ||
"build-md": "remark . --quiet --frail --output", | ||
"build-bundle": "browserify index.js --no-builtins -s mdastUtilHeadingRange > mdast-util-heading-range.js", | ||
"build-mangle": "esmangle mdast-util-heading-range.js > mdast-util-heading-range.min.js", | ||
"build": "npm run build-md && npm run build-bundle && npm run build-mangle", | ||
"lint-api": "eslint .", | ||
"lint-style": "jscs --reporter inline .", | ||
"lint": "npm run lint-api && npm run lint-style", | ||
"lint": "xo", | ||
"test-api": "node test.js", | ||
"test-coverage": "istanbul cover test.js", | ||
"test-coverage": "nyc --reporter lcov tape test.js", | ||
"test": "npm run build && npm run lint && npm run test-coverage" | ||
}, | ||
"xo": { | ||
"space": true, | ||
"esnext": false, | ||
"ignore": [ | ||
"mdast-util-heading-range.js" | ||
] | ||
}, | ||
"nyc": { | ||
"check-coverage": true, | ||
"lines": 100, | ||
"functions": 100, | ||
"branches": 100 | ||
}, | ||
"remarkConfig": { | ||
"plugins": [ | ||
"preset-wooorm" | ||
] | ||
} | ||
} |
102
readme.md
# mdast-util-heading-range [![Build Status][build-badge]][build-status] [![Coverage Status][coverage-badge]][coverage-status] [![Chat][chat-badge]][chat] | ||
<!--lint disable list-item-spacing heading-increment no-duplicate-headings--> | ||
Markdown heading as ranges in [**MDAST**][mdast]. | ||
@@ -15,51 +13,45 @@ | ||
**mdast-util-heading-range** is also available as an AMD, CommonJS, and | ||
globals module, [uncompressed and compressed][releases]. | ||
## Usage | ||
Dependencies: | ||
Say we have the following file, `example.md`: | ||
```markdown | ||
# Foo | ||
Bar. | ||
# Baz | ||
``` | ||
And our script, `example.js`, looks as follows: | ||
```javascript | ||
var vfile = require('to-vfile'); | ||
var remark = require('remark'); | ||
var heading = require('mdast-util-heading-range'); | ||
var remark = require('remark'); | ||
``` | ||
Plug-in: | ||
remark() | ||
.use(plugin) | ||
.process(vfile.readSync('example.md'), function (err, file) { | ||
if (err) throw err; | ||
console.log(String(file)); | ||
}); | ||
```javascript | ||
function plugin() { | ||
return function (node) { | ||
heading(node, 'foo', function (start, nodes, end) { | ||
return [ | ||
start, | ||
{ | ||
'type': 'paragraph', | ||
'children': [{ | ||
'type': 'text', | ||
'value': 'Qux.' | ||
}] | ||
}, | ||
end | ||
]; | ||
}); | ||
} | ||
return transformer; | ||
function transformer(tree) { | ||
heading(tree, 'foo', mutate); | ||
} | ||
function mutate(start, nodes, end) { | ||
return [ | ||
start, | ||
{type: 'paragraph', children: [{type: 'text', value: 'Qux.'}]}, | ||
end | ||
]; | ||
} | ||
} | ||
``` | ||
Process a document. | ||
Now, running `node example` yields: | ||
```javascript | ||
var file = remark().use(plugin).process([ | ||
'# Foo', | ||
'', | ||
'Bar.', | ||
'', | ||
'# Baz', | ||
'' | ||
].join('\n')); | ||
``` | ||
Yields: | ||
```markdown | ||
@@ -83,8 +75,8 @@ # Foo | ||
* `node` ([`Node`][node]) — Node to search; | ||
* `node` ([`Node`][node]) — Node to search | ||
* `test` (`string`, `RegExp`, `function(string, Node): boolean`) | ||
— Heading to look for. When `string`, wrapped in | ||
`new RegExp('^(' + value + ')$', 'i')`; when `RegExp`, wrapped | ||
in `function (value) {expression.test(value)}`. | ||
* `onrun` ([`Function`][onrun]). | ||
in `function (value) {expression.test(value)}` | ||
* `onrun` ([`Function`][onrun]) | ||
@@ -97,10 +89,10 @@ #### `function onrun(start, nodes, end?, scope)` | ||
* `start` (`Heading`) — Start of range; | ||
* `nodes` (`Array.<Node>`) — Nodes between `start` and `end`; | ||
* `end` (`Heading?`) — End of range, if any. | ||
* `start` (`Heading`) — Start of range | ||
* `nodes` (`Array.<Node>`) — Nodes between `start` and `end` | ||
* `end` (`Heading?`) — End of range, if any | ||
* `scope` (`Object`): | ||
* `parent` (`Node`) — Parent of the range; | ||
* `start` (`number`) — Index of `start` in `parent`; | ||
* `end` (`number?`) — Index of `end` in `parent`. | ||
* `parent` (`Node`) — Parent of the range | ||
* `start` (`number`) — Index of `start` in `parent` | ||
* `end` (`number?`) — Index of `end` in `parent` | ||
@@ -113,9 +105,9 @@ ## License | ||
[build-badge]: https://img.shields.io/travis/wooorm/mdast-util-heading-range.svg | ||
[build-badge]: https://img.shields.io/travis/syntax-tree/mdast-util-heading-range.svg | ||
[build-status]: https://travis-ci.org/wooorm/mdast-util-heading-range | ||
[build-status]: https://travis-ci.org/syntax-tree/mdast-util-heading-range | ||
[coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/mdast-util-heading-range.svg | ||
[coverage-badge]: https://img.shields.io/codecov/c/github/syntax-tree/mdast-util-heading-range.svg | ||
[coverage-status]: https://codecov.io/github/wooorm/mdast-util-heading-range | ||
[coverage-status]: https://codecov.io/github/syntax-tree/mdast-util-heading-range | ||
@@ -126,4 +118,2 @@ [chat-badge]: https://img.shields.io/gitter/room/wooorm/remark.svg | ||
[releases]: https://github.com/wooorm/mdast-util-heading-range/releases | ||
[license]: LICENSE | ||
@@ -135,6 +125,6 @@ | ||
[mdast]: https://github.com/wooorm/mdast | ||
[mdast]: https://github.com/syntax-tree/mdast | ||
[node]: https://github.com/wooorm/mdast#node | ||
[node]: https://github.com/syntax-tree/unist#node | ||
[onrun]: #function-onrunstart-nodes-end-scope |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
8
8106
94
125
1
1