From 2740621867e7317408119235cbc27a759ed4e562 Mon Sep 17 00:00:00 2001 From: jden Date: Mon, 29 Apr 2013 23:41:21 -0700 Subject: [PATCH] gratuitous functional rewrite --- index.js | 86 ++++++++++++++++++---------------------------- package.json | 7 +++- test/test.match.js | 7 ++-- 3 files changed, 44 insertions(+), 56 deletions(-) diff --git a/index.js b/index.js index 9d1521d..169261e 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ +var funderscore = require('funderscore') // type Match: { // path: Array, // key: String, @@ -6,70 +7,51 @@ // } // (selectors: String|Array, obj: Object) => Array -// or -// (selectors: String|Array) => (obj: Object) => Array -var match = function (selectors, obj) { - +// or (selectors: String|Array) => (obj: Object) => Array +module.exports = function match (selectors, obj) { selectors = [].concat(selectors).map(function (selector) { return selector.split('.') }) - var fn = function (document) { - - var matches = [] - var pathSeg - var seg = document - var stack = [{path: [], value: document, depth: -1}] - var node - - // breadth-first search - while(node = stack.pop()) { - - // full selector match - if(selectors.some(exactMatch(node))) { - - // in ES6, I would so yield. - matches.push({ - path: node.path, - value: node.value, - parent: node.parent, - key: node.path[node.path.length - 1]}) - continue - } - - // first node or partial match - if(node.depth === -1 || selectors.some(partialMatch(node))) { - - for(var child in node.value) { - stack.push({ - path: node.path.concat(child), - value: node.value[child], - parent: node.value, - depth: node.depth + 1 - }) - } - } - - } - return matches - } - - return obj ? fn(obj) : fn + return obj ? findMatches(obj, selectors) + : function (obj) { return findMatches(obj, selectors) } } -function exactMatch(node) { - var len = node.path.length +function exactMatch(path) { return function (selector) { - return len === selector.length && node.path.every(function (segment, i) { + return path.length === selector.length && path.every(function (segment, i) { return selector[i] === '*' || selector[i] === segment }) } } -function partialMatch(node) { - var i = node.depth +function partialMatch(path) { + var i = path.length - 1 return function (selector) { - return selector[i] === '*' || selector[i] === node.path[node.depth] + return selector[i] === '*' || selector[i] === path[i] } } -module.exports = match \ No newline at end of file + +function findMatches(obj, selectors, path, parent) { + if (path === void 0) { path = [] } + + // full selector match + if(selectors.some(exactMatch(path))) { + return { + path: path, + value: obj, + parent: parent, + key: path[path.length - 1] + } + } + + // first node or partial match + if(!parent || selectors.some(partialMatch(path))) { + return funderscore.flatMap(obj, function (val, key) { + return findMatches(val, selectors, path.concat(key), obj) + }) + } + + // default + return [] +} \ No newline at end of file diff --git a/package.json b/package.json index 3341681..b4618e2 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,17 @@ "match", "pattern" ], - "contributors": ["jden "], + "contributors": [ + "jden " + ], "author": "Agile Diagnosis ", "license": "MIT", "readmeFilename": "README.md", "devDependencies": { "chai": "~1.6.0", "mocha": "~1.9.0" + }, + "dependencies": { + "funderscore": "~0.2.0" } } diff --git a/test/test.match.js b/test/test.match.js index 97054f4..c4c3069 100644 --- a/test/test.match.js +++ b/test/test.match.js @@ -92,7 +92,7 @@ describe('match', function () { {path: ['animals','owl','size'], value: 2, parent: {size: 2}, key: 'size'}, {path: ['animals','blue whale','size'], value: 80, parent: {size: 80}, key: 'size'}, {path: ['animals','megalodon','size'], value: 100, parent: {size: 100}, key: 'size'} - ].reverse(/* order doesnt actually matter */)) + ]) }) it('works on arrays', function () { @@ -103,8 +103,9 @@ describe('match', function () { m.should.deep.equal([ { path: [ 'a', '2', 'c' ], value: 3, parent: {c: 3}, key: 'c' }, { path: [ 'a', '1', 'c' ], value: 2, parent: {c: 2}, key: 'c' }, - { path: [ 'a', '0', 'c' ], value: 1, parent: {c: 1}, key: 'c' } ]) - }) + { path: [ 'a', '0', 'c' ], value: 1, parent: {c: 1}, key: 'c' } + ].reverse()) + }) it('works with multiple wildcards', function () { var m = match('a.*.c.*')({