normal-store 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ ISC License
2
+
3
+ Copyright 2021 Voiceflow Inc.
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,59 @@
1
+ Normal Store
2
+ =========================
3
+
4
+ [![npm version](https://img.shields.io/npm/v/normal-store.svg?style=flat-square)](https://www.npmjs.com/package/normal-store)
5
+ [![npm downloads](https://img.shields.io/npm/dm/normal-store.svg?style=flat-square)](https://www.npmjs.com/package/normal-store)
6
+
7
+ Utilities to transform data with unique identifiers to and from a normalized data store.
8
+ All data is treated as immutable, new data structures are returned when updating.
9
+
10
+ ## Why?
11
+
12
+ Often when dealing with data in a single-page-application (SPA) it is useful to represent collections of resources in a way that is both easy to query and to update.
13
+
14
+ With `normal-store` you can convert the resources served by your backend into a format similar to an indexed database.
15
+
16
+ ```ts
17
+ const resources = [{ id: 'a' }, { id: 'b' }];
18
+
19
+ const normalized = normalize(resources); // { allKeys: ['a', 'b'], byKey: { a: { id: 'a' }, b: { id: 'b' } }}
20
+
21
+ const denormalized = denormalize(normalized); // [{ id: 'a' }, { id: 'b' }]
22
+ ```
23
+
24
+ ## Example
25
+
26
+ ```ts
27
+ import axios from 'axios';
28
+ import { normalize, getOne, patchOne, removeOne } from 'normal-store';
29
+
30
+ const products = await axios.get('/products').then(res => res.data);
31
+
32
+ let productStore = normalize(products);
33
+
34
+ const decrementStock = (productID) => {
35
+ productStore = patchOne(productStore, productID, ({ stock }) => ({ stock: stock - 1 }));
36
+ };
37
+
38
+ const removeProduct = (productID) => {
39
+ productStore = removeOne(productStore, productID);
40
+ };
41
+ ```
42
+
43
+ ## Installation
44
+
45
+ To use `normal-store`, install it as a dependency:
46
+
47
+ ```bash
48
+ # If you use npm:
49
+ npm install normal-store
50
+
51
+ # Or if you use Yarn:
52
+ yarn add normal-store
53
+ ```
54
+
55
+ This assumes that you’re using a package manager such as [npm](http://npmjs.com/).
56
+
57
+ ## License
58
+
59
+ [ISC](LICENSE.md)
@@ -0,0 +1,2 @@
1
+ export * from './store';
2
+ export * from './types';
package/build/index.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./store"), exports);
14
+ __exportStar(require("./types"), exports);
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0CAAwB;AACxB,0CAAwB"}
@@ -0,0 +1,7 @@
1
+ import { Normalized, NormalizedValue } from "../types";
2
+ export interface AddOne {
3
+ <T>(store: Normalized<T>, key: string, value: T): T | null;
4
+ <T extends Normalized<any>>(store: T, key: string, value: NormalizedValue<T>): T;
5
+ }
6
+ export declare const prependOne: AddOne;
7
+ export declare const appendOne: AddOne;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendOne = exports.prependOne = void 0;
4
+ const utils_1 = require("../utils");
5
+ const update_1 = require("./update");
6
+ const prependOne = (normalized, key, value) => (Object.assign(Object.assign({}, (0, update_1.updateOne)(normalized, key, value)), { allKeys: (0, utils_1.prependUnique)(normalized.allKeys, key) }));
7
+ exports.prependOne = prependOne;
8
+ const appendOne = (normalized, key, value) => (Object.assign(Object.assign({}, (0, update_1.updateOne)(normalized, key, value)), { allKeys: (0, utils_1.appendUnique)(normalized.allKeys, key) }));
9
+ exports.appendOne = appendOne;
10
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/store/add.ts"],"names":[],"mappings":";;;AACA,oCAAsD;AAEtD,qCAAqC;AAO9B,MAAM,UAAU,GAAW,CAA0B,UAAa,EAAE,GAAW,EAAE,KAAyB,EAAK,EAAE,CAAC,iCACpH,IAAA,kBAAS,EAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,KACpC,OAAO,EAAE,IAAA,qBAAa,EAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,IAC/C,CAAC;AAHU,QAAA,UAAU,cAGpB;AAEI,MAAM,SAAS,GAAW,CAA0B,UAAa,EAAE,GAAW,EAAE,KAAyB,EAAK,EAAE,CAAC,iCACnH,IAAA,kBAAS,EAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,KACpC,OAAO,EAAE,IAAA,oBAAY,EAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,IAC9C,CAAC;AAHU,QAAA,SAAS,aAGnB"}
@@ -0,0 +1,9 @@
1
+ import { GetKey, Identifiable, Normalized } from "../types";
2
+ export interface AddMany {
3
+ <T extends Identifiable>(store: Normalized<T>, values: T[]): T[];
4
+ <T>(store: Normalized<T>, values: T[], getKey: GetKey<T>): T[];
5
+ <T extends Normalized<Identifiable>>(store: T, values: T[]): T;
6
+ <T extends Normalized<any>>(store: T, values: T[], getKey: GetKey<T>): T;
7
+ }
8
+ export declare const prependMany: AddMany;
9
+ export declare const appendMany: AddMany;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendMany = exports.prependMany = void 0;
4
+ const utils_1 = require("../utils");
5
+ const addMany = (store, values, mergeKeys, getKey) => {
6
+ const keyGetter = getKey !== null && getKey !== void 0 ? getKey : utils_1.defaultGetKey;
7
+ const newKeys = (0, utils_1.withoutValues)(values.map(keyGetter), store.allKeys);
8
+ return Object.assign(Object.assign({}, store), { byKey: Object.assign(Object.assign({}, store.byKey), Object.fromEntries(values.map((value, index, allValues) => [keyGetter(value, index, allValues), value]))), allKeys: mergeKeys(store.allKeys, newKeys) });
9
+ };
10
+ const prependMany = (store, values, getKey) => addMany(store, values, (allKeys, newKeys) => [...newKeys, ...allKeys], getKey);
11
+ exports.prependMany = prependMany;
12
+ const appendMany = (store, values, getKey) => addMany(store, values, (allKeys, newKeys) => [...allKeys, ...newKeys], getKey);
13
+ exports.appendMany = appendMany;
14
+ //# sourceMappingURL=addMany.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addMany.js","sourceRoot":"","sources":["../../src/store/addMany.ts"],"names":[],"mappings":";;;AACA,oCAAuD;AASvD,MAAM,OAAO,GAAG,CACd,KAAQ,EACR,MAAW,EACX,SAA6D,EAC7D,MAAU,EACP,EAAE;IACL,MAAM,SAAS,GAAG,MAAM,aAAN,MAAM,cAAN,MAAM,GAAK,qBAA8B,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAA,qBAAa,EAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAEpE,uCACK,KAAK,KACR,KAAK,kCACA,KAAK,CAAC,KAAK,GACX,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,GAE7G,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,IAC1C;AACJ,CAAC,CAAC;AAEK,MAAM,WAAW,GAAY,CAA4B,KAAQ,EAAE,MAA4B,EAAE,MAAmC,EAAE,EAAE,CAC7I,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;AADpE,QAAA,WAAW,eACyD;AAE1E,MAAM,UAAU,GAAY,CAA4B,KAAQ,EAAE,MAA4B,EAAE,MAAmC,EAAE,EAAE,CAC5I,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;AADpE,QAAA,UAAU,cAC0D"}
@@ -0,0 +1,13 @@
1
+ import { Normalized } from "../types";
2
+ export interface GetOne {
3
+ <T>(store: Normalized<T>, key: string): T | null;
4
+ <T extends Normalized<any>>(store: T, key: string): T extends Normalized<infer R> ? R | null : never;
5
+ }
6
+ export interface GetMany {
7
+ <T>(store: Normalized<T>, keys: string[]): T[];
8
+ <T extends Normalized<any>>(store: T, keys: string[]): T extends Normalized<infer R> ? R[] : never;
9
+ }
10
+ export declare type Get = GetOne & GetMany;
11
+ export declare const getMany: GetMany;
12
+ export declare const getOne: GetOne;
13
+ export declare const get: Get;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.get = exports.getOne = exports.getMany = void 0;
4
+ const has_1 = require("./has");
5
+ const getMany = ({ allKeys, byKey }, keys) => keys.filter((key) => allKeys.includes(key)).map((key) => byKey[key]);
6
+ exports.getMany = getMany;
7
+ const getOne = (store, key) => ((0, has_1.hasOne)(store, key) ? store.byKey[key] : null);
8
+ exports.getOne = getOne;
9
+ const get = (store, keys) => (Array.isArray(keys) ? (0, exports.getMany)(store, keys) : (0, exports.getOne)(store, keys));
10
+ exports.get = get;
11
+ //# sourceMappingURL=get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get.js","sourceRoot":"","sources":["../../src/store/get.ts"],"names":[],"mappings":";;;AAEA,+BAA+B;AAcxB,MAAM,OAAO,GAAY,CAAC,EAAE,OAAO,EAAE,KAAK,EAAmB,EAAE,IAAc,EAAE,EAAE,CACtF,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAD1D,QAAA,OAAO,WACmD;AAEhE,MAAM,MAAM,GAAW,CAAC,KAAsB,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC,IAAA,YAAM,EAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAAzG,QAAA,MAAM,UAAmG;AAE/G,MAAM,GAAG,GAAQ,CAAC,KAAsB,EAAE,IAAuB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,eAAO,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,cAAM,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAAnI,QAAA,GAAG,OAAgI"}
@@ -0,0 +1,13 @@
1
+ import { Normalized } from "../types";
2
+ export interface HasOne {
3
+ <T>(store: Normalized<T>, key: string): boolean;
4
+ <T extends Normalized<any>>(store: T, key: string): boolean;
5
+ }
6
+ export interface HasMany {
7
+ <T>(store: Normalized<T>, keys: string[]): boolean;
8
+ <T extends Normalized<any>>(store: T, keys: string[]): boolean;
9
+ }
10
+ export declare type Has = HasOne & HasMany;
11
+ export declare const hasMany: HasMany;
12
+ export declare const hasOne: HasOne;
13
+ export declare const has: Has;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.has = exports.hasOne = exports.hasMany = void 0;
4
+ const utils_1 = require("../utils");
5
+ const hasMany = ({ allKeys }, keys) => keys.every((key) => allKeys.includes(key));
6
+ exports.hasMany = hasMany;
7
+ const hasOne = ({ byKey }, key) => (0, utils_1.hasProperty)(byKey, key);
8
+ exports.hasOne = hasOne;
9
+ const has = (store, keys) => (Array.isArray(keys) ? (0, exports.hasMany)(store, keys) : (0, exports.hasOne)(store, keys));
10
+ exports.has = has;
11
+ //# sourceMappingURL=has.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"has.js","sourceRoot":"","sources":["../../src/store/has.ts"],"names":[],"mappings":";;;AACA,oCAAsC;AAc/B,MAAM,OAAO,GAAY,CAAC,EAAE,OAAO,EAAmB,EAAE,IAAc,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AAAhH,QAAA,OAAO,WAAyG;AAEtH,MAAM,MAAM,GAAW,CAAC,EAAE,KAAK,EAAmB,EAAE,GAAW,EAAE,EAAE,CAAC,IAAA,mBAAW,EAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAAtF,QAAA,MAAM,UAAgF;AAE5F,MAAM,GAAG,GAAQ,CAAC,KAAsB,EAAE,IAAuB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,eAAO,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,cAAM,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAAnI,QAAA,GAAG,OAAgI"}
@@ -0,0 +1,15 @@
1
+ import { GetKey, Identifiable, Normalized } from "../types";
2
+ export * from './add';
3
+ export * from './addMany';
4
+ export * from './get';
5
+ export * from './has';
6
+ export * from './patch';
7
+ export * from './remove';
8
+ export * from './update';
9
+ export interface Normalize {
10
+ <T extends Identifiable>(items: T[]): Normalized<T>;
11
+ <T>(items: T[], getKey: GetKey<T>): Normalized<T>;
12
+ }
13
+ export declare const normalize: Normalize;
14
+ export declare const denormalize: <T>({ allKeys, byKey }: Normalized<T>) => T[];
15
+ export declare const createEmpty: <T>() => Normalized<T>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.createEmpty = exports.denormalize = exports.normalize = void 0;
14
+ const utils_1 = require("../utils");
15
+ __exportStar(require("./add"), exports);
16
+ __exportStar(require("./addMany"), exports);
17
+ __exportStar(require("./get"), exports);
18
+ __exportStar(require("./has"), exports);
19
+ __exportStar(require("./patch"), exports);
20
+ __exportStar(require("./remove"), exports);
21
+ __exportStar(require("./update"), exports);
22
+ const normalize = (items, getKey) => {
23
+ const allKeys = items.map(getKey !== null && getKey !== void 0 ? getKey : utils_1.defaultGetKey);
24
+ return {
25
+ byKey: (0, utils_1.buildLookup)(allKeys, (0, utils_1.getByIndex)(items)),
26
+ allKeys,
27
+ };
28
+ };
29
+ exports.normalize = normalize;
30
+ const denormalize = ({ allKeys, byKey }) => allKeys.map((key) => byKey[key]);
31
+ exports.denormalize = denormalize;
32
+ const createEmpty = () => ({ byKey: {}, allKeys: [] });
33
+ exports.createEmpty = createEmpty;
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;AACA,oCAAiE;AAEjE,wCAAsB;AACtB,4CAA0B;AAC1B,wCAAsB;AACtB,wCAAsB;AACtB,0CAAwB;AACxB,2CAAyB;AACzB,2CAAyB;AAOlB,MAAM,SAAS,GAAc,CAAmC,KAAU,EAAE,MAAkB,EAAE,EAAE;IACvG,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,aAAN,MAAM,cAAN,MAAM,GAAK,qBAA2B,CAAC,CAAC;IAElE,OAAO;QACL,KAAK,EAAE,IAAA,mBAAW,EAAI,OAAO,EAAE,IAAA,kBAAU,EAAI,KAAK,CAAC,CAAC;QACpD,OAAO;KACR,CAAC;AACJ,CAAC,CAAC;AAPW,QAAA,SAAS,aAOpB;AAEK,MAAM,WAAW,GAAG,CAAI,EAAE,OAAO,EAAE,KAAK,EAAiB,EAAO,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAA9F,QAAA,WAAW,eAAmF;AAEpG,MAAM,WAAW,GAAG,GAAqB,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;AAAnE,QAAA,WAAW,eAAwD"}
@@ -0,0 +1,6 @@
1
+ import { Normalized, NormalizedValue } from "../types";
2
+ export interface PatchOne {
3
+ <T>(store: Normalized<T>, key: string, patch: Partial<T> | ((value: T) => Partial<T>)): T;
4
+ <T extends Normalized<any>>(store: T, key: string, patch: Partial<NormalizedValue<T>> | ((value: T) => Partial<NormalizedValue<T>>)): T;
5
+ }
6
+ export declare const patchOne: PatchOne;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.patchOne = void 0;
4
+ const get_1 = require("./get");
5
+ const has_1 = require("./has");
6
+ const update_1 = require("./update");
7
+ const patchOne = (store, key, patch) => {
8
+ if (!(0, has_1.hasOne)(store, key))
9
+ return store;
10
+ const value = (0, get_1.getOne)(store, key);
11
+ return (0, update_1.updateOne)(store, key, Object.assign(Object.assign({}, value), (typeof patch === 'function' ? patch(value) : patch)));
12
+ };
13
+ exports.patchOne = patchOne;
14
+ //# sourceMappingURL=patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.js","sourceRoot":"","sources":["../../src/store/patch.ts"],"names":[],"mappings":";;;AAEA,+BAA+B;AAC/B,+BAA+B;AAC/B,qCAAqC;AAO9B,MAAM,QAAQ,GAAa,CAChC,KAAQ,EACR,GAAW,EACX,KAAgF,EAC7E,EAAE;IACL,IAAI,CAAC,IAAA,YAAM,EAAC,KAAK,EAAE,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAEtC,MAAM,KAAK,GAAG,IAAA,YAAM,EAAC,KAAK,EAAE,GAAG,CAAE,CAAC;IAElC,OAAO,IAAA,kBAAS,EAAC,KAAK,EAAE,GAAG,kCAAO,KAAK,GAAK,CAAC,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAG,CAAC;AACtG,CAAC,CAAC;AAVW,QAAA,QAAQ,YAUnB"}
@@ -0,0 +1,13 @@
1
+ import { Normalized } from "../types";
2
+ export interface RemoveOne {
3
+ <T>(store: Normalized<T>, key: string): Normalized<T>;
4
+ <T extends Normalized<any>>(store: T, key: string): T;
5
+ }
6
+ export interface RemoveMany {
7
+ <T>(store: Normalized<T>, keys: string[]): Normalized<T>;
8
+ <T extends Normalized<any>>(store: T, keys: string[]): T;
9
+ }
10
+ export declare type Remove = RemoveOne | RemoveMany;
11
+ export declare const removeOne: RemoveOne;
12
+ export declare const removeMany: RemoveMany;
13
+ export declare const remove: <T extends Normalized<any>>(store: T, keys: string | string[]) => Normalized<any>;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.remove = exports.removeMany = exports.removeOne = void 0;
4
+ const utils_1 = require("../utils");
5
+ const removeOne = (store, key) => {
6
+ const filteredKeys = (0, utils_1.withoutValue)(store.allKeys, key);
7
+ return Object.assign(Object.assign({}, store), { allKeys: filteredKeys, byKey: (0, utils_1.buildLookup)(filteredKeys, (0, utils_1.getByKey)(store.byKey)) });
8
+ };
9
+ exports.removeOne = removeOne;
10
+ const removeMany = (store, keys) => {
11
+ const filteredKeys = (0, utils_1.withoutValues)(store.allKeys, keys);
12
+ return Object.assign(Object.assign({}, store), { allKeys: filteredKeys, byKey: (0, utils_1.buildLookup)(filteredKeys, (0, utils_1.getByKey)(store.byKey)) });
13
+ };
14
+ exports.removeMany = removeMany;
15
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
16
+ const remove = (store, keys) => Array.isArray(keys) ? (0, exports.removeMany)(store, keys) : (0, exports.removeOne)(store, keys);
17
+ exports.remove = remove;
18
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/store/remove.ts"],"names":[],"mappings":";;;AACA,oCAA6E;AActE,MAAM,SAAS,GAAc,CAAC,KAAsB,EAAE,GAAW,EAAE,EAAE;IAC1E,MAAM,YAAY,GAAG,IAAA,oBAAY,EAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAEtD,uCACK,KAAK,KACR,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,IAAA,mBAAW,EAAC,YAAY,EAAE,IAAA,gBAAQ,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IACvD;AACJ,CAAC,CAAC;AARW,QAAA,SAAS,aAQpB;AAEK,MAAM,UAAU,GAAe,CAAC,KAAsB,EAAE,IAAc,EAAE,EAAE;IAC/E,MAAM,YAAY,GAAG,IAAA,qBAAa,EAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAExD,uCACK,KAAK,KACR,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,IAAA,mBAAW,EAAC,YAAY,EAAE,IAAA,gBAAQ,EAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IACvD;AACJ,CAAC,CAAC;AARW,QAAA,UAAU,cAQrB;AAEF,6EAA6E;AACtE,MAAM,MAAM,GAAG,CAA4B,KAAQ,EAAE,IAAuB,EAAE,EAAE,CACrF,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,kBAAU,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAS,EAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAD5D,QAAA,MAAM,UACsD"}
@@ -0,0 +1,6 @@
1
+ import { Normalized, NormalizedValue } from "../types";
2
+ export interface UpdateOne {
3
+ <T>(store: Normalized<T>, key: string, update: T): T;
4
+ <T extends Normalized<any>>(store: T, key: string, update: NormalizedValue<T>): T;
5
+ }
6
+ export declare const updateOne: UpdateOne;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.updateOne = void 0;
4
+ const updateOne = (store, key, value) => (Object.assign(Object.assign({}, store), { byKey: Object.assign(Object.assign({}, store.byKey), { [key]: value }) }));
5
+ exports.updateOne = updateOne;
6
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/store/update.ts"],"names":[],"mappings":";;;AAOO,MAAM,SAAS,GAAc,CAA4B,KAAQ,EAAE,GAAW,EAAE,KAAyB,EAAK,EAAE,CAAC,iCACnH,KAAK,KACR,KAAK,kCAAO,KAAK,CAAC,KAAK,KAAE,CAAC,GAAG,CAAC,EAAE,KAAK,OACrC,CAAC;AAHU,QAAA,SAAS,aAGnB"}
@@ -0,0 +1,9 @@
1
+ export interface Identifiable {
2
+ id: number | string;
3
+ }
4
+ export declare type NormalizedValue<T> = T extends Normalized<infer R> ? R : never;
5
+ export interface Normalized<T> {
6
+ byKey: Record<string, T>;
7
+ allKeys: string[];
8
+ }
9
+ export declare type GetKey<T> = (obj: T, index: number, array: T[]) => string;
package/build/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ import { Identifiable } from './types';
2
+ export declare const stringify: (value: any) => string;
3
+ export declare const withoutValue: <T>(items: T[], value: T) => T[];
4
+ export declare const withoutValues: <T>(items: T[], values: T[]) => T[];
5
+ export declare const appendUnique: <T>(items: T[], value: T) => T[];
6
+ export declare const prependUnique: <T>(items: T[], value: T) => T[];
7
+ export declare const buildLookup: <T>(allKeys: string[], getValue: (key: string, index: number) => T) => Record<string, T>;
8
+ export declare const hasProperty: <T, K extends keyof T>(obj: T, key: string | K) => obj is T & Record<K, unknown>;
9
+ export declare const getByIndex: <T>(items: T[]) => (_: string, index: number) => T;
10
+ export declare const getByKey: <T>(lookup: Record<string, T>) => (key: string) => T;
11
+ export declare const defaultGetKey: <T extends Identifiable>(obj: T) => string;
package/build/utils.js ADDED
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultGetKey = exports.getByKey = exports.getByIndex = exports.hasProperty = exports.buildLookup = exports.prependUnique = exports.appendUnique = exports.withoutValues = exports.withoutValue = exports.stringify = void 0;
4
+ const stringify = (value) => (typeof value === 'string' ? value : String(value));
5
+ exports.stringify = stringify;
6
+ const withoutValue = (items, value) => {
7
+ const index = items.indexOf(value);
8
+ return index < 0 ? items : [...items.slice(0, index), ...items.slice(index + 1)];
9
+ };
10
+ exports.withoutValue = withoutValue;
11
+ const withoutValues = (items, values) => items.filter((item) => !values.includes(item));
12
+ exports.withoutValues = withoutValues;
13
+ const appendUnique = (items, value) => (items.includes(value) ? items : [...items, value]);
14
+ exports.appendUnique = appendUnique;
15
+ const prependUnique = (items, value) => (items.includes(value) ? items : [value, ...items]);
16
+ exports.prependUnique = prependUnique;
17
+ const buildLookup = (allKeys, getValue) => allKeys.reduce((acc, key, index) => {
18
+ acc[key] = getValue(key, index);
19
+ return acc;
20
+ }, {});
21
+ exports.buildLookup = buildLookup;
22
+ const hasProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
23
+ exports.hasProperty = hasProperty;
24
+ const getByIndex = (items) => (_, index) => items[index];
25
+ exports.getByIndex = getByIndex;
26
+ const getByKey = (lookup) => (key) => lookup[key];
27
+ exports.getByKey = getByKey;
28
+ const defaultGetKey = (obj) => (0, exports.stringify)(obj.id);
29
+ exports.defaultGetKey = defaultGetKey;
30
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;AAEO,MAAM,SAAS,GAAG,CAAC,KAAU,EAAU,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAAxF,QAAA,SAAS,aAA+E;AAE9F,MAAM,YAAY,GAAG,CAAI,KAAU,EAAE,KAAQ,EAAO,EAAE;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAEnC,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;AACnF,CAAC,CAAC;AAJW,QAAA,YAAY,gBAIvB;AAEK,MAAM,aAAa,GAAG,CAAI,KAAU,EAAE,MAAW,EAAO,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAApG,QAAA,aAAa,iBAAuF;AAE1G,MAAM,YAAY,GAAG,CAAI,KAAU,EAAE,KAAQ,EAAO,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAArG,QAAA,YAAY,gBAAyF;AAE3G,MAAM,aAAa,GAAG,CAAI,KAAU,EAAE,KAAQ,EAAO,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AAAtG,QAAA,aAAa,iBAAyF;AAE5G,MAAM,WAAW,GAAG,CAAI,OAAiB,EAAE,QAA2C,EAAqB,EAAE,CAClH,OAAO,CAAC,MAAM,CAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;IACpD,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAEhC,OAAO,GAAG,CAAC;AACb,CAAC,EAAE,EAAE,CAAC,CAAC;AALI,QAAA,WAAW,eAKf;AAEF,MAAM,WAAW,GAAG,CAAuB,GAAM,EAAE,GAAe,EAAiC,EAAE,CAC1G,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AADpC,QAAA,WAAW,eACyB;AAE1C,MAAM,UAAU,GACrB,CAAI,KAAU,EAAE,EAAE,CAClB,CAAC,CAAS,EAAE,KAAa,EAAK,EAAE,CAC9B,KAAK,CAAC,KAAK,CAAC,CAAC;AAHJ,QAAA,UAAU,cAGN;AAEV,MAAM,QAAQ,GACnB,CAAI,MAAyB,EAAE,EAAE,CACjC,CAAC,GAAW,EAAK,EAAE,CACjB,MAAM,CAAC,GAAG,CAAC,CAAC;AAHH,QAAA,QAAQ,YAGL;AAET,MAAM,aAAa,GAAG,CAAyB,GAAM,EAAU,EAAE,CAAC,IAAA,iBAAS,EAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAA9E,QAAA,aAAa,iBAAiE"}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "normal-store",
3
+ "description": "tools for interacting with normalized data structures",
4
+ "version": "1.0.0",
5
+ "author": "Tyler Han, Ben Teichman",
6
+ "bugs": {
7
+ "url": "https://github.com/voiceflow/normal-store/issues"
8
+ },
9
+ "config": {
10
+ "commitizen": {
11
+ "path": "./node_modules/cz-conventional-changelog"
12
+ }
13
+ },
14
+ "devDependencies": {
15
+ "@commitlint/cli": "^11.0.0",
16
+ "@istanbuljs/nyc-config-typescript": "^1.0.1",
17
+ "@types/chai": "^4.2.15",
18
+ "@types/mocha": "^9.0.0",
19
+ "@voiceflow/commitlint-config": "1.1.0",
20
+ "@voiceflow/eslint-config": "3.4.0",
21
+ "@voiceflow/git-branch-check": "1.2.0",
22
+ "@voiceflow/prettier-config": "1.0.5",
23
+ "@voiceflow/tsconfig": "1.1.0",
24
+ "@zerollup/ts-transform-paths": "^1.7.18",
25
+ "chai": "^4.3.0",
26
+ "commitizen": "^4.2.3",
27
+ "cz-conventional-changelog": "^3.3.0",
28
+ "depcheck": "^1.4.2",
29
+ "eslint": "^7.20.0",
30
+ "eslint-output": "^3.0.1",
31
+ "fixpack": "^4.0.0",
32
+ "husky": "^4.3.8",
33
+ "istanbul": "^0.4.5",
34
+ "lint-staged": "^10.5.4",
35
+ "mocha": "^8.3.0",
36
+ "nyc": "^15.1.0",
37
+ "prettier": "^2.2.1",
38
+ "source-map-support": "^0.5.19",
39
+ "ts-mocha": "^8.0.0",
40
+ "ts-node": "^9.1.1",
41
+ "ttypescript": "^1.5.12",
42
+ "typescript": "^4.4.2"
43
+ },
44
+ "files": [
45
+ "build/"
46
+ ],
47
+ "homepage": "https://github.com/voiceflow/normal-store#readme",
48
+ "keywords": [
49
+ "data",
50
+ "voiceflow"
51
+ ],
52
+ "license": "ISC",
53
+ "main": "build/index.js",
54
+ "prettier": "@voiceflow/prettier-config",
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/voiceflow/normal-store.git"
58
+ },
59
+ "scripts": {
60
+ "build": "yarn clean && ttsc --project ./tsconfig.build.json --declaration",
61
+ "clean": "rimraf build",
62
+ "commit": "cz",
63
+ "eslint-output": "eslint-output",
64
+ "lint": "eslint '**/*.{js,ts}'",
65
+ "lint:output": "yarn run eslint-output --quiet \"**/*.{js,ts}\"",
66
+ "lint:quiet": "yarn lint --quiet",
67
+ "lint:report": "yarn lint:output",
68
+ "prepublishOnly": "yarn build",
69
+ "test": "yarn test:run",
70
+ "test:dependencies": "depcheck",
71
+ "test:integration": "NODE_ENV=test nyc --report-dir nyc_coverage_integration ts-mocha --paths --config ./config/test/.mocharc.yml 'test/**/*.it.ts'",
72
+ "test:run": "NODE_ENV=test nyc ts-mocha --paths --config ./config/test/.mocharc.yml 'test/**/*.{unit,it}.ts'",
73
+ "test:single": "NODE_ENV=test ts-mocha --paths --config ./config/test/.mocharc.yml",
74
+ "test:unit": "NODE_ENV=test nyc --report-dir=nyc_coverage_unit ts-mocha --paths --config ./config/test/.mocharc.yml 'test/**/*.unit.ts'"
75
+ },
76
+ "types": "build/index.d.ts"
77
+ }