diff --git a/src/jsonData.js b/src/jsonData.js index 691c5b6..27072b8 100644 --- a/src/jsonData.js +++ b/src/jsonData.js @@ -542,6 +542,54 @@ export function search (data, text): SearchResult[] { return results } +/** + * Find the next search result given a current search result + * - When the current search result is the last one, the search will wrap around + * and return the first result as next. + * - When current search result is not found, the first search result will be + * returned as next + * - When `searchResults` is empty, null will be returned + */ +export function nextSearchResult (searchResults: SearchResult[], current: SearchResult): SearchResult | null { + if (searchResults.length === 0) { + return null + } + + const index = searchResults.findIndex(searchResult => isEqual(searchResult, current)) + if (index !== -1) { + return index < searchResults.length - 1 + ? searchResults[index + 1] + : searchResults[0] + } + else { + return searchResults[0] + } +} + +/** + * Find the previous search result given a current search result + * - When the current search result is the first one, the search will wrap around + * and return the last result as next. + * - When current search result is not found, the last search result will be + * returned as next + * - When `searchResults` is empty, null will be returned + */ +export function previousSearchResult (searchResults: SearchResult[], current: SearchResult): SearchResult | null { + if (searchResults.length === 0) { + return null + } + + const index = searchResults.findIndex(searchResult => isEqual(searchResult, current)) + if (index !== -1) { + return index > 0 + ? searchResults[index - 1] + : last(searchResults) + } + else { + return searchResults[0] + } +} + /** * Merge searchResults into the data */ diff --git a/test/jsonData.test.js b/test/jsonData.test.js index 3b51cf8..8aa3c6b 100644 --- a/test/jsonData.test.js +++ b/test/jsonData.test.js @@ -2,7 +2,7 @@ import test from 'ava'; import { jsonToData, dataToJson, patchData, pathExists, transform, traverse, parseJSONPointer, compileJSONPointer, - expand, addErrors, search, addSearchResults + expand, addErrors, search, addSearchResults, nextSearchResult, previousSearchResult } from '../src/jsonData' @@ -939,3 +939,59 @@ test('search', t => { t.deepEqual(updatedData, JSON_DATA_EXAMPLE_SEARCH_L) }) + +test('nextSearchResult', t => { + const searchResults = [ + {dataPath: ['obj', 'arr', '2', 'last'], type: 'property'}, + {dataPath: ['str'], type: 'value'}, + {dataPath: ['nill'], type: 'property'}, + {dataPath: ['nill'], type: 'value'}, + {dataPath: ['bool'], type: 'property'}, + {dataPath: ['bool'], type: 'value'} + ] + + t.deepEqual(nextSearchResult(searchResults, + {dataPath: ['nill'], type: 'property'}), + {dataPath: ['nill'], type: 'value'}) + + // wrap around + t.deepEqual(nextSearchResult(searchResults, + {dataPath: ['bool'], type: 'value'}), + {dataPath: ['obj', 'arr', '2', 'last'], type: 'property'}) + + // return first when current is not found + t.deepEqual(nextSearchResult(searchResults, + {dataPath: ['non', 'existing'], type: 'value'}), + {dataPath: ['obj', 'arr', '2', 'last'], type: 'property'}) + + // return null when searchResults are empty + t.deepEqual(nextSearchResult([], {dataPath: ['non', 'existing'], type: 'value'}), null) +}) + +test('previousSearchResult', t => { + const searchResults = [ + {dataPath: ['obj', 'arr', '2', 'last'], type: 'property'}, + {dataPath: ['str'], type: 'value'}, + {dataPath: ['nill'], type: 'property'}, + {dataPath: ['nill'], type: 'value'}, + {dataPath: ['bool'], type: 'property'}, + {dataPath: ['bool'], type: 'value'} + ] + + t.deepEqual(previousSearchResult(searchResults, + {dataPath: ['nill'], type: 'property'}), + {dataPath: ['str'], type: 'value'}) + + // wrap around + t.deepEqual(previousSearchResult(searchResults, + {dataPath: ['obj', 'arr', '2', 'last'], type: 'property'}), + {dataPath: ['bool'], type: 'value'}) + + // return first when current is not found + t.deepEqual(previousSearchResult(searchResults, + {dataPath: ['non', 'existing'], type: 'value'}), + {dataPath: ['obj', 'arr', '2', 'last'], type: 'property'}) + + // return null when searchResults are empty + t.deepEqual(previousSearchResult([], {dataPath: ['non', 'existing'], type: 'value'}), null) +})