Skip to content

Commit

Permalink
Refactor to externalise assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Sep 2, 2015
1 parent 980e34b commit df39f22
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 124 deletions.
3 changes: 3 additions & 0 deletions component.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"util",
"utility"
],
"dependencies": {
"wooorm/unist-util-is": "^1.0.0"
},
"repository": "wooorm/unist-util-find-before",
"scripts": [
"index.js"
Expand Down
59 changes: 5 additions & 54 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,11 @@

/* eslint-env commonjs */

/**
* Test.
*
* @typedef {Function} findBefore~test
* @param {Node} node - Node to test.
* @param {number} index - Position of `node` in `parent`.
* @param {Node} parent - Parent of `node`.
* @return {boolean?} - Whether this iteration passes.
*/

/**
* Utility to return true for the first node.
*
* @type {findBefore~test}
*/
function first() {
return true;
}

/**
* Utility to convert a string into a function which checks
* a given node’s type for said string.
*
* @param {string} test - Node type to test.
* @return {findBefore~test} - Tester.
/*
* Dependencies.
*/
function typeFactory(test) {
return function (node) {
return Boolean(node && node.type === test);
}
}

/**
* Utility to convert a node into a function which checks
* a given node for strict equality.
*
* @param {Node} test - Node to test.
* @return {findBefore~test} - Tester.
*/
function nodeFactory(test) {
return function (node) {
return Boolean(node && node === test);
}
}
var is = require('unist-util-is');

/**
* Find a node before `index` in `parent` which passes
Expand All @@ -62,7 +23,7 @@ function nodeFactory(test) {
* @param {Node} parent - Parent to search in.
* @param {number|Node} index - (Position of) node to
* search before.
* @param {string|Node|findBefore~test} test - Tester.
* @param {*} test - See `wooorm/unist-util-is`.
* @return {Node?} - A child node of `parent` which passes
* `test`.
*/
Expand All @@ -89,20 +50,10 @@ function findBefore(parent, index, test) {
index = children.length;
}

if (typeof test === 'string') {
test = typeFactory(test);
} else if (test && test.type) {
test = nodeFactory(test);
} else if (test === null || test === undefined) {
test = first;
} else if (typeof test !== 'function') {
throw new Error('Expected function, string, or node as test');
}

while (index--) {
child = children[index];

if (test(child, index, parent)) {
if (is(test, child, index, parent)) {
return child;
}
}
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"util",
"utility"
],
"dependencies": {
"unist-util-is": "^1.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/wooorm/unist-util-find-before.git"
Expand Down
24 changes: 2 additions & 22 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,31 +75,11 @@ given).

* `index` (`number`) — Position of child to search before;

* `test` ([`Function`](#function-testnode-index-parent), `string`, or
`Node`, optional)
— Invoked for each preceding child of `parent` before `node` or `position`.
When `test` returns truthy for the first time on a `child`, that `child` is
returned.

Passing a `string` is equal to passing
`function (node) {return node.type === test}`.

Passing a `node` is equal to passing
`function (node) {return node === test}`, useful when checking if `test`
comes before `index` or `node` in `parent`.
* `test` (`Function`, `string`, or `Node`; optional)
— See [`is()`](https://github.com/wooorm/unist-util-is#istest-node-index-parent-context).

**Returns**: `node?`, when found. Child node of `parent` which passes `test`.

### function test(node, index, parent)

**Parameters**:

* `node` (`Node`) — Node to test;
* `index` (`number`) — Position of `node` in `parent`.
* `parent` (`Node`) — Parent of `node`.

**Returns**: `boolean?`, whether this iteration passes.

## License

[MIT](LICENSE) © [Titus Wormer](http://wooorm.com)
12 changes: 8 additions & 4 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,19 @@ describe('unist-util-find-before', function () {
assert.throws(function () {
findBefore({
'type': 'foo',
'children': []
}, 0, false);
'children': [{
'type': 'bar'
}]
}, 1, false);
}, /Expected function, string, or node as test/);

assert.throws(function () {
findBefore({
'type': 'foo',
'children': []
}, 0, true);
'children': [{
'type': 'bar'
}]
}, 1, true);
}, /Expected function, string, or node as test/);
});

Expand Down
178 changes: 135 additions & 43 deletions unist-util-find-before.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,90 @@

/* eslint-env commonjs */

/*
* Dependencies.
*/

var is = require('unist-util-is');

/**
* Find a node before `index` in `parent` which passes
* `test`.
*
* @param {Node} parent - Parent to search in.
* @param {number|Node} index - (Position of) node to
* search before.
* @param {*} test - See `wooorm/unist-util-is`.
* @return {Node?} - A child node of `parent` which passes
* `test`.
*/
function findBefore(parent, index, test) {
var children;
var child;

if (!parent || !parent.type || !parent.children) {
throw new Error('Expected parent node');
}

children = parent.children;

if (index && index.type) {
index = children.indexOf(index);
}

if (isNaN(index) || index < 0 || index === Infinity) {
throw new Error('Expected positive finite index or child node');
}

/* Performance. */
if (index > children.length) {
index = children.length;
}

while (index--) {
child = children[index];

if (is(test, child, index, parent)) {
return child;
}
}

return null;
}

/*
* Expose.
*/

module.exports = findBefore;

},{"unist-util-is":2}],2:[function(require,module,exports){
/**
* @author Titus Wormer
* @copyright 2015 Titus Wormer
* @license MIT
* @module unist:util:is
* @fileoverview Utility to check if a node passes a test.
*/

'use strict';

/* eslint-env commonjs */

/**
* Test.
*
* @typedef {Function} findBefore~test
* @typedef {Function} is~test
* @param {Node} node - Node to test.
* @param {number} index - Position of `node` in `parent`.
* @param {Node} parent - Parent of `node`.
* @return {boolean?} - Whether this iteration passes.
*/

/**
* Utility to return true for the first node.
* Utility to return true.
*
* @type {findBefore~test}
* @type {is~test}
*/
function first() {
return true;
Expand All @@ -35,7 +105,7 @@ function first() {
* a given node’s type for said string.
*
* @param {string} test - Node type to test.
* @return {findBefore~test} - Tester.
* @return {is~test} - Tester.
*/
function typeFactory(test) {
return function (node) {
Expand All @@ -48,47 +118,58 @@ function typeFactory(test) {
* a given node for strict equality.
*
* @param {Node} test - Node to test.
* @return {findBefore~test} - Tester.
* @return {is~test} - Tester.
*/
function nodeFactory(test) {
return function (node) {
return Boolean(node && node === test);
return node === test;
}
}

/**
* Find a node before `index` in `parent` which passes
* `test`.
* Assert if `test` passes for `node`.
* When a `parent` node is known the `index` of node
*
* @param {Node} parent - Parent to search in.
* @param {number|Node} index - (Position of) node to
* search before.
* @param {string|Node|findBefore~test} test - Tester.
* @return {Node?} - A child node of `parent` which passes
* `test`.
* @example
* is(null, {type: 'strong'}); // true
*
* @example
* is('strong', {type: 'strong'}); // true
* is('emphasis', {type: 'strong'}); // false
*
* @example
* var node = {type: 'strong'};
* is(node, node) // true
* is(node, {type: 'strong'}) // false
*
* @example
* var node = {type: 'strong'};
* var parent = {type: 'paragraph', children: [node]};
* function test(node, n) {return n === 5};
* is(test, {type: 'strong'}); // false
* is(test, {type: 'strong'}, 4, parent); // false
* is(test, {type: 'strong'}, 5, parent); // true
*
* @example
* var node = {type: 'strong'};
* var parent = {type: 'paragraph', children: [node]};
* is('strong'); // throws
* is('strong', node, 0) // throws
* is('strong', node, null, parent) // throws
* is('strong', node, 0, {type: 'paragraph'}) // throws
* is('strong', node, -1, parent) // throws
* is('strong', node, Infinity, parent) // throws
*
* @param {(string|Node|is~test)?} test - Tester.
* @param {Node} node - Node to test.
* @param {number?} [index] - Position of `node` in `parent`.
* @param {Node?} [parent] - Parent of `node`.
* @param {*} [context] - Context to invoke `test` with.
* @return {boolean} - Whether `test` passes.
*/
function findBefore(parent, index, test) {
var children;
var child;

if (!parent || !parent.type || !parent.children) {
throw new Error('Expected parent node');
}

children = parent.children;

if (index && index.type) {
index = children.indexOf(index);
}

if (isNaN(index) || index < 0 || index === Infinity) {
throw new Error('Expected positive finite index or child node');
}

/* Performance. */
if (index > children.length) {
index = children.length;
}
function is(test, node, index, parent, context) {
var hasParent = parent !== null && parent !== undefined;
var hasIndex = index !== null && index !== undefined;

if (typeof test === 'string') {
test = typeFactory(test);
Expand All @@ -100,22 +181,33 @@ function findBefore(parent, index, test) {
throw new Error('Expected function, string, or node as test');
}

while (index--) {
child = children[index];
if (!node || !node.type) {
throw new Error('Expected node');
}

if (test(child, index, parent)) {
return child;
}
if (
hasIndex &&
(typeof index !== 'number' || index < 0 || index === Infinity)
) {
throw new Error('Expected positive finite index or child node');
}

return null;
if (hasParent && (!parent || !parent.type || !parent.children)) {
throw new Error('Expected parent node');
}

if (hasParent !== hasIndex) {
throw new Error('Expected both parent and index');
}

return Boolean(test.call(context, node, index, parent));
}

/*
* Expose.
*/

module.exports = findBefore;
module.exports = is;

},{}]},{},[1])(1)
});
Loading

0 comments on commit df39f22

Please sign in to comment.