Comparing version
@@ -0,1 +1,17 @@ | ||
## 1.3.0 - 2020-12-07 | ||
### Features | ||
- add curried (data last) versions of `get` and `getter` via `get-wild/fp` | ||
- add `exports.parse` as an alias for `exports.parser` | ||
### Fixes | ||
- fix a bug which caused custom `collect`, `map` and `flatMap` settings to be | ||
forgotten after the first wildcard match | ||
### Changes | ||
- types: narrow `get`'s return type from `any` to `unknown` | ||
## 1.2.0 - 2020-09-19 | ||
@@ -2,0 +18,0 @@ |
@@ -31,3 +31,6 @@ // @ts-ignore | ||
} = Array; | ||
const $Object = Object; | ||
const { | ||
defineProperty, | ||
values: defaultCollect | ||
} = Object; | ||
const $Symbol = Symbol; | ||
@@ -38,3 +41,3 @@ const NO_MAP = $Symbol(); | ||
const { | ||
collect = $Object.values, | ||
collect = defaultCollect, | ||
default: $$default, | ||
@@ -48,4 +51,7 @@ flatMap: $flatMap = '*', | ||
const map = $map === false ? NO_MAP : $map; | ||
const parse = typeof split === 'string' ? path => path.split(split) : split; | ||
return (obj, path, $default = $$default) => { | ||
const parse = typeof split === 'string' ? path => path.split(split) : split; // XXX the name is important; if omitted, `get` refers to the default `get` | ||
// export defined at the bottom of the file rather than this `get`, which | ||
// may have different options | ||
function get(obj, path, ...rest) { | ||
let props; | ||
@@ -72,2 +78,3 @@ | ||
const $default = rest.length ? rest[0] : $$default; | ||
const lastIndex = props.length - 1; | ||
@@ -115,6 +122,13 @@ | ||
return obj === undefined ? $default : obj; | ||
}; | ||
} // expose the selected/generated parser as a (read-only) property on the | ||
// function. this is for the currying wrapper and isn't exposed by the | ||
// curried functions | ||
return defineProperty(get, 'parse', { | ||
value: parse | ||
}); | ||
}; | ||
const get = getter(); | ||
export { get, getter, parser, parser as split }; | ||
export { get, getter, parser as parse, parser, parser as split }; |
@@ -35,3 +35,6 @@ 'use strict'; | ||
} = Array; | ||
const $Object = Object; | ||
const { | ||
defineProperty, | ||
values: defaultCollect | ||
} = Object; | ||
const $Symbol = Symbol; | ||
@@ -42,3 +45,3 @@ const NO_MAP = $Symbol(); | ||
const { | ||
collect = $Object.values, | ||
collect = defaultCollect, | ||
default: $$default, | ||
@@ -52,4 +55,7 @@ flatMap: $flatMap = '*', | ||
const map = $map === false ? NO_MAP : $map; | ||
const parse = typeof split === 'string' ? path => path.split(split) : split; | ||
return (obj, path, $default = $$default) => { | ||
const parse = typeof split === 'string' ? path => path.split(split) : split; // XXX the name is important; if omitted, `get` refers to the default `get` | ||
// export defined at the bottom of the file rather than this `get`, which | ||
// may have different options | ||
function get(obj, path, ...rest) { | ||
let props; | ||
@@ -76,2 +82,3 @@ | ||
const $default = rest.length ? rest[0] : $$default; | ||
const lastIndex = props.length - 1; | ||
@@ -119,3 +126,10 @@ | ||
return obj === undefined ? $default : obj; | ||
}; | ||
} // expose the selected/generated parser as a (read-only) property on the | ||
// function. this is for the currying wrapper and isn't exposed by the | ||
// curried functions | ||
return defineProperty(get, 'parse', { | ||
value: parse | ||
}); | ||
}; | ||
@@ -126,3 +140,4 @@ const get = getter(); | ||
exports.getter = getter; | ||
exports.parse = parser; | ||
exports.parser = parser; | ||
exports.split = parser; |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).GetWild={})}(this,(function(e){"use strict";const t=/(?:(?:\[(?:(?:(["'])((?:\\.|(?:(?!\1).))*)\1)|([-+]?\d+))\])|(?:\[(.?))|(?:(?:^|(?:(?!^)\.))([^\s"'\`\[\].\\]+))|(.))/g,r=/\\(.)/g,n=e=>{const n=[];return e.replace(t,(t,s,i,o,l,a,f,p)=>{let c;if(s)c=i.replace(r,(...e)=>e[1]===s?s:e[0]);else if(o)c=+o;else{if(!a)throw new SyntaxError(`Invalid step @ ${p}: ${JSON.stringify(e)}`);c=a}return n.push(c),""}),n},{isArray:s}=Array,i=Object,o=Symbol,l=o(),a=o(),f=(e={})=>{const{collect:t=i.values,default:r,flatMap:o="*",map:f="**",parser:c=n,split:u=c}=e,d=!1===o?a:o,y=!1===f?l:f,b="string"==typeof u?e=>e.split(u):u;return(e,n,i=r)=>{let o;switch(typeof n){case"string":o=b(n);break;case"number":case"symbol":o=[n];break;default:if(!s(n))throw new TypeError("Invalid path: expected a string, array, number, or symbol");o=n}const l=o.length-1;for(let r=0;r<=l;++r){if(!e)return i;const n=o[r];if(n===d||n===y){const a=s(e)?e:t(e);if(r===l)return n===d?a.flat():a;const f=o.slice(r+1);return n===d?a.flatMap(e=>p(e,f,i)):a.map(e=>p(e,f,i))}e=s(e)&&Number.isInteger(n)&&n<0?e[e.length+n]:e[n]}return void 0===e?i:e}},p=f();e.get=p,e.getter=f,e.parser=n,e.split=n,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).GetWild={})}(this,(function(e){"use strict";const t=/(?:(?:\[(?:(?:(["'])((?:\\.|(?:(?!\1).))*)\1)|([-+]?\d+))\])|(?:\[(.?))|(?:(?:^|(?:(?!^)\.))([^\s"'\`\[\].\\]+))|(.))/g,r=/\\(.)/g,n=e=>{const n=[];return e.replace(t,(t,s,i,o,l,a,f,p)=>{let c;if(s)c=i.replace(r,(...e)=>e[1]===s?s:e[0]);else if(o)c=+o;else{if(!a)throw new SyntaxError(`Invalid step @ ${p}: ${JSON.stringify(e)}`);c=a}return n.push(c),""}),n},{isArray:s}=Array,{defineProperty:i,values:o}=Object,l=Symbol,a=l(),f=l(),p=(e={})=>{const{collect:t=o,default:r,flatMap:l="*",map:p="**",parser:c=n,split:u=c}=e,d=!1===l?f:l,y=!1===p?a:p,g="string"==typeof u?e=>e.split(u):u;return i((function e(n,i,...o){let l;switch(typeof i){case"string":l=g(i);break;case"number":case"symbol":l=[i];break;default:if(!s(i))throw new TypeError("Invalid path: expected a string, array, number, or symbol");l=i}const a=o.length?o[0]:r,f=l.length-1;for(let r=0;r<=f;++r){if(!n)return a;const i=l[r];if(i===d||i===y){const o=s(n)?n:t(n);if(r===f)return i===d?o.flat():o;const p=l.slice(r+1);return i===d?o.flatMap(t=>e(t,p,a)):o.map(t=>e(t,p,a))}n=s(n)&&Number.isInteger(i)&&i<0?n[n.length+i]:n[i]}return void 0===n?a:n}),"parse",{value:g})},c=p();e.get=c,e.getter=p,e.parse=n,e.parser=n,e.split=n,Object.defineProperty(e,"__esModule",{value:!0})})); |
@@ -7,10 +7,11 @@ declare type Options = { | ||
parser?: Options['split']; | ||
split?: string | ((path: string) => Array<PropertyKey>); | ||
split?: string | Parser; | ||
}; | ||
declare type Parser = (path: string) => Array<PropertyKey>; | ||
declare type Path = PropertyKey | Array<PropertyKey>; | ||
declare const getter: (options?: Options) => (obj: any, path: Path, $default?: any) => any; | ||
declare const get: (obj: any, path: Path, $default?: any) => any; | ||
declare const getter: (options?: Options) => (obj: any, path: Path, ...rest: [] | [any]) => unknown; | ||
declare const get: (obj: any, path: Path, ...rest: [] | [any]) => unknown; | ||
declare const parser: (path: string) => (string | number)[]; | ||
export { Options, Path, get, getter, parser, parser as split }; | ||
export { Options, Parser, Path, get, getter, parser as parse, parser, parser as split }; |
{ | ||
"name": "get-wild", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "Pluck nested properties from an object with support for wildcards", | ||
@@ -14,16 +14,17 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"build": "bili --map --format cjs -d dist src/index.ts", | ||
"build:default": "cross-env NODE_ENV=production bili --no-map --format cjs,esm -d dist src/index.ts", | ||
"build:doc": "toc-md --max-depth 3 README.md", | ||
"build": "bili --map --format cjs -d dist src/index.ts src/fp.ts", | ||
"build:default": "cross-env NODE_ENV=production bili --no-map --format cjs,esm -d dist src/index.ts src/fp.ts", | ||
"build:doc": "toc-md README.md", | ||
"build:dts": "rollup -c resources/rollup.config.js", | ||
"build:min": "cross-env NODE_ENV=production bili --no-map --format esm-min -d dist src/index.ts", | ||
"build:min": "cross-env NODE_ENV=production bili --no-map --format esm-min -d dist src/index.ts src/fp.ts", | ||
"build:release": "run-s typecheck build:default build:umd build:dts build:doc", | ||
"build:umd": "cross-env NODE_ENV=production bili --no-map --module-name GetWild --format umd-min -d dist src/index.ts", | ||
"build:umd": "cross-env NODE_ENV=production bili --no-map --module-name GetWild --format umd,umd-min -d dist src/index.ts src/fp.ts", | ||
"clean": "shx rm -rf dist .nyc_output", | ||
"coverage": "run-s build nyc", | ||
"nyc": "nyc ava --verbose \"./test/**/*.js\"", | ||
"prepublishOnly": "run-s clean build:release nyc", | ||
"coverage": "nyc ava --verbose \"./test/**/*.js\"", | ||
"postpack": "shx rm -f ./fp*.js", | ||
"prepack": "shx cp ./dist/fp*.js .", | ||
"prepublishOnly": "run-s clean build:release test:run", | ||
"rebuild": "run-s clean build", | ||
"repl": "node -r ./resources/repl.js", | ||
"test": "run-s typecheck build test:run", | ||
"test": "run-s clean typecheck build coverage", | ||
"test:run": "ava --verbose \"./test/**/*.js\"", | ||
@@ -35,3 +36,9 @@ "typecheck": "tsc --noEmit --noImplicitAny --noUnusedLocals --noUnusedParameters --strict" | ||
"dist/index.js", | ||
"dist/index.umd.js", | ||
"dist/index.umd.min.js", | ||
"/fp.d.ts", | ||
"/fp.esm.js", | ||
"/fp.js", | ||
"/fp.umd.js", | ||
"/fp.umd.min.js", | ||
"/index.d.ts" | ||
@@ -41,17 +48,17 @@ ], | ||
"devDependencies": { | ||
"@babel/core": "^7.11.6", | ||
"@babel/core": "^7.12.9", | ||
"array-flat-polyfill": "^1.0.1", | ||
"ava": "^3.12.1", | ||
"ava": "^3.14.0", | ||
"babel-plugin-codegen": "^4.0.1", | ||
"babel-plugin-source-map-support": "^2.1.3", | ||
"bili": "^5.0.5", | ||
"cross-env": "^7.0.2", | ||
"cross-env": "^7.0.3", | ||
"npm-run-all": "^4.1.5", | ||
"nyc": "^15.1.0", | ||
"rollup": "^2.27.1", | ||
"rollup-plugin-dts": "^1.4.13", | ||
"rollup-plugin-typescript2": "^0.27.2", | ||
"shx": "^0.3.2", | ||
"toc-md-alt": "^0.4.0", | ||
"typescript": "^4.0.3" | ||
"rollup": "^2.34.2", | ||
"rollup-plugin-dts": "^2.0.0", | ||
"rollup-plugin-typescript2": "^0.29.0", | ||
"shx": "^0.3.3", | ||
"toc-md-alt": "^0.4.1", | ||
"typescript": "^4.1.2" | ||
}, | ||
@@ -58,0 +65,0 @@ "keywords": [ |
122
README.md
# get-wild | ||
[](https://travis-ci.org/chocolateboy/get-wild) | ||
[](https://github.com/chocolateboy/get-wild/actions?query=workflow%3Atest) | ||
[](https://www.npmjs.org/package/get-wild) | ||
@@ -47,3 +47,4 @@ | ||
- no dependencies | ||
- < 700 B minified + gzipped | ||
- ~700 B minified + gzipped | ||
- curried (data last) versions for functional programming | ||
- fully typed (TypeScript) | ||
@@ -115,3 +116,2 @@ - CDN builds (UMD) - [jsDelivr][], [unpkg][] | ||
get(array, '[-1].*.value') // [7, 8, 9] | ||
``` | ||
@@ -155,7 +155,9 @@ | ||
builder function ([`getter`](#getter)) which can be used to create a custom | ||
`get` with different [options](#options) baked in. | ||
`get` with different [options](#options) baked in, as well as curried | ||
(data last) versions of [`get`](#get-fp) and [`getter`](#getter-fp) to | ||
facilitate functional composition and reuse. | ||
## Why? | ||
I needed a small, dependency-free version of `Lodash.get` with wildcard | ||
I needed a small, dependency-free version of [`Lodash.get`][Lodash.get] with wildcard | ||
support, and preferably with an option to filter out/exclude missing values. | ||
@@ -170,3 +172,3 @@ Although there are a huge number of `get` implementations on NPM, I could only | ||
[options](#options), there are smaller implementations, e.g. | ||
[just-safe-get](https://www.npmjs.com/package/just-safe-get). | ||
[dlv][]. | ||
@@ -179,3 +181,3 @@ # TYPES | ||
type Options = { | ||
collect?: (value: {}) ⇒ Array<any>; | ||
collect?: (value: {}) => Array<any>; | ||
default?: any; | ||
@@ -185,5 +187,6 @@ flatMap?: PropertyKey | false; | ||
parser?: Options['split']; | ||
split?: string | ((path: string) => Array<PropertyKey>); | ||
split?: string | Parser; | ||
}; | ||
type Parser = (path: string) => Array<PropertyKey>; | ||
type Path = PropertyKey | Array<PropertyKey>; | ||
@@ -196,10 +199,23 @@ ``` | ||
- **Type**: `(obj: any, path: Path, $default?: any) ⇒ any` | ||
- **Type**: `(obj: any, path: Path, $default?: any) => unknown` | ||
```javascript | ||
import { get } from 'get-wild' | ||
```javascript | ||
import { get } from 'get-wild' | ||
get(obj, 'foo.*.bar', []) | ||
``` | ||
get(obj, 'foo.*.bar', []) | ||
``` | ||
<a name="get-fp"></a> | ||
- **Type**: `(path: Path, $default?: any) => (obj: any) => unknown` | ||
```javascript | ||
import { get } from 'get-wild/fp' | ||
const followers = get('users.*.followers.*.name', []) | ||
users.map(followers) // equivalent to users.map(user => get(user, path, [])) | ||
users.map(followers, '<anon>') // override the default value | ||
``` | ||
`get` takes an object, a path and an optional default value, and returns the | ||
@@ -211,3 +227,7 @@ value(s) found in the object at the specified path, or the default value (which | ||
The [syntax](#path-syntax) for dotted path expressions mostly matches that of | ||
A curried version is available via `get-wild/fp`. It takes a path and optional | ||
default value and returns a function which takes the object and returns the | ||
value(s) located at the path. | ||
The [syntax](#path-syntax) of dotted path expressions mostly matches that of | ||
regular JavaScript path expressions, with a few additions. | ||
@@ -235,14 +255,28 @@ | ||
- **Type**: `(options?: Options) ⇒ typeof get` | ||
- **Type**: `(options?: Options) => typeof get` | ||
```javascript | ||
import { getter } from 'get-wild' | ||
```javascript | ||
import { getter } from 'get-wild' | ||
const split = path => path.split('.') | ||
const get = getter({ split }) | ||
const obj = { '': { '': 42 } } | ||
const split = path => path.split('.') | ||
const get = getter({ split }) | ||
const obj = { '': { '': 42 } } | ||
get(obj, '.') // 42 | ||
``` | ||
get(obj, '.') // 42 | ||
``` | ||
<a name="getter-fp"></a> | ||
- **Type**: `(path: Path, $default?: any) => (obj: any) => unknown` | ||
```javascript | ||
import { getter } from 'get-wild/fp' | ||
const get = getter({ default: [], split: '.' }) | ||
const followers = get('users.*.followers.*.name') | ||
users.map(followers) // equivalent to users.map(user => get(user, path, [])) | ||
users.map(followers, '<anon>') // override the default value | ||
``` | ||
`getter` is a function which is used to build `get` functions. The default | ||
@@ -274,6 +308,10 @@ `get` export is generated by calling `getter` with no arguments, which uses the | ||
The version available via `get-wild/fp` takes an optional [Options](#options) | ||
object and returns a [curried version of `get`](#get-fp) with the options baked | ||
in. | ||
## split | ||
- **Type**: `(path: string) ⇒ Array<PropertyKey>` | ||
- **Alias**: parser | ||
- **Type**: `Parser` | ||
- **Aliases**: parse, parser | ||
@@ -293,4 +331,6 @@ ```javascript | ||
The array is not mutated, so, e.g., the function can be memoized (or the path | ||
can pre-parsed) to avoid re-parsing long/frequently-used paths. | ||
The array is not mutated, so, e.g., the function can be memoized to avoid | ||
re-parsing long/frequently-used paths. Alternatively, the path can be | ||
pre-parsed into an array (this is done automatically if the curried versions | ||
are used). | ||
@@ -327,3 +367,3 @@ <!-- TOC:ignore --> | ||
- **Type**: `(value: {}) ⇒ Array<any>` | ||
- **Type**: `(value: {}) => Array<any>` | ||
- **Default**: `Object.values` | ||
@@ -335,7 +375,5 @@ | ||
const collect = value => { | ||
if (value instanceof Map || value instanceof Set) { | ||
return Array.from(value.values()) | ||
} else { | ||
return Object.values(value) | ||
} | ||
return (value instanceof Map || value instanceof Set) | ||
? Array.from(value.values()) | ||
: Object.values(value) | ||
} | ||
@@ -360,3 +398,3 @@ | ||
[`Object.values`][Object.values], which works with objects, arrays, and other | ||
non-nullish values. Can be overridden to add support for traversable values | ||
non-nullish values. It can be overridden to add support for traversable values | ||
that aren't plain objects, e.g. ES6 Map and Set instances. | ||
@@ -457,4 +495,3 @@ | ||
```javascript | ||
const split = path => path.split('.') | ||
const get = getter({ flatMap: '[]', split }) | ||
const get = getter({ flatMap: '[]', split: '.' }) | ||
@@ -489,3 +526,3 @@ get(obj, 'foo.[].bar') // [1, 2] | ||
- **Type**: `string | ((path: string) ⇒ Array<PropertyKey>)` | ||
- **Type**: `string | Parser` | ||
- **Alias**: parser | ||
@@ -545,3 +582,3 @@ | ||
[`Array#flat`][flat]/[`Array#flatMap`][flatMap] | ||
([polyfill](https://www.npmjs.com/package/array-flat-polyfill)) | ||
([polyfill][]) | ||
@@ -551,4 +588,2 @@ # SEE ALSO | ||
- [dot-wild-tiny](https://www.npmjs.com/package/dot-wild-tiny) | ||
- [just-safe-get](https://www.npmjs.com/package/just-safe-get) | ||
- [lodash.get](https://www.npmjs.com/package/lodash.get) | ||
- [object-path-wild](https://www.npmjs.com/package/object-path-wild) | ||
@@ -559,3 +594,3 @@ - [@gizt/selector](https://www.npmjs.com/package/@gizt/selector) | ||
1.2.0 | ||
1.3.0 | ||
@@ -573,8 +608,11 @@ # AUTHOR | ||
[dlv]: https://www.npmjs.com/package/dlv | ||
[flat]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat | ||
[flatMap]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap | ||
[globs]: https://en.wikipedia.org/wiki/Glob_(programming) | ||
[jsDelivr]: https://cdn.jsdelivr.net/npm/get-wild@1.2.0/dist/index.umd.min.js | ||
[jsDelivr]: https://cdn.jsdelivr.net/npm/get-wild | ||
[Lodash.get]: https://www.npmjs.com/package/lodash.get | ||
[map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map | ||
[Object.values]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values | ||
[unpkg]: https://unpkg.com/get-wild@1.2.0/dist/index.umd.min.js | ||
[polyfill]: https://www.npmjs.com/package/array-flat-polyfill | ||
[unpkg]: https://unpkg.com/get-wild |
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
60242
64.38%14
75%773
254.59%599
6.77%1
Infinity%