From cfda2b565d8c580c19827de90d3f5aac21878c58 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Mon, 15 Apr 2024 14:24:17 -0700 Subject: [PATCH] fix(jsdoc-salty): support `left` and `right` matchers (#2103) --- packages/jsdoc-salty/README.md | 4 + packages/jsdoc-salty/lib/salty.js | 34 +++++--- packages/jsdoc-salty/test/specs/lib/salty.js | 83 ++++++++++++-------- 3 files changed, 74 insertions(+), 47 deletions(-) diff --git a/packages/jsdoc-salty/README.md b/packages/jsdoc-salty/README.md index bcd25f8c..1e3a4bc8 100644 --- a/packages/jsdoc-salty/README.md +++ b/packages/jsdoc-salty/README.md @@ -107,6 +107,10 @@ const arrayMatcher = db({ a: [1, 3] }).get(); const multiMatcher = db({ a: 1 }, { b: 'hello' }).get(); // Get array of items where `b` is undefined const undefinedMatcher = db({ b: { isUndefined: true } }).get(); +// Get array of items where `b` starts with `he` +const leftMatcher = db({ b: { left: 'he' } }).get(); +// Get array of items where `b` ends with `lo` +const rightMatcher = db({ b: { right: 'lo' } }).get(); ``` ### Get items with a custom query function diff --git a/packages/jsdoc-salty/lib/salty.js b/packages/jsdoc-salty/lib/salty.js index 89c8081b..8a2da5b6 100644 --- a/packages/jsdoc-salty/lib/salty.js +++ b/packages/jsdoc-salty/lib/salty.js @@ -21,14 +21,6 @@ if (!Object.hasOwn) { Object.hasOwn = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); } -const IS_UNDEFINED = { - isUndefined: true, -}; - -const IS_NOT_UNDEFINED = { - isUndefined: false, -}; - function addToSelection(salty, item, i) { salty._selectedItems.push(item); salty._selectedIndexes.push(i); @@ -61,6 +53,24 @@ function finderWithFunction(salty, func) { return salty; } +function applyMatcherObject(value, matcherObject) { + if (matcherObject.isUndefined === true) { + return _.isUndefined(value); + } + + if (matcherObject.isUndefined === false) { + return !_.isUndefined(value); + } + + if (matcherObject.left) { + return value && value.startsWith && value.startsWith(matcherObject.left); + } + + if (matcherObject.right) { + return value && value.endsWith && value.endsWith(matcherObject.right); + } +} + function finderWithMatcher(salty, ...args) { let item; let matches; @@ -81,14 +91,12 @@ function finderWithMatcher(salty, ...args) { item = salty._items[i]; for (const key of matcherKeys) { matcherValue = matcher[key]; - if (_.isMatch(matcherValue, IS_UNDEFINED)) { - matches = _.isUndefined(item[key]); - } else if (_.isMatch(matcherValue, IS_NOT_UNDEFINED)) { - matches = !_.isUndefined(item[key]); - } else if (Array.isArray(matcherValue)) { + if (Array.isArray(matcherValue)) { if (!matcherValue.includes(item[key])) { matches = false; } + } else if (_.isObject(matcherValue)) { + matches = applyMatcherObject(item[key], matcherValue); } else if (matcherValue !== item[key]) { matches = false; } diff --git a/packages/jsdoc-salty/test/specs/lib/salty.js b/packages/jsdoc-salty/test/specs/lib/salty.js index 65a573d0..fade1864 100644 --- a/packages/jsdoc-salty/test/specs/lib/salty.js +++ b/packages/jsdoc-salty/test/specs/lib/salty.js @@ -17,20 +17,21 @@ describe('@jsdoc/salty/lib/salty', () => { const _ = require('lodash'); const Salty = require('../../../lib/salty'); - const data = [ - { a: 2, b: undefined, c: true }, - { a: 47, b: null, c: true }, - { a: 100, b: 'hello', c: true }, - { a: 7, b: 'goodbye', c: false }, - { a: 42, b: 8, c: null }, - { a: 35, b: undefined, c: true }, - { a: 22, b: null, c: true }, - { a: 17, b: 0, c: false }, - { a: 66, c: true }, - ]; + let data; let db; beforeEach(() => { + data = [ + { a: 2, b: undefined, c: true }, + { a: 47, b: null, c: true }, + { a: 100, b: 'hello', c: true }, + { a: 7, b: 'goodbye', c: false }, + { a: 42, b: 8, c: null }, + { a: 35, b: undefined, c: true }, + { a: 22, b: null, c: true }, + { a: 17, b: 0, c: false }, + { a: 66, c: true }, + ]; db = new Salty(_.cloneDeep(data)); }); @@ -162,29 +163,6 @@ describe('@jsdoc/salty/lib/salty', () => { ]); }); - it('returns the correct items with the special matcher for undefined values', () => { - const result = db({ b: { isUndefined: true } }).get(); - - expect(result).toMatchArrayOfObjects([ - { a: 2, b: undefined, c: true }, - { a: 35, b: undefined, c: true }, - { a: 66, c: true }, - ]); - }); - - it('returns the correct items with the special matcher for defined values', () => { - const result = db({ b: { isUndefined: false } }).get(); - - expect(result).toMatchArrayOfObjects([ - { a: 47, b: null, c: true }, - { a: 100, b: 'hello', c: true }, - { a: 7, b: 'goodbye', c: false }, - { a: 42, b: 8, c: null }, - { a: 22, b: null, c: true }, - { a: 17, b: 0, c: false }, - ]); - }); - it('returns no items if the selection is empty', () => { expect(db({ a: 1000000000 }).get()).toBeEmptyArray(); }); @@ -203,6 +181,43 @@ describe('@jsdoc/salty/lib/salty', () => { { a: 66, c: true }, ]); }); + + describe('matcher objects', () => { + it('returns the correct items for `isUndefined: true`', () => { + const result = db({ b: { isUndefined: true } }).get(); + + expect(result).toMatchArrayOfObjects([ + { a: 2, b: undefined, c: true }, + { a: 35, b: undefined, c: true }, + { a: 66, c: true }, + ]); + }); + + it('returns the correct items for `isUndefined: false`', () => { + const result = db({ b: { isUndefined: false } }).get(); + + expect(result).toMatchArrayOfObjects([ + { a: 47, b: null, c: true }, + { a: 100, b: 'hello', c: true }, + { a: 7, b: 'goodbye', c: false }, + { a: 42, b: 8, c: null }, + { a: 22, b: null, c: true }, + { a: 17, b: 0, c: false }, + ]); + }); + + it('returns the correct items for `left`', () => { + const result = db({ b: { left: 'good' } }).get(); + + expect(result).toMatchArrayOfObjects([{ a: 7, b: 'goodbye', c: false }]); + }); + + it('returns the correct items for `right`', () => { + const result = db({ b: { right: 'bye' } }).get(); + + expect(result).toMatchArrayOfObjects([{ a: 7, b: 'goodbye', c: false }]); + }); + }); }); describe('remove', () => {