@voiceflow/common 7.25.3 → 7.27.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.
@@ -37,4 +37,30 @@ export declare const filterOutNullish: <T>(items: readonly T[]) => NonNullable<T
37
37
  export declare const filterAndGetLastRemovedValue: <T>(list: T[], filter: (item: T) => boolean) => [T[], T | null];
38
38
  export declare const inferUnion: <T extends ArrayLike<unknown>>(array: T) => import("../types").SafeArray<T[number], T>;
39
39
  export declare const toArray: <T>(valueOrArray: T | T[]) => T[];
40
+ /**
41
+ * Merge together two arrays, if two items have the same identity based on the {@link identify} function
42
+ * they will be merged together using the {@link merge} function provided.
43
+ * @param items Array of items as a starting base.
44
+ * @param newItems Array of items to merge in.
45
+ * @param identify Function returning how to identify an item in the array
46
+ * @param merge Function given two matching item identifiers, returning a single merged result
47
+ * @example
48
+ * const existingItems = [{a: 1, b: [1, 2, 3]}, {a: 2, b: [4]}];
49
+ * const newItems = [{a: 1, b: [5]}, {a: 3, b: [6, 7]}];
50
+ *
51
+ * const items = mergeByIdentifier(
52
+ * existingItems,
53
+ * newItems,
54
+ * (item) => item.a,
55
+ * (existingItem, newItem) => {
56
+ * return {
57
+ * ...existingItem,
58
+ * b: [...existingItem.b, ...newItem.b]
59
+ * }
60
+ * }
61
+ * );
62
+ *
63
+ * items == [{a: 1, b: [1, 2, 3, 5]}, {a: 2, b: [4]}, {a: 3, b: [6, 7]}];
64
+ */
65
+ export declare const mergeByIdentifier: <T>(items: T[], newItems: T[], identify: (item: T, index: number) => string, merge: (item1: T, item2: T) => T) => T[];
40
66
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toArray = exports.inferUnion = exports.filterAndGetLastRemovedValue = exports.filterOutNullish = exports.isNotNullish = exports.isNullish = exports.asyncForEach = exports.hasIdenticalMembers = exports.diff = exports.findUnion = exports.createMap = exports.createEntries = exports.separate = exports.reorder = exports.tail = exports.head = exports.toggleMembership = exports.append = exports.insertAll = exports.insert = exports.replace = exports.withoutValues = exports.withoutValue = exports.without = exports.unique = void 0;
3
+ exports.mergeByIdentifier = exports.toArray = exports.inferUnion = exports.filterAndGetLastRemovedValue = exports.filterOutNullish = exports.isNotNullish = exports.isNullish = exports.asyncForEach = exports.hasIdenticalMembers = exports.diff = exports.findUnion = exports.createMap = exports.createEntries = exports.separate = exports.reorder = exports.tail = exports.head = exports.toggleMembership = exports.append = exports.insertAll = exports.insert = exports.replace = exports.withoutValues = exports.withoutValue = exports.without = exports.unique = void 0;
4
4
  const unique = (items) => Array.from(new Set(items));
5
5
  exports.unique = unique;
6
6
  const without = (items, index) => (index < 0 ? items : [...items.slice(0, index), ...items.slice(index + 1)]);
@@ -125,3 +125,42 @@ const inferUnion = (array) => array;
125
125
  exports.inferUnion = inferUnion;
126
126
  const toArray = (valueOrArray) => (Array.isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
127
127
  exports.toArray = toArray;
128
+ /**
129
+ * Merge together two arrays, if two items have the same identity based on the {@link identify} function
130
+ * they will be merged together using the {@link merge} function provided.
131
+ * @param items Array of items as a starting base.
132
+ * @param newItems Array of items to merge in.
133
+ * @param identify Function returning how to identify an item in the array
134
+ * @param merge Function given two matching item identifiers, returning a single merged result
135
+ * @example
136
+ * const existingItems = [{a: 1, b: [1, 2, 3]}, {a: 2, b: [4]}];
137
+ * const newItems = [{a: 1, b: [5]}, {a: 3, b: [6, 7]}];
138
+ *
139
+ * const items = mergeByIdentifier(
140
+ * existingItems,
141
+ * newItems,
142
+ * (item) => item.a,
143
+ * (existingItem, newItem) => {
144
+ * return {
145
+ * ...existingItem,
146
+ * b: [...existingItem.b, ...newItem.b]
147
+ * }
148
+ * }
149
+ * );
150
+ *
151
+ * items == [{a: 1, b: [1, 2, 3, 5]}, {a: 2, b: [4]}, {a: 3, b: [6, 7]}];
152
+ */
153
+ const mergeByIdentifier = (items, newItems, identify, merge) => {
154
+ const newItemsMap = new Map(newItems.map((newItem, i) => [identify(newItem, i), newItem]));
155
+ const result = items.map((item, i) => {
156
+ const itemIdentity = identify(item, i);
157
+ const matchingNewItem = newItemsMap.get(itemIdentity);
158
+ if (matchingNewItem) {
159
+ newItemsMap.delete(itemIdentity);
160
+ return merge(item, matchingNewItem);
161
+ }
162
+ return item;
163
+ });
164
+ return result.concat(Array.from(newItemsMap.values()));
165
+ };
166
+ exports.mergeByIdentifier = mergeByIdentifier;
@@ -23,4 +23,7 @@ export declare const omitBy: PickOmitBy;
23
23
  * @deprecated use pickBy instead
24
24
  */
25
25
  export declare const filterEntries: PickOmitBy;
26
+ export declare const mapValue: <T, R>(obj: Record<string | number | symbol, T>, callback: (value: T) => R) => {
27
+ [k: string]: R;
28
+ };
26
29
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.filterEntries = exports.omitBy = exports.pickBy = exports.pick = exports.omit = exports.hasProperty = exports.isObject = exports.selectValue = exports.selectKey = exports.selectID = exports.selectField = void 0;
3
+ exports.mapValue = exports.filterEntries = exports.omitBy = exports.pickBy = exports.pick = exports.omit = exports.hasProperty = exports.isObject = exports.selectValue = exports.selectKey = exports.selectID = exports.selectField = void 0;
4
4
  const selectField = (field) => (obj) => obj[field];
5
5
  exports.selectField = selectField;
6
6
  exports.selectID = (0, exports.selectField)('id');
@@ -61,3 +61,5 @@ exports.omitBy = omitBy;
61
61
  * @deprecated use pickBy instead
62
62
  */
63
63
  exports.filterEntries = exports.pickBy;
64
+ const mapValue = (obj, callback) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, callback(value)]));
65
+ exports.mapValue = mapValue;
@@ -4,3 +4,23 @@ export declare const addPrebuiltEntities: <A extends {
4
4
  }>(entities: A[], prebuiltEntities: Record<string, string[]>) => A[];
5
5
  export declare const getUniqueSamples: (input: string) => string[];
6
6
  export declare const getAllSamples: (inputs?: string[]) => string[];
7
+ /**
8
+ * Return a tuple of synonyms, the first value being the first synonym, the next being the remaining synonyms
9
+ */
10
+ export declare const getValueWithSynonyms: (input: string) => [string, string[]];
11
+ /**
12
+ * Map through all slot annotations in the given string input.
13
+ * For each annotation, the callbackFn will be called with the slot's key and name, returning a key and name.
14
+ * @param input String with slot annotations.
15
+ * @param callbackFn Map function called with the key and name of the slot.
16
+ * @returns Input with mapped slot annotations
17
+ * @example const result = mapSlotAnnotations("Hello {{[slot].id}}", ({key, name}) => ({key: key + '2', slot: slot + '2'});
18
+ * result === "Hello {{[slot2].id2}}"
19
+ */
20
+ export declare const mapSlotAnnotations: (input: string, callbackFn: (slot: {
21
+ key: string;
22
+ name: string;
23
+ }) => {
24
+ key: string;
25
+ name: string;
26
+ }) => string;
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getAllSamples = exports.getUniqueSamples = exports.addPrebuiltEntities = void 0;
6
+ exports.mapSlotAnnotations = exports.getValueWithSynonyms = exports.getAllSamples = exports.getUniqueSamples = exports.addPrebuiltEntities = void 0;
7
7
  const uniqBy_1 = __importDefault(require("lodash/uniqBy"));
8
+ const constants_1 = require("../constants");
8
9
  const addPrebuiltEntities = (entities, prebuiltEntities) => entities.map((entity) => {
9
10
  if (prebuiltEntities[entity.key]) {
10
11
  return Object.assign(Object.assign({}, entity), { inputs: [...entity.inputs, ...prebuiltEntities[entity.key]] });
@@ -17,3 +18,27 @@ exports.getUniqueSamples = getUniqueSamples;
17
18
  // spread all synonyms into string array ['car, automobile', 'plane, jet'] => ['car', 'automobile', 'plane', 'jet']
18
19
  const getAllSamples = (inputs = []) => inputs.flatMap((input) => input.split(',')).filter((sample) => !!sample.trim());
19
20
  exports.getAllSamples = getAllSamples;
21
+ /**
22
+ * Return a tuple of synonyms, the first value being the first synonym, the next being the remaining synonyms
23
+ */
24
+ const getValueWithSynonyms = (input) => {
25
+ const [value, ...synonyms] = input.split(',').map((str) => str.trim());
26
+ return [value, synonyms];
27
+ };
28
+ exports.getValueWithSynonyms = getValueWithSynonyms;
29
+ /**
30
+ * Map through all slot annotations in the given string input.
31
+ * For each annotation, the callbackFn will be called with the slot's key and name, returning a key and name.
32
+ * @param input String with slot annotations.
33
+ * @param callbackFn Map function called with the key and name of the slot.
34
+ * @returns Input with mapped slot annotations
35
+ * @example const result = mapSlotAnnotations("Hello {{[slot].id}}", ({key, name}) => ({key: key + '2', slot: slot + '2'});
36
+ * result === "Hello {{[slot2].id2}}"
37
+ */
38
+ const mapSlotAnnotations = (input, callbackFn) => {
39
+ return input.replace(constants_1.SLOT_REGEXP, (_, slotName, slotKey) => {
40
+ const { key, name } = callbackFn({ key: slotKey, name: slotName });
41
+ return `{{[${name}].${key}}}`;
42
+ });
43
+ };
44
+ exports.mapSlotAnnotations = mapSlotAnnotations;
@@ -47,6 +47,9 @@ exports.getTimeDuration = getTimeDuration;
47
47
  const getAbbrevatedFormat = (time) => time
48
48
  .split(' ')
49
49
  .map((str) => {
50
+ if (str.includes('month')) {
51
+ return 'mo';
52
+ }
50
53
  if (str.includes('day')) {
51
54
  return 'd';
52
55
  }
@@ -37,4 +37,30 @@ export declare const filterOutNullish: <T>(items: readonly T[]) => NonNullable<T
37
37
  export declare const filterAndGetLastRemovedValue: <T>(list: T[], filter: (item: T) => boolean) => [T[], T | null];
38
38
  export declare const inferUnion: <T extends ArrayLike<unknown>>(array: T) => import("../types").SafeArray<T[number], T>;
39
39
  export declare const toArray: <T>(valueOrArray: T | T[]) => T[];
40
+ /**
41
+ * Merge together two arrays, if two items have the same identity based on the {@link identify} function
42
+ * they will be merged together using the {@link merge} function provided.
43
+ * @param items Array of items as a starting base.
44
+ * @param newItems Array of items to merge in.
45
+ * @param identify Function returning how to identify an item in the array
46
+ * @param merge Function given two matching item identifiers, returning a single merged result
47
+ * @example
48
+ * const existingItems = [{a: 1, b: [1, 2, 3]}, {a: 2, b: [4]}];
49
+ * const newItems = [{a: 1, b: [5]}, {a: 3, b: [6, 7]}];
50
+ *
51
+ * const items = mergeByIdentifier(
52
+ * existingItems,
53
+ * newItems,
54
+ * (item) => item.a,
55
+ * (existingItem, newItem) => {
56
+ * return {
57
+ * ...existingItem,
58
+ * b: [...existingItem.b, ...newItem.b]
59
+ * }
60
+ * }
61
+ * );
62
+ *
63
+ * items == [{a: 1, b: [1, 2, 3, 5]}, {a: 2, b: [4]}, {a: 3, b: [6, 7]}];
64
+ */
65
+ export declare const mergeByIdentifier: <T>(items: T[], newItems: T[], identify: (item: T, index: number) => string, merge: (item1: T, item2: T) => T) => T[];
40
66
  export {};
@@ -97,3 +97,41 @@ export const filterAndGetLastRemovedValue = (list, filter) => {
97
97
  };
98
98
  export const inferUnion = (array) => array;
99
99
  export const toArray = (valueOrArray) => (Array.isArray(valueOrArray) ? valueOrArray : [valueOrArray]);
100
+ /**
101
+ * Merge together two arrays, if two items have the same identity based on the {@link identify} function
102
+ * they will be merged together using the {@link merge} function provided.
103
+ * @param items Array of items as a starting base.
104
+ * @param newItems Array of items to merge in.
105
+ * @param identify Function returning how to identify an item in the array
106
+ * @param merge Function given two matching item identifiers, returning a single merged result
107
+ * @example
108
+ * const existingItems = [{a: 1, b: [1, 2, 3]}, {a: 2, b: [4]}];
109
+ * const newItems = [{a: 1, b: [5]}, {a: 3, b: [6, 7]}];
110
+ *
111
+ * const items = mergeByIdentifier(
112
+ * existingItems,
113
+ * newItems,
114
+ * (item) => item.a,
115
+ * (existingItem, newItem) => {
116
+ * return {
117
+ * ...existingItem,
118
+ * b: [...existingItem.b, ...newItem.b]
119
+ * }
120
+ * }
121
+ * );
122
+ *
123
+ * items == [{a: 1, b: [1, 2, 3, 5]}, {a: 2, b: [4]}, {a: 3, b: [6, 7]}];
124
+ */
125
+ export const mergeByIdentifier = (items, newItems, identify, merge) => {
126
+ const newItemsMap = new Map(newItems.map((newItem, i) => [identify(newItem, i), newItem]));
127
+ const result = items.map((item, i) => {
128
+ const itemIdentity = identify(item, i);
129
+ const matchingNewItem = newItemsMap.get(itemIdentity);
130
+ if (matchingNewItem) {
131
+ newItemsMap.delete(itemIdentity);
132
+ return merge(item, matchingNewItem);
133
+ }
134
+ return item;
135
+ });
136
+ return result.concat(Array.from(newItemsMap.values()));
137
+ };
@@ -23,4 +23,7 @@ export declare const omitBy: PickOmitBy;
23
23
  * @deprecated use pickBy instead
24
24
  */
25
25
  export declare const filterEntries: PickOmitBy;
26
+ export declare const mapValue: <T, R>(obj: Record<string | number | symbol, T>, callback: (value: T) => R) => {
27
+ [k: string]: R;
28
+ };
26
29
  export {};
@@ -51,3 +51,4 @@ export const omitBy = (obj, predicate) => Object.entries(obj).reduce((acc, [key,
51
51
  * @deprecated use pickBy instead
52
52
  */
53
53
  export const filterEntries = pickBy;
54
+ export const mapValue = (obj, callback) => Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, callback(value)]));
@@ -4,3 +4,23 @@ export declare const addPrebuiltEntities: <A extends {
4
4
  }>(entities: A[], prebuiltEntities: Record<string, string[]>) => A[];
5
5
  export declare const getUniqueSamples: (input: string) => string[];
6
6
  export declare const getAllSamples: (inputs?: string[]) => string[];
7
+ /**
8
+ * Return a tuple of synonyms, the first value being the first synonym, the next being the remaining synonyms
9
+ */
10
+ export declare const getValueWithSynonyms: (input: string) => [string, string[]];
11
+ /**
12
+ * Map through all slot annotations in the given string input.
13
+ * For each annotation, the callbackFn will be called with the slot's key and name, returning a key and name.
14
+ * @param input String with slot annotations.
15
+ * @param callbackFn Map function called with the key and name of the slot.
16
+ * @returns Input with mapped slot annotations
17
+ * @example const result = mapSlotAnnotations("Hello {{[slot].id}}", ({key, name}) => ({key: key + '2', slot: slot + '2'});
18
+ * result === "Hello {{[slot2].id2}}"
19
+ */
20
+ export declare const mapSlotAnnotations: (input: string, callbackFn: (slot: {
21
+ key: string;
22
+ name: string;
23
+ }) => {
24
+ key: string;
25
+ name: string;
26
+ }) => string;
@@ -1,4 +1,5 @@
1
1
  import _uniqBy from 'lodash/uniqBy';
2
+ import { SLOT_REGEXP } from '../constants';
2
3
  export const addPrebuiltEntities = (entities, prebuiltEntities) => entities.map((entity) => {
3
4
  if (prebuiltEntities[entity.key]) {
4
5
  return Object.assign(Object.assign({}, entity), { inputs: [...entity.inputs, ...prebuiltEntities[entity.key]] });
@@ -8,3 +9,25 @@ export const addPrebuiltEntities = (entities, prebuiltEntities) => entities.map(
8
9
  export const getUniqueSamples = (input) => _uniqBy(input.split(','), (sample) => sample.toLowerCase());
9
10
  // spread all synonyms into string array ['car, automobile', 'plane, jet'] => ['car', 'automobile', 'plane', 'jet']
10
11
  export const getAllSamples = (inputs = []) => inputs.flatMap((input) => input.split(',')).filter((sample) => !!sample.trim());
12
+ /**
13
+ * Return a tuple of synonyms, the first value being the first synonym, the next being the remaining synonyms
14
+ */
15
+ export const getValueWithSynonyms = (input) => {
16
+ const [value, ...synonyms] = input.split(',').map((str) => str.trim());
17
+ return [value, synonyms];
18
+ };
19
+ /**
20
+ * Map through all slot annotations in the given string input.
21
+ * For each annotation, the callbackFn will be called with the slot's key and name, returning a key and name.
22
+ * @param input String with slot annotations.
23
+ * @param callbackFn Map function called with the key and name of the slot.
24
+ * @returns Input with mapped slot annotations
25
+ * @example const result = mapSlotAnnotations("Hello {{[slot].id}}", ({key, name}) => ({key: key + '2', slot: slot + '2'});
26
+ * result === "Hello {{[slot2].id2}}"
27
+ */
28
+ export const mapSlotAnnotations = (input, callbackFn) => {
29
+ return input.replace(SLOT_REGEXP, (_, slotName, slotKey) => {
30
+ const { key, name } = callbackFn({ key: slotKey, name: slotName });
31
+ return `{{[${name}].${key}}}`;
32
+ });
33
+ };
@@ -39,6 +39,9 @@ export const getTimeDuration = (pastTime) => {
39
39
  export const getAbbrevatedFormat = (time) => time
40
40
  .split(' ')
41
41
  .map((str) => {
42
+ if (str.includes('month')) {
43
+ return 'mo';
44
+ }
42
45
  if (str.includes('day')) {
43
46
  return 'd';
44
47
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@voiceflow/common",
3
3
  "description": "Junk drawer of utility functions",
4
- "version": "7.25.3",
4
+ "version": "7.27.0",
5
5
  "author": "Voiceflow",
6
6
  "bugs": {
7
7
  "url": "https://github.com/voiceflow/libs/issues"
@@ -64,10 +64,10 @@
64
64
  "build:esm": "ttsc --project ./tsconfig.build.json --module esnext --outDir ./build/esm",
65
65
  "clean": "rimraf build",
66
66
  "commit": "cz",
67
- "lint": "eslint \"**/*.{js,ts}\"",
67
+ "lint": "eslint \"{src,tests}/**/*.{js,ts}\"",
68
68
  "lint:fix": "yarn lint --fix",
69
69
  "lint:quiet": "yarn lint --quiet",
70
- "lint:report": "eslint-output --quiet \"**/*.{js,ts}\"",
70
+ "lint:report": "eslint-output --quiet \"{src,tests}/**/*.{js,ts}\"",
71
71
  "tdd": "yarn test --watch",
72
72
  "test": "yarn test:run",
73
73
  "test:dependencies": "depcheck",
@@ -76,5 +76,5 @@
76
76
  "test:single": "NODE_ENV=test ts-mocha --paths --config config/tests/mocharc.yml",
77
77
  "test:unit": "NODE_ENV=test nyc --report-dir=nyc_coverage_unit ts-mocha --paths --config config/tests/mocharc.yml 'tests/**/*.unit.ts'"
78
78
  },
79
- "gitHead": "af1863006aa5748d2f373bff4a9aaa69b3a20333"
79
+ "gitHead": "aad20f39f18f98da96b48ad4ee7ff0c95e096421"
80
80
  }