@tidyjs/tidy 2.5.2 → 2.6.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.
Files changed (230) hide show
  1. package/dist/es/addRows.js.map +1 -1
  2. package/dist/es/arrange.js +9 -5
  3. package/dist/es/arrange.js.map +1 -1
  4. package/dist/es/complete.js.map +1 -1
  5. package/dist/es/count.js +6 -2
  6. package/dist/es/count.js.map +1 -1
  7. package/dist/es/debug.js +4 -2
  8. package/dist/es/debug.js.map +1 -1
  9. package/dist/es/distinct.js +3 -3
  10. package/dist/es/distinct.js.map +1 -1
  11. package/dist/es/expand.js +18 -13
  12. package/dist/es/expand.js.map +1 -1
  13. package/dist/es/fill.js +10 -3
  14. package/dist/es/fill.js.map +1 -1
  15. package/dist/es/filter.js.map +1 -1
  16. package/dist/es/fullJoin.js +23 -20
  17. package/dist/es/fullJoin.js.map +1 -1
  18. package/dist/es/groupBy.js +56 -28
  19. package/dist/es/groupBy.js.map +1 -1
  20. package/dist/es/helpers/assignGroupKeys.js +4 -4
  21. package/dist/es/helpers/assignGroupKeys.js.map +1 -1
  22. package/dist/es/helpers/groupMap.js +2 -2
  23. package/dist/es/helpers/groupMap.js.map +1 -1
  24. package/dist/es/helpers/groupTraversal.js +5 -4
  25. package/dist/es/helpers/groupTraversal.js.map +1 -1
  26. package/dist/es/helpers/identity.js.map +1 -1
  27. package/dist/es/helpers/isObject.js.map +1 -1
  28. package/dist/es/helpers/keysFromItems.js +1 -2
  29. package/dist/es/helpers/keysFromItems.js.map +1 -1
  30. package/dist/es/helpers/singleOrArray.js.map +1 -1
  31. package/dist/es/helpers/summation.js +11 -3
  32. package/dist/es/helpers/summation.js.map +1 -1
  33. package/dist/es/innerJoin.js +37 -12
  34. package/dist/es/innerJoin.js.map +1 -1
  35. package/dist/es/item/rate.js +2 -3
  36. package/dist/es/item/rate.js.map +1 -1
  37. package/dist/es/leftJoin.js +13 -8
  38. package/dist/es/leftJoin.js.map +1 -1
  39. package/dist/es/map.js.map +1 -1
  40. package/dist/es/math/math.js.map +1 -1
  41. package/dist/es/mutate.js +1 -1
  42. package/dist/es/mutate.js.map +1 -1
  43. package/dist/es/mutateWithSummary.js +1 -1
  44. package/dist/es/mutateWithSummary.js.map +1 -1
  45. package/dist/es/pivotLonger.js +31 -7
  46. package/dist/es/pivotLonger.js.map +1 -1
  47. package/dist/es/pivotWider.js +24 -19
  48. package/dist/es/pivotWider.js.map +1 -1
  49. package/dist/es/rename.js.map +1 -1
  50. package/dist/es/replaceNully.js +1 -1
  51. package/dist/es/replaceNully.js.map +1 -1
  52. package/dist/es/select.js +3 -3
  53. package/dist/es/select.js.map +1 -1
  54. package/dist/es/selectors/contains.js.map +1 -1
  55. package/dist/es/selectors/endsWith.js.map +1 -1
  56. package/dist/es/selectors/everything.js.map +1 -1
  57. package/dist/es/selectors/matches.js.map +1 -1
  58. package/dist/es/selectors/negate.js +2 -2
  59. package/dist/es/selectors/negate.js.map +1 -1
  60. package/dist/es/selectors/numRange.js.map +1 -1
  61. package/dist/es/selectors/startsWith.js.map +1 -1
  62. package/dist/es/sequences/fullSeq.js +5 -1
  63. package/dist/es/sequences/fullSeq.js.map +1 -1
  64. package/dist/es/slice.js +2 -3
  65. package/dist/es/slice.js.map +1 -1
  66. package/dist/es/summarize.js +6 -4
  67. package/dist/es/summarize.js.map +1 -1
  68. package/dist/es/summary/deviation.js.map +1 -1
  69. package/dist/es/summary/first.js.map +1 -1
  70. package/dist/es/summary/last.js.map +1 -1
  71. package/dist/es/summary/max.js.map +1 -1
  72. package/dist/es/summary/mean.js.map +1 -1
  73. package/dist/es/summary/meanRate.js.map +1 -1
  74. package/dist/es/summary/median.js.map +1 -1
  75. package/dist/es/summary/min.js.map +1 -1
  76. package/dist/es/summary/n.js.map +1 -1
  77. package/dist/es/summary/nDistinct.js +2 -2
  78. package/dist/es/summary/nDistinct.js.map +1 -1
  79. package/dist/es/summary/sum.js.map +1 -1
  80. package/dist/es/summary/variance.js.map +1 -1
  81. package/dist/es/tally.js +4 -2
  82. package/dist/es/tally.js.map +1 -1
  83. package/dist/es/tidy.js.map +1 -1
  84. package/dist/es/total.js.map +1 -1
  85. package/dist/es/transmute.js.map +1 -1
  86. package/dist/es/vector/cumsum.js.map +1 -1
  87. package/dist/es/vector/lag.js +1 -1
  88. package/dist/es/vector/lag.js.map +1 -1
  89. package/dist/es/vector/lead.js +1 -1
  90. package/dist/es/vector/lead.js.map +1 -1
  91. package/dist/es/vector/roll.js +1 -1
  92. package/dist/es/vector/roll.js.map +1 -1
  93. package/dist/es/vector/rowNumber.js.map +1 -1
  94. package/dist/es/when.js +1 -2
  95. package/dist/es/when.js.map +1 -1
  96. package/dist/lib/addRows.js +0 -2
  97. package/dist/lib/addRows.js.map +1 -1
  98. package/dist/lib/arrange.js +9 -7
  99. package/dist/lib/arrange.js.map +1 -1
  100. package/dist/lib/complete.js +0 -2
  101. package/dist/lib/complete.js.map +1 -1
  102. package/dist/lib/count.js +6 -4
  103. package/dist/lib/count.js.map +1 -1
  104. package/dist/lib/debug.js +4 -4
  105. package/dist/lib/debug.js.map +1 -1
  106. package/dist/lib/distinct.js +3 -5
  107. package/dist/lib/distinct.js.map +1 -1
  108. package/dist/lib/expand.js +18 -15
  109. package/dist/lib/expand.js.map +1 -1
  110. package/dist/lib/fill.js +10 -5
  111. package/dist/lib/fill.js.map +1 -1
  112. package/dist/lib/filter.js +0 -2
  113. package/dist/lib/filter.js.map +1 -1
  114. package/dist/lib/fullJoin.js +22 -21
  115. package/dist/lib/fullJoin.js.map +1 -1
  116. package/dist/lib/groupBy.js +56 -30
  117. package/dist/lib/groupBy.js.map +1 -1
  118. package/dist/lib/helpers/assignGroupKeys.js +4 -6
  119. package/dist/lib/helpers/assignGroupKeys.js.map +1 -1
  120. package/dist/lib/helpers/groupMap.js +2 -4
  121. package/dist/lib/helpers/groupMap.js.map +1 -1
  122. package/dist/lib/helpers/groupTraversal.js +5 -6
  123. package/dist/lib/helpers/groupTraversal.js.map +1 -1
  124. package/dist/lib/helpers/identity.js +0 -2
  125. package/dist/lib/helpers/identity.js.map +1 -1
  126. package/dist/lib/helpers/isObject.js +0 -2
  127. package/dist/lib/helpers/isObject.js.map +1 -1
  128. package/dist/lib/helpers/keysFromItems.js +1 -4
  129. package/dist/lib/helpers/keysFromItems.js.map +1 -1
  130. package/dist/lib/helpers/singleOrArray.js +0 -2
  131. package/dist/lib/helpers/singleOrArray.js.map +1 -1
  132. package/dist/lib/helpers/summation.js +10 -4
  133. package/dist/lib/helpers/summation.js.map +1 -1
  134. package/dist/lib/index.js +0 -2
  135. package/dist/lib/index.js.map +1 -1
  136. package/dist/lib/innerJoin.js +38 -14
  137. package/dist/lib/innerJoin.js.map +1 -1
  138. package/dist/lib/item/rate.js +2 -5
  139. package/dist/lib/item/rate.js.map +1 -1
  140. package/dist/lib/leftJoin.js +12 -9
  141. package/dist/lib/leftJoin.js.map +1 -1
  142. package/dist/lib/map.js +0 -2
  143. package/dist/lib/map.js.map +1 -1
  144. package/dist/lib/math/math.js +0 -2
  145. package/dist/lib/math/math.js.map +1 -1
  146. package/dist/lib/mutate.js +1 -3
  147. package/dist/lib/mutate.js.map +1 -1
  148. package/dist/lib/mutateWithSummary.js +1 -3
  149. package/dist/lib/mutateWithSummary.js.map +1 -1
  150. package/dist/lib/pivotLonger.js +31 -9
  151. package/dist/lib/pivotLonger.js.map +1 -1
  152. package/dist/lib/pivotWider.js +24 -21
  153. package/dist/lib/pivotWider.js.map +1 -1
  154. package/dist/lib/rename.js +0 -2
  155. package/dist/lib/rename.js.map +1 -1
  156. package/dist/lib/replaceNully.js +1 -3
  157. package/dist/lib/replaceNully.js.map +1 -1
  158. package/dist/lib/select.js +3 -5
  159. package/dist/lib/select.js.map +1 -1
  160. package/dist/lib/selectors/contains.js +0 -2
  161. package/dist/lib/selectors/contains.js.map +1 -1
  162. package/dist/lib/selectors/endsWith.js +0 -2
  163. package/dist/lib/selectors/endsWith.js.map +1 -1
  164. package/dist/lib/selectors/everything.js +0 -2
  165. package/dist/lib/selectors/everything.js.map +1 -1
  166. package/dist/lib/selectors/matches.js +0 -2
  167. package/dist/lib/selectors/matches.js.map +1 -1
  168. package/dist/lib/selectors/negate.js +2 -4
  169. package/dist/lib/selectors/negate.js.map +1 -1
  170. package/dist/lib/selectors/numRange.js +0 -2
  171. package/dist/lib/selectors/numRange.js.map +1 -1
  172. package/dist/lib/selectors/startsWith.js +0 -2
  173. package/dist/lib/selectors/startsWith.js.map +1 -1
  174. package/dist/lib/sequences/fullSeq.js +5 -3
  175. package/dist/lib/sequences/fullSeq.js.map +1 -1
  176. package/dist/lib/slice.js +2 -5
  177. package/dist/lib/slice.js.map +1 -1
  178. package/dist/lib/summarize.js +6 -6
  179. package/dist/lib/summarize.js.map +1 -1
  180. package/dist/lib/summary/deviation.js +0 -2
  181. package/dist/lib/summary/deviation.js.map +1 -1
  182. package/dist/lib/summary/first.js +0 -2
  183. package/dist/lib/summary/first.js.map +1 -1
  184. package/dist/lib/summary/last.js +0 -2
  185. package/dist/lib/summary/last.js.map +1 -1
  186. package/dist/lib/summary/max.js +0 -2
  187. package/dist/lib/summary/max.js.map +1 -1
  188. package/dist/lib/summary/mean.js +0 -2
  189. package/dist/lib/summary/mean.js.map +1 -1
  190. package/dist/lib/summary/meanRate.js +0 -2
  191. package/dist/lib/summary/meanRate.js.map +1 -1
  192. package/dist/lib/summary/median.js +0 -2
  193. package/dist/lib/summary/median.js.map +1 -1
  194. package/dist/lib/summary/min.js +0 -2
  195. package/dist/lib/summary/min.js.map +1 -1
  196. package/dist/lib/summary/n.js +0 -2
  197. package/dist/lib/summary/n.js.map +1 -1
  198. package/dist/lib/summary/nDistinct.js +2 -4
  199. package/dist/lib/summary/nDistinct.js.map +1 -1
  200. package/dist/lib/summary/sum.js +0 -2
  201. package/dist/lib/summary/sum.js.map +1 -1
  202. package/dist/lib/summary/variance.js +0 -2
  203. package/dist/lib/summary/variance.js.map +1 -1
  204. package/dist/lib/tally.js +4 -4
  205. package/dist/lib/tally.js.map +1 -1
  206. package/dist/lib/tidy.js +0 -2
  207. package/dist/lib/tidy.js.map +1 -1
  208. package/dist/lib/total.js +0 -2
  209. package/dist/lib/total.js.map +1 -1
  210. package/dist/lib/transmute.js +0 -2
  211. package/dist/lib/transmute.js.map +1 -1
  212. package/dist/lib/vector/cumsum.js +0 -2
  213. package/dist/lib/vector/cumsum.js.map +1 -1
  214. package/dist/lib/vector/lag.js +1 -3
  215. package/dist/lib/vector/lag.js.map +1 -1
  216. package/dist/lib/vector/lead.js +1 -3
  217. package/dist/lib/vector/lead.js.map +1 -1
  218. package/dist/lib/vector/roll.js +1 -3
  219. package/dist/lib/vector/roll.js.map +1 -1
  220. package/dist/lib/vector/rowNumber.js +0 -2
  221. package/dist/lib/vector/rowNumber.js.map +1 -1
  222. package/dist/lib/when.js +1 -4
  223. package/dist/lib/when.js.map +1 -1
  224. package/dist/tidy.d.ts +217 -1775
  225. package/dist/umd/tidy.js +307 -184
  226. package/dist/umd/tidy.js.map +1 -1
  227. package/dist/umd/tidy.min.js +1 -1
  228. package/dist/umd/tidy.min.js.map +1 -1
  229. package/package.json +14 -9
  230. package/LICENSE +0 -21
@@ -1 +1 @@
1
- {"version":3,"file":"assignGroupKeys.js","sources":["../../../src/helpers/assignGroupKeys.ts"],"sourcesContent":["import { GroupKey } from '../types';\n\n/**\n * Given an object and a set of group keys [[keyName, keyValue], ...]\n * set the keys as properties within the object: { [keyName]: keyValue, ... }\n * (creates a new object with these properties added)\n */\nexport function assignGroupKeys<T extends object>(d: T, keys: GroupKey[]) {\n // abort if atypical input\n if (d == null || typeof d !== 'object' || Array.isArray(d)) return d;\n\n // transform to { groupKey1: value, ... } excluding function group keys\n const keysObj = Object.fromEntries(\n keys.filter((key) => typeof key[0] !== 'function' && key[0] != null)\n );\n\n return Object.assign(keysObj, d);\n}\n"],"names":[],"mappings":";;;;yBAOkD,GAAM;AAEtD,MAAI,KAAK,QAAQ,OAAO,MAAM,YAAY,MAAM,QAAQ;AAAI,WAAO;AAGnE,QAAM,UAAU,OAAO,YACrB,KAAK,OAAO,CAAC,QAAQ,OAAO,IAAI,OAAO,cAAc,IAAI,MAAM;AAGjE,SAAO,OAAO,OAAO,SAAS;AAAA;;;;"}
1
+ {"version":3,"file":"assignGroupKeys.js","sources":["../../../src/helpers/assignGroupKeys.ts"],"sourcesContent":["import { GroupKey } from '../types';\n\n/**\n * Given an object and a set of group keys [[keyName, keyValue], ...]\n * set the keys as properties within the object: { [keyName]: keyValue, ... }\n * (creates a new object with these properties added)\n */\nexport function assignGroupKeys<T extends object>(\n d: T,\n keys: GroupKey[],\n filteredKeys?: GroupKey[]\n) {\n // abort if atypical input\n if (d == null || typeof d !== 'object' || Array.isArray(d)) return d;\n\n // use pre-filtered keys if provided, otherwise filter here\n const validKeys =\n filteredKeys ??\n keys.filter((key) => typeof key[0] !== 'function' && key[0] != null);\n\n // transform to { groupKey1: value, ... } excluding function group keys\n const keysObj = Object.fromEntries(validKeys);\n\n return Object.assign(keysObj, d);\n}\n"],"names":[],"mappings":";;AAOgB,SAAA,eAAA,CACd,CACA,EAAA,IAAA,EACA,YACA,EAAA;AAEA,EAAI,IAAA,CAAA,IAAK,QAAQ,OAAO,CAAA,KAAM,YAAY,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA,EAAU,OAAA,CAAA,CAAA;AAGnE,EAAA,MAAM,SACJ,GAAA,YAAA,IAAA,IAAA,GAAA,YAAA,GACA,IAAK,CAAA,MAAA,CAAO,CAAC,GAAQ,KAAA,OAAO,GAAI,CAAA,CAAC,CAAM,KAAA,UAAA,IAAc,GAAI,CAAA,CAAC,KAAK,IAAI,CAAA,CAAA;AAGrE,EAAM,MAAA,OAAA,GAAU,MAAO,CAAA,WAAA,CAAY,SAAS,CAAA,CAAA;AAE5C,EAAO,OAAA,MAAA,CAAO,MAAO,CAAA,OAAA,EAAS,CAAC,CAAA,CAAA;AACjC;;;;"}
@@ -1,19 +1,17 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var groupTraversal = require('./groupTraversal.js');
6
4
 
7
5
  function groupMap(grouped, groupFn, keyFn = (keys) => keys[keys.length - 1]) {
8
6
  function addSubgroup(parentGrouped, keys) {
9
- const subgroup = new Map();
7
+ const subgroup = /* @__PURE__ */ new Map();
10
8
  parentGrouped.set(keyFn(keys), subgroup);
11
9
  return subgroup;
12
10
  }
13
11
  function addLeaves(parentGrouped, keys, values) {
14
12
  parentGrouped.set(keyFn(keys), groupFn(values, keys));
15
13
  }
16
- const outputGrouped = new Map();
14
+ const outputGrouped = /* @__PURE__ */ new Map();
17
15
  groupTraversal.groupTraversal(grouped, outputGrouped, [], addSubgroup, addLeaves);
18
16
  return outputGrouped;
19
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"groupMap.js","sources":["../../../src/helpers/groupMap.ts"],"sourcesContent":["import { Grouped } from '../types';\nimport { groupTraversal } from './groupTraversal';\n\nexport function groupMap<T extends object, OutputT extends object = T>(\n grouped: Grouped<T>,\n groupFn: (items: T[], keys: any[]) => OutputT[],\n keyFn: (keys: any[]) => any = (keys) =>\n keys[\n keys.length - 1\n ] /* optional func to transform key based on all keys in map so far */\n): Grouped<OutputT> {\n function addSubgroup(parentGrouped: Grouped<OutputT>, keys: any[]) {\n const subgroup = new Map();\n parentGrouped.set(keyFn(keys), subgroup);\n return subgroup;\n }\n\n function addLeaves(\n parentGrouped: Grouped<OutputT>,\n keys: any[],\n values: T[]\n ) {\n parentGrouped.set(keyFn(keys), groupFn(values, keys));\n }\n\n const outputGrouped: Grouped<OutputT> = new Map();\n\n groupTraversal(grouped, outputGrouped, [], addSubgroup, addLeaves);\n\n return outputGrouped;\n}\n"],"names":[],"mappings":";;;;;;kBAIE,SACA,SACA,QAA8B,CAAC,SAC7B,KACE,KAAK,SAAS;AAGlB,uBAAqB,eAAiC;AACpD,UAAM,WAAW,IAAI;AACrB,kBAAc,IAAI,MAAM,OAAO;AAC/B,WAAO;AAAA;AAGT,qBACE,eACA,MACA;AAEA,kBAAc,IAAI,MAAM,OAAO,QAAQ,QAAQ;AAAA;AAGjD,QAAM,gBAAkC,IAAI;AAE5C,gCAAe,SAAS,eAAe,IAAI,aAAa;AAExD,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"groupMap.js","sources":["../../../src/helpers/groupMap.ts"],"sourcesContent":["import { Grouped } from '../types';\nimport { groupTraversal } from './groupTraversal';\n\nexport function groupMap<T extends object, OutputT extends object = T>(\n grouped: Grouped<T>,\n groupFn: (items: T[], keys: any[]) => OutputT[],\n keyFn: (keys: any[]) => any = (keys) =>\n keys[\n keys.length - 1\n ] /* optional func to transform key based on all keys in map so far */\n): Grouped<OutputT> {\n function addSubgroup(parentGrouped: Grouped<OutputT>, keys: any[]) {\n const subgroup = new Map();\n parentGrouped.set(keyFn(keys), subgroup);\n return subgroup;\n }\n\n function addLeaves(\n parentGrouped: Grouped<OutputT>,\n keys: any[],\n values: T[]\n ) {\n parentGrouped.set(keyFn(keys), groupFn(values, keys));\n }\n\n const outputGrouped: Grouped<OutputT> = new Map();\n\n groupTraversal(grouped, outputGrouped, [], addSubgroup, addLeaves);\n\n return outputGrouped;\n}\n"],"names":["groupTraversal"],"mappings":";;;;AAGgB,SAAA,QAAA,CACd,OACA,EAAA,OAAA,EACA,KAA8B,GAAA,CAAC,SAC7B,IACE,CAAA,IAAA,CAAK,MAAS,GAAA,CAChB,CACgB,EAAA;AAClB,EAAS,SAAA,WAAA,CAAY,eAAiC,IAAa,EAAA;AACjE,IAAM,MAAA,QAAA,uBAAe,GAAI,EAAA,CAAA;AACzB,IAAA,aAAA,CAAc,GAAI,CAAA,KAAA,CAAM,IAAI,CAAA,EAAG,QAAQ,CAAA,CAAA;AACvC,IAAO,OAAA,QAAA,CAAA;AAAA,GACT;AAEA,EAAS,SAAA,SAAA,CACP,aACA,EAAA,IAAA,EACA,MACA,EAAA;AACA,IAAA,aAAA,CAAc,IAAI,KAAM,CAAA,IAAI,GAAG,OAAQ,CAAA,MAAA,EAAQ,IAAI,CAAC,CAAA,CAAA;AAAA,GACtD;AAEA,EAAM,MAAA,aAAA,uBAAsC,GAAI,EAAA,CAAA;AAEhD,EAAAA,6BAAA,CAAe,OAAS,EAAA,aAAA,EAAe,EAAC,EAAG,aAAa,SAAS,CAAA,CAAA;AAEjE,EAAO,OAAA,aAAA,CAAA;AACT;;;;"}
@@ -1,16 +1,15 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function groupTraversal(grouped, outputGrouped, keys, addSubgroup, addLeaves, level = 0) {
6
4
  for (const [key, value] of grouped.entries()) {
7
- const keysHere = [...keys, key];
5
+ keys.push(key);
8
6
  if (value instanceof Map) {
9
- const subgroup = addSubgroup(outputGrouped, keysHere, level);
10
- groupTraversal(value, subgroup, keysHere, addSubgroup, addLeaves, level + 1);
7
+ const subgroup = addSubgroup(outputGrouped, keys, level);
8
+ groupTraversal(value, subgroup, keys, addSubgroup, addLeaves, level + 1);
11
9
  } else {
12
- addLeaves(outputGrouped, keysHere, value, level);
10
+ addLeaves(outputGrouped, keys, value, level);
13
11
  }
12
+ keys.pop();
14
13
  }
15
14
  return outputGrouped;
16
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"groupTraversal.js","sources":["../../../src/helpers/groupTraversal.ts"],"sourcesContent":["import { Grouped, Datum } from '../types';\n\n/**\n * Traverse the leaves of the grouped items and and run the\n * groupFn on them. Basically an in-order traversal. Can you\n * believe this is real and not part of a coding interview??\n */\nexport function groupTraversal<\n T extends object,\n T2 extends Datum = T,\n OutputType = Grouped<T2>\n>(\n grouped: Grouped<T>,\n outputGrouped: OutputType,\n keys: any[],\n addSubgroup: (root: OutputType, keys: any[], level: number) => OutputType,\n addLeaves: (root: OutputType, keys: any[], items: T[], level: number) => void,\n level: number = 0\n) {\n for (const [key, value] of grouped.entries()) {\n const keysHere = [...keys, key];\n\n // internal node\n if (value instanceof Map) {\n const subgroup = addSubgroup(outputGrouped, keysHere, level);\n\n // recurse\n groupTraversal(\n value,\n subgroup,\n keysHere,\n addSubgroup,\n addLeaves,\n level + 1\n );\n } else {\n // leaf\n addLeaves(outputGrouped, keysHere, value, level);\n }\n }\n\n return outputGrouped;\n}\n"],"names":[],"mappings":";;;;wBAYE,SACA,eACA,MACA,aACA,WACA,QAAgB;AAEhB,aAAW,CAAC,KAAK,UAAU,QAAQ;AACjC,UAAM,WAAW,CAAC,GAAG,MAAM;AAG3B,QAAI,iBAAiB;AACnB,YAAM,WAAW,YAAY,eAAe,UAAU;AAGtD,qBACE,OACA,UACA,UACA,aACA,WACA,QAAQ;AAAA;AAIV,gBAAU,eAAe,UAAU,OAAO;AAAA;AAAA;AAI9C,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"groupTraversal.js","sources":["../../../src/helpers/groupTraversal.ts"],"sourcesContent":["import { Grouped, Datum } from '../types';\n\n/**\n * Traverse the leaves of the grouped items and and run the\n * groupFn on them. Basically an in-order traversal. Can you\n * believe this is real and not part of a coding interview??\n */\nexport function groupTraversal<\n T extends object,\n T2 extends Datum = T,\n OutputType = Grouped<T2>\n>(\n grouped: Grouped<T>,\n outputGrouped: OutputType,\n keys: any[],\n addSubgroup: (root: OutputType, keys: any[], level: number) => OutputType,\n addLeaves: (root: OutputType, keys: any[], items: T[], level: number) => void,\n level: number = 0\n) {\n for (const [key, value] of grouped.entries()) {\n keys.push(key);\n\n // internal node\n if (value instanceof Map) {\n const subgroup = addSubgroup(outputGrouped, keys, level);\n\n // recurse\n groupTraversal(value, subgroup, keys, addSubgroup, addLeaves, level + 1);\n } else {\n // leaf\n addLeaves(outputGrouped, keys, value, level);\n }\n\n keys.pop();\n }\n\n return outputGrouped;\n}\n"],"names":[],"mappings":";;AAOO,SAAS,eAKd,OACA,EAAA,aAAA,EACA,MACA,WACA,EAAA,SAAA,EACA,QAAgB,CAChB,EAAA;AACA,EAAA,KAAA,MAAW,CAAC,GAAK,EAAA,KAAK,CAAK,IAAA,OAAA,CAAQ,SAAW,EAAA;AAC5C,IAAA,IAAA,CAAK,KAAK,GAAG,CAAA,CAAA;AAGb,IAAA,IAAI,iBAAiB,GAAK,EAAA;AACxB,MAAA,MAAM,QAAW,GAAA,WAAA,CAAY,aAAe,EAAA,IAAA,EAAM,KAAK,CAAA,CAAA;AAGvD,MAAA,cAAA,CAAe,OAAO,QAAU,EAAA,IAAA,EAAM,WAAa,EAAA,SAAA,EAAW,QAAQ,CAAC,CAAA,CAAA;AAAA,KAClE,MAAA;AAEL,MAAU,SAAA,CAAA,aAAA,EAAe,IAAM,EAAA,KAAA,EAAO,KAAK,CAAA,CAAA;AAAA,KAC7C;AAEA,IAAA,IAAA,CAAK,GAAI,EAAA,CAAA;AAAA,GACX;AAEA,EAAO,OAAA,aAAA,CAAA;AACT;;;;"}
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  const identity = (d) => d;
6
4
 
7
5
  exports.identity = identity;
@@ -1 +1 @@
1
- {"version":3,"file":"identity.js","sources":["../../../src/helpers/identity.ts"],"sourcesContent":["export const identity = <T>(d: T): T => d;\n"],"names":[],"mappings":";;;;MAAa,WAAW,CAAI,MAAY;;;;"}
1
+ {"version":3,"file":"identity.js","sources":["../../../src/helpers/identity.ts"],"sourcesContent":["export const identity = <T>(d: T): T => d;\n"],"names":[],"mappings":";;AAAa,MAAA,QAAA,GAAW,CAAI,CAAY,KAAA;;;;"}
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function isObject(obj) {
6
4
  const type = typeof obj;
7
5
  return obj != null && (type === "object" || type === "function");
@@ -1 +1 @@
1
- {"version":3,"file":"isObject.js","sources":["../../../src/helpers/isObject.ts"],"sourcesContent":["/**\n * Returns true if input is an object\n */\nexport function isObject(obj: any) {\n const type = typeof obj;\n return obj != null && (type === 'object' || type === 'function');\n}\n"],"names":[],"mappings":";;;;kBAGyB;AACvB,QAAM,OAAO,OAAO;AACpB,SAAO,OAAO,kBAAkB,YAAY,SAAS;AAAA;;;;"}
1
+ {"version":3,"file":"isObject.js","sources":["../../../src/helpers/isObject.ts"],"sourcesContent":["/**\n * Returns true if input is an object\n */\nexport function isObject(obj: any) {\n const type = typeof obj;\n return obj != null && (type === 'object' || type === 'function');\n}\n"],"names":[],"mappings":";;AAGO,SAAS,SAAS,GAAU,EAAA;AACjC,EAAA,MAAM,OAAO,OAAO,GAAA,CAAA;AACpB,EAAA,OAAO,GAAO,IAAA,IAAA,KAAS,IAAS,KAAA,QAAA,IAAY,IAAS,KAAA,UAAA,CAAA,CAAA;AACvD;;;;"}
@@ -1,10 +1,7 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function keysFromItems(items) {
6
- if (items.length < 1)
7
- return [];
4
+ if (items.length < 1) return [];
8
5
  const keys = Object.keys(items[0]);
9
6
  return keys;
10
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"keysFromItems.js","sources":["../../../src/helpers/keysFromItems.ts"],"sourcesContent":["/**\n * Helper to get keys from a collection of items.\n * For now, it naively just looks at the first item, but a more complete\n * solution involves looking at all of them (in case keys are omitted).\n * This isn't very efficient though, so perhaps there's a future where\n * the keys are stored sneakily on the object somewhere and that set\n * is updated after each tidy fn is called (if we can do it efficiently)\n *\n * Or perhaps this function can be memoized in a smart way where we don't\n * call it more than necessary?\n */\nexport function keysFromItems<T extends object>(items: T[]): (keyof T)[] {\n if (items.length < 1) return [];\n const keys = Object.keys(items[0]) as (keyof T)[];\n return keys;\n}\n"],"names":[],"mappings":";;;;uBAWgD;AAC9C,MAAI,MAAM,SAAS;AAAG,WAAO;AAC7B,QAAM,OAAO,OAAO,KAAK,MAAM;AAC/B,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"keysFromItems.js","sources":["../../../src/helpers/keysFromItems.ts"],"sourcesContent":["/**\n * Helper to get keys from a collection of items.\n * For now, it naively just looks at the first item, but a more complete\n * solution involves looking at all of them (in case keys are omitted).\n * This isn't very efficient though, so perhaps there's a future where\n * the keys are stored sneakily on the object somewhere and that set\n * is updated after each tidy fn is called (if we can do it efficiently)\n *\n * Or perhaps this function can be memoized in a smart way where we don't\n * call it more than necessary?\n */\nexport function keysFromItems<T extends object>(items: T[]): (keyof T)[] {\n if (items.length < 1) return [];\n const keys = Object.keys(items[0]) as (keyof T)[];\n return keys;\n}\n"],"names":[],"mappings":";;AAWO,SAAS,cAAgC,KAAyB,EAAA;AACvE,EAAA,IAAI,KAAM,CAAA,MAAA,GAAS,CAAG,EAAA,OAAO,EAAC,CAAA;AAC9B,EAAA,MAAM,IAAO,GAAA,MAAA,CAAO,IAAK,CAAA,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AACjC,EAAO,OAAA,IAAA,CAAA;AACT;;;;"}
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function singleOrArray(d) {
6
4
  return d == null ? [] : Array.isArray(d) ? d : [d];
7
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"singleOrArray.js","sources":["../../../src/helpers/singleOrArray.ts"],"sourcesContent":["export type SingleOrArray<T> = T | T[];\n\n/**\n * Given an arg that may or may not be an array, make it an array if it isn't one.\n */\nexport function singleOrArray<T>(d: SingleOrArray<T> | null | undefined): T[] {\n return d == null ? [] : Array.isArray(d) ? d : [d];\n}\n"],"names":[],"mappings":";;;;uBAKiC;AAC/B,SAAO,KAAK,OAAO,KAAK,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA;;;;"}
1
+ {"version":3,"file":"singleOrArray.js","sources":["../../../src/helpers/singleOrArray.ts"],"sourcesContent":["export type SingleOrArray<T> = T | T[];\n\n/**\n * Given an arg that may or may not be an array, make it an array if it isn't one.\n */\nexport function singleOrArray<T>(d: SingleOrArray<T> | null | undefined): T[] {\n return d == null ? [] : Array.isArray(d) ? d : [d];\n}\n"],"names":[],"mappings":";;AAKO,SAAS,cAAiB,CAA6C,EAAA;AAC5E,EAAO,OAAA,CAAA,IAAK,IAAO,GAAA,EAAK,GAAA,KAAA,CAAM,QAAQ,CAAC,CAAA,GAAI,CAAI,GAAA,CAAC,CAAC,CAAA,CAAA;AACnD;;;;"}
@@ -1,22 +1,28 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var d3Array = require('d3-array');
6
4
 
7
5
  function fcumsum(items, accessor) {
8
6
  let sum = new d3Array.Adder(), i = 0;
9
- return Float64Array.from(items, (value) => sum.add(+(accessor(value, i++, items) || 0)));
7
+ return Float64Array.from(
8
+ items,
9
+ // we do not actually need to coerce the Adder to number,
10
+ // as @Fil demonstrated here: https://github.com/pbeshai/tidy/pull/5
11
+ // so we can just tell typescript to be quiet.
12
+ (value) => sum.add(+(accessor(value, i++, items) || 0))
13
+ );
10
14
  }
11
15
  function mean(items, accessor) {
12
16
  let n = 0;
17
+ const sum = new d3Array.Adder();
13
18
  for (let i = 0; i < items.length; ++i) {
14
19
  const value = accessor(items[i], i, items);
15
20
  if (+value === value) {
21
+ sum.add(+value);
16
22
  n += 1;
17
23
  }
18
24
  }
19
- return n ? d3Array.fsum(items, accessor) / n : void 0;
25
+ return n ? +sum / n : void 0;
20
26
  }
21
27
 
22
28
  exports.fcumsum = fcumsum;
@@ -1 +1 @@
1
- {"version":3,"file":"summation.js","sources":["../../../src/helpers/summation.ts"],"sourcesContent":["import { fsum, Adder } from 'd3-array';\n\n// See also https://observablehq.com/@fil/fcumsum\nexport function fcumsum<T>(\n items: T[],\n accessor: (element: T, i: number, array: Iterable<T>) => any\n): Float64Array {\n let sum = new Adder(),\n i = 0;\n\n return Float64Array.from(\n items,\n // we do not actually need to coerce the Adder to number,\n // as @Fil demonstrated here: https://github.com/pbeshai/tidy/pull/5\n // so we can just tell typescript to be quiet.\n (value: T): number =>\n (sum.add(+(accessor(value, i++, items) || 0)) as unknown) as number\n );\n}\n\nexport function mean<T>(\n items: T[],\n accessor: (element: T, i: number, array: Iterable<T>) => any\n): number | undefined {\n let n = 0;\n for (let i = 0; i < items.length; ++i) {\n const value = accessor(items[i], i, items);\n // count it if we have a valid number\n if (+value === value) {\n n += 1;\n }\n }\n\n return n ? fsum(items, accessor) / n : undefined;\n}\n"],"names":["Adder","fsum"],"mappings":";;;;;;iBAIE,OACA;AAEA,MAAI,MAAM,IAAIA,iBACZ,IAAI;AAEN,SAAO,aAAa,KAClB,OAIA,CAAC,UACE,IAAI,IAAI,WAAW,OAAO,KAAK,UAAU;AAAA;cAK9C,OACA;AAEA,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,EAAE;AAClC,UAAM,QAAQ,SAAS,MAAM,IAAI,GAAG;AAEpC,QAAI,CAAC,UAAU;AACb,WAAK;AAAA;AAAA;AAIT,SAAO,IAAIC,aAAK,OAAO,YAAY,IAAI;AAAA;;;;;"}
1
+ {"version":3,"file":"summation.js","sources":["../../../src/helpers/summation.ts"],"sourcesContent":["import { Adder } from 'd3-array';\n\n// See also https://observablehq.com/@fil/fcumsum\nexport function fcumsum<T>(\n items: T[],\n accessor: (element: T, i: number, array: Iterable<T>) => any\n): Float64Array {\n let sum = new Adder(),\n i = 0;\n\n return Float64Array.from(\n items,\n // we do not actually need to coerce the Adder to number,\n // as @Fil demonstrated here: https://github.com/pbeshai/tidy/pull/5\n // so we can just tell typescript to be quiet.\n (value: T): number =>\n sum.add(+(accessor(value, i++, items) || 0)) as unknown as number\n );\n}\n\nexport function mean<T>(\n items: T[],\n accessor: (element: T, i: number, array: Iterable<T>) => any\n): number | undefined {\n let n = 0;\n const sum = new Adder();\n for (let i = 0; i < items.length; ++i) {\n const value = accessor(items[i], i, items);\n // count it if we have a valid number\n if (+value === value) {\n sum.add(+value);\n n += 1;\n }\n }\n\n return n ? +sum / n : undefined;\n}\n"],"names":["Adder"],"mappings":";;;;AAGgB,SAAA,OAAA,CACd,OACA,QACc,EAAA;AACd,EAAA,IAAI,GAAM,GAAA,IAAIA,aAAM,EAAA,EAClB,CAAI,GAAA,CAAA,CAAA;AAEN,EAAA,OAAO,YAAa,CAAA,IAAA;AAAA,IAClB,KAAA;AAAA;AAAA;AAAA;AAAA,IAIA,CAAC,KACC,KAAA,GAAA,CAAI,GAAI,CAAA,EAAE,SAAS,KAAO,EAAA,CAAA,EAAA,EAAK,KAAK,CAAA,IAAK,CAAE,CAAA,CAAA;AAAA,GAC/C,CAAA;AACF,CAAA;AAEgB,SAAA,IAAA,CACd,OACA,QACoB,EAAA;AACpB,EAAA,IAAI,CAAI,GAAA,CAAA,CAAA;AACR,EAAM,MAAA,GAAA,GAAM,IAAIA,aAAM,EAAA,CAAA;AACtB,EAAA,KAAA,IAAS,IAAI,CAAG,EAAA,CAAA,GAAI,KAAM,CAAA,MAAA,EAAQ,EAAE,CAAG,EAAA;AACrC,IAAA,MAAM,QAAQ,QAAS,CAAA,KAAA,CAAM,CAAC,CAAA,EAAG,GAAG,KAAK,CAAA,CAAA;AAEzC,IAAI,IAAA,CAAC,UAAU,KAAO,EAAA;AACpB,MAAI,GAAA,CAAA,GAAA,CAAI,CAAC,KAAK,CAAA,CAAA;AACd,MAAK,CAAA,IAAA,CAAA,CAAA;AAAA,KACP;AAAA,GACF;AAEA,EAAO,OAAA,CAAA,GAAI,CAAC,GAAA,GAAM,CAAI,GAAA,KAAA,CAAA,CAAA;AACxB;;;;;"}
package/dist/lib/index.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var tidy = require('./tidy.js');
6
4
  var filter = require('./filter.js');
7
5
  var when = require('./when.js');
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,10 +1,7 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function autodetectByMap(itemsA, itemsB) {
6
- if (itemsA.length === 0 || itemsB.length === 0)
7
- return {};
4
+ if (itemsA.length === 0 || itemsB.length === 0) return {};
8
5
  const keysA = Object.keys(itemsA[0]);
9
6
  const keysB = Object.keys(itemsB[0]);
10
7
  const byMap = {};
@@ -25,23 +22,49 @@ function makeByMap(by) {
25
22
  } else if (typeof by === "object") {
26
23
  return by;
27
24
  }
28
- return {[by]: by};
25
+ return { [by]: by };
26
+ }
27
+ const KEY_DELIMITER = "\0";
28
+ const NULL_SENTINEL = "N";
29
+ const UNDEF_SENTINEL = "U";
30
+ function serializeValue(v) {
31
+ if (v === null) return NULL_SENTINEL;
32
+ if (v === void 0) return UNDEF_SENTINEL;
33
+ return String(v);
34
+ }
35
+ function computeKey(row, keys) {
36
+ if (keys.length === 1) return serializeValue(row[keys[0]]);
37
+ let key = "";
38
+ for (let i = 0; i < keys.length; i++) {
39
+ if (i > 0) key += KEY_DELIMITER;
40
+ key += serializeValue(row[keys[i]]);
41
+ }
42
+ return key;
29
43
  }
30
- function isMatch(d, j, byMap) {
31
- for (const jKey in byMap) {
32
- const dKey = byMap[jKey];
33
- if (d[dKey] !== j[jKey]) {
34
- return false;
44
+ function buildJoinIndex(itemsToJoin, joinKeys) {
45
+ const index = /* @__PURE__ */ new Map();
46
+ for (const j of itemsToJoin) {
47
+ const key = computeKey(j, joinKeys);
48
+ let bucket = index.get(key);
49
+ if (bucket === void 0) {
50
+ bucket = [];
51
+ index.set(key, bucket);
35
52
  }
53
+ bucket.push(j);
36
54
  }
37
- return true;
55
+ return index;
38
56
  }
39
57
  function innerJoin(itemsToJoin, options) {
40
58
  const _innerJoin = (items) => {
41
59
  const byMap = (options == null ? void 0 : options.by) == null ? autodetectByMap(items, itemsToJoin) : makeByMap(options.by);
60
+ const joinKeys = Object.keys(byMap);
61
+ const itemKeys = joinKeys.map((jKey) => byMap[jKey]);
62
+ const index = buildJoinIndex(itemsToJoin, joinKeys);
42
63
  const joined = items.flatMap((d) => {
43
- const matches = itemsToJoin.filter((j) => isMatch(d, j, byMap));
44
- return matches.map((j) => ({...d, ...j}));
64
+ const key = computeKey(d, itemKeys);
65
+ const matches = index.get(key);
66
+ if (matches === void 0) return [];
67
+ return matches.map((j) => ({ ...d, ...j }));
45
68
  });
46
69
  return joined;
47
70
  };
@@ -49,7 +72,8 @@ function innerJoin(itemsToJoin, options) {
49
72
  }
50
73
 
51
74
  exports.autodetectByMap = autodetectByMap;
75
+ exports.buildJoinIndex = buildJoinIndex;
76
+ exports.computeKey = computeKey;
52
77
  exports.innerJoin = innerJoin;
53
- exports.isMatch = isMatch;
54
78
  exports.makeByMap = makeByMap;
55
79
  //# sourceMappingURL=innerJoin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"innerJoin.js","sources":["../../src/innerJoin.ts"],"sourcesContent":["import { O } from 'ts-toolbelt';\nimport { TidyFn, Datum } from './types';\n\ntype ByMap<JoinT extends Datum, T extends Datum> = Partial<\n Record<keyof JoinT, keyof T>\n>;\n\nexport type JoinOptions<JoinT extends Datum, T extends Datum> = {\n by?: keyof T | (keyof T)[] | ByMap<JoinT, T>;\n};\n\n/**\n * Compares first two sets of items to find overlapping keys\n * Naively looks at first element... could cause problems if first\n * elements don't have all keys, but scanning each entire set seems\n * unnecessarily slow for most cases.\n */\nexport function autodetectByMap<A, B>(itemsA: A[], itemsB: B[]) {\n if (itemsA.length === 0 || itemsB.length === 0) return {};\n\n // intersection of shared keys\n const keysA = Object.keys(itemsA[0]);\n const keysB = Object.keys(itemsB[0]);\n\n // naive linear intersection, but we don't expect objects to have tons of keys\n // so it's probably fine.\n const byMap: any = {};\n for (const key of keysA) {\n if (keysB.includes(key)) {\n byMap[key] = key;\n }\n }\n\n return byMap;\n}\n\n// convert by option in to a map from JoinT to T key\nexport function makeByMap<T extends Datum, JoinT extends Datum>(\n by: JoinOptions<JoinT, T>['by']\n): ByMap<JoinT, T> {\n // convert by option in to a map from JoinT to T key\n if (Array.isArray(by)) {\n const byMap: ByMap<JoinT, T> = {};\n for (const key of by) {\n byMap[key as any] = key;\n }\n return byMap;\n } else if (typeof by === 'object') {\n return by;\n }\n return { [by as keyof JoinT]: by as keyof T } as ByMap<JoinT, T>;\n}\n\nexport function isMatch<T extends object, JoinT extends object>(\n d: T,\n j: JoinT,\n byMap: ByMap<JoinT, T>\n) {\n for (const jKey in byMap) {\n const dKey = byMap[jKey];\n if ((d[dKey as keyof T] as any) !== j[jKey as keyof JoinT]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Performs an inner join on two collections\n * @param itemsToJoin The rows/items to be appended to end of collection\n */\nexport function innerJoin<T extends object, JoinT extends object>(\n itemsToJoin: JoinT[],\n options?: JoinOptions<JoinT, T> | null | undefined\n): TidyFn<T, O.Merge<T, JoinT>> {\n const _innerJoin: TidyFn<T, O.Merge<T, JoinT>> = (\n items: T[]\n ): O.Merge<T, JoinT>[] => {\n // convert by option in to a map from JoinT to T key\n const byMap =\n options?.by == null\n ? autodetectByMap(items, itemsToJoin)\n : makeByMap(options.by);\n\n const joined = items.flatMap((d: T) => {\n const matches = itemsToJoin.filter((j: JoinT) => isMatch(d, j, byMap));\n return matches.map((j: JoinT) => ({ ...d, ...j }));\n });\n\n return joined as O.Merge<T, JoinT>[];\n };\n return _innerJoin;\n}\n"],"names":[],"mappings":";;;;yBAiBsC,QAAa;AACjD,MAAI,OAAO,WAAW,KAAK,OAAO,WAAW;AAAG,WAAO;AAGvD,QAAM,QAAQ,OAAO,KAAK,OAAO;AACjC,QAAM,QAAQ,OAAO,KAAK,OAAO;AAIjC,QAAM,QAAa;AACnB,aAAW,OAAO;AAChB,QAAI,MAAM,SAAS;AACjB,YAAM,OAAO;AAAA;AAAA;AAIjB,SAAO;AAAA;mBAKP;AAGA,MAAI,MAAM,QAAQ;AAChB,UAAM,QAAyB;AAC/B,eAAW,OAAO;AAChB,YAAM,OAAc;AAAA;AAEtB,WAAO;AAAA,aACE,OAAO,OAAO;AACvB,WAAO;AAAA;AAET,SAAO,EAAG,KAAoB;AAAA;iBAI9B,GACA,GACA;AAEA,aAAW,QAAQ;AACjB,UAAM,OAAO,MAAM;AACnB,QAAK,EAAE,UAA6B,EAAE;AACpC,aAAO;AAAA;AAAA;AAGX,SAAO;AAAA;mBAQP,aACA;AAEA,QAAM,aAA2C,CAC/C;AAGA,UAAM,QACJ,oCAAS,OAAM,OACX,gBAAgB,OAAO,eACvB,UAAU,QAAQ;AAExB,UAAM,SAAS,MAAM,QAAQ,CAAC;AAC5B,YAAM,UAAU,YAAY,OAAO,CAAC,MAAa,QAAQ,GAAG,GAAG;AAC/D,aAAO,QAAQ,IAAI,CAAC,WAAmB,MAAM;AAAA;AAG/C,WAAO;AAAA;AAET,SAAO;AAAA;;;;;;;"}
1
+ {"version":3,"file":"innerJoin.js","sources":["../../src/innerJoin.ts"],"sourcesContent":["import { TidyFn, Datum } from './types';\nimport { Merge } from './type-utils';\n\ntype ByMap<JoinT extends Datum, T extends Datum> = Partial<\n Record<keyof JoinT, keyof T>\n>;\n\nexport type JoinOptions<JoinT extends Datum, T extends Datum> = {\n by?: keyof T | (keyof T)[] | ByMap<JoinT, T>;\n};\n\n/**\n * Compares first two sets of items to find overlapping keys\n * Naively looks at first element... could cause problems if first\n * elements don't have all keys, but scanning each entire set seems\n * unnecessarily slow for most cases.\n */\nexport function autodetectByMap<A extends object, B extends object>(\n itemsA: A[],\n itemsB: B[]\n) {\n if (itemsA.length === 0 || itemsB.length === 0) return {};\n\n // intersection of shared keys\n const keysA = Object.keys(itemsA[0]);\n const keysB = Object.keys(itemsB[0]);\n\n // naive linear intersection, but we don't expect objects to have tons of keys\n // so it's probably fine.\n const byMap: any = {};\n for (const key of keysA) {\n if (keysB.includes(key)) {\n byMap[key] = key;\n }\n }\n\n return byMap;\n}\n\n// convert by option in to a map from JoinT to T key\nexport function makeByMap<T extends Datum, JoinT extends Datum>(\n by: JoinOptions<JoinT, T>['by']\n): ByMap<JoinT, T> {\n // convert by option in to a map from JoinT to T key\n if (Array.isArray(by)) {\n const byMap: ByMap<JoinT, T> = {};\n for (const key of by) {\n byMap[key as any] = key;\n }\n return byMap;\n } else if (typeof by === 'object') {\n return by;\n }\n return { [by as keyof JoinT]: by as keyof T } as ByMap<JoinT, T>;\n}\n\nexport function isMatch<T extends object, JoinT extends object>(\n d: T,\n j: JoinT,\n byMap: ByMap<JoinT, T>\n) {\n for (const jKey in byMap) {\n const dKey = byMap[jKey];\n if ((d[dKey as keyof T] as any) !== j[jKey as keyof JoinT]) {\n return false;\n }\n }\n return true;\n}\n\nconst KEY_DELIMITER = '\\x00';\nconst NULL_SENTINEL = '\\x01N';\nconst UNDEF_SENTINEL = '\\x01U';\n\nfunction serializeValue(v: any): string {\n if (v === null) return NULL_SENTINEL;\n if (v === undefined) return UNDEF_SENTINEL;\n return String(v);\n}\n\nexport function computeKey(row: any, keys: string[]): string {\n if (keys.length === 1) return serializeValue(row[keys[0]]);\n let key = '';\n for (let i = 0; i < keys.length; i++) {\n if (i > 0) key += KEY_DELIMITER;\n key += serializeValue(row[keys[i]]);\n }\n return key;\n}\n\nexport function buildJoinIndex<JoinT extends object>(\n itemsToJoin: JoinT[],\n joinKeys: string[]\n): Map<string, JoinT[]> {\n const index = new Map<string, JoinT[]>();\n for (const j of itemsToJoin) {\n const key = computeKey(j, joinKeys);\n let bucket = index.get(key);\n if (bucket === undefined) {\n bucket = [];\n index.set(key, bucket);\n }\n bucket.push(j);\n }\n return index;\n}\n\n/**\n * Performs an inner join on two collections\n * @param itemsToJoin The rows/items to be appended to end of collection\n */\nexport function innerJoin<T extends object, JoinT extends object>(\n itemsToJoin: JoinT[],\n options?: JoinOptions<JoinT, T> | null | undefined\n): TidyFn<T, Merge<T, JoinT>> {\n const _innerJoin: TidyFn<T, Merge<T, JoinT>> = (\n items: T[]\n ): Merge<T, JoinT>[] => {\n // convert by option in to a map from JoinT to T key\n const byMap =\n options?.by == null\n ? autodetectByMap(items, itemsToJoin)\n : makeByMap(options.by);\n\n const joinKeys = Object.keys(byMap);\n const itemKeys = joinKeys.map((jKey) => byMap[jKey] as string);\n const index = buildJoinIndex(itemsToJoin, joinKeys);\n\n const joined = items.flatMap((d: T) => {\n const key = computeKey(d, itemKeys);\n const matches = index.get(key);\n if (matches === undefined) return [];\n return matches.map((j: JoinT) => ({ ...d, ...j }));\n });\n\n return joined as Merge<T, JoinT>[];\n };\n return _innerJoin;\n}\n"],"names":[],"mappings":";;AAiBgB,SAAA,eAAA,CACd,QACA,MACA,EAAA;AACA,EAAA,IAAI,OAAO,MAAW,KAAA,CAAA,IAAK,OAAO,MAAW,KAAA,CAAA,SAAU,EAAC,CAAA;AAGxD,EAAA,MAAM,KAAQ,GAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA;AACnC,EAAA,MAAM,KAAQ,GAAA,MAAA,CAAO,IAAK,CAAA,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA;AAInC,EAAA,MAAM,QAAa,EAAC,CAAA;AACpB,EAAA,KAAA,MAAW,OAAO,KAAO,EAAA;AACvB,IAAI,IAAA,KAAA,CAAM,QAAS,CAAA,GAAG,CAAG,EAAA;AACvB,MAAA,KAAA,CAAM,GAAG,CAAI,GAAA,GAAA,CAAA;AAAA,KACf;AAAA,GACF;AAEA,EAAO,OAAA,KAAA,CAAA;AACT,CAAA;AAGO,SAAS,UACd,EACiB,EAAA;AAEjB,EAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,EAAE,CAAG,EAAA;AACrB,IAAA,MAAM,QAAyB,EAAC,CAAA;AAChC,IAAA,KAAA,MAAW,OAAO,EAAI,EAAA;AACpB,MAAA,KAAA,CAAM,GAAU,CAAI,GAAA,GAAA,CAAA;AAAA,KACtB;AACA,IAAO,OAAA,KAAA,CAAA;AAAA,GACT,MAAA,IAAW,OAAO,EAAA,KAAO,QAAU,EAAA;AACjC,IAAO,OAAA,EAAA,CAAA;AAAA,GACT;AACA,EAAA,OAAO,EAAE,CAAC,EAAiB,GAAG,EAAc,EAAA,CAAA;AAC9C,CAAA;AAgBA,MAAM,aAAgB,GAAA,IAAA,CAAA;AACtB,MAAM,aAAgB,GAAA,IAAA,CAAA;AACtB,MAAM,cAAiB,GAAA,IAAA,CAAA;AAEvB,SAAS,eAAe,CAAgB,EAAA;AACtC,EAAI,IAAA,CAAA,KAAM,MAAa,OAAA,aAAA,CAAA;AACvB,EAAI,IAAA,CAAA,KAAM,QAAkB,OAAA,cAAA,CAAA;AAC5B,EAAA,OAAO,OAAO,CAAC,CAAA,CAAA;AACjB,CAAA;AAEgB,SAAA,UAAA,CAAW,KAAU,IAAwB,EAAA;AAC3D,EAAI,IAAA,IAAA,CAAK,WAAW,CAAG,EAAA,OAAO,eAAe,GAAI,CAAA,IAAA,CAAK,CAAC,CAAC,CAAC,CAAA,CAAA;AACzD,EAAA,IAAI,GAAM,GAAA,EAAA,CAAA;AACV,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,IAAA,CAAK,QAAQ,CAAK,EAAA,EAAA;AACpC,IAAI,IAAA,CAAA,GAAI,GAAU,GAAA,IAAA,aAAA,CAAA;AAClB,IAAA,GAAA,IAAO,cAAe,CAAA,GAAA,CAAI,IAAK,CAAA,CAAC,CAAC,CAAC,CAAA,CAAA;AAAA,GACpC;AACA,EAAO,OAAA,GAAA,CAAA;AACT,CAAA;AAEgB,SAAA,cAAA,CACd,aACA,QACsB,EAAA;AACtB,EAAM,MAAA,KAAA,uBAAY,GAAqB,EAAA,CAAA;AACvC,EAAA,KAAA,MAAW,KAAK,WAAa,EAAA;AAC3B,IAAM,MAAA,GAAA,GAAM,UAAW,CAAA,CAAA,EAAG,QAAQ,CAAA,CAAA;AAClC,IAAI,IAAA,MAAA,GAAS,KAAM,CAAA,GAAA,CAAI,GAAG,CAAA,CAAA;AAC1B,IAAA,IAAI,WAAW,KAAW,CAAA,EAAA;AACxB,MAAA,MAAA,GAAS,EAAC,CAAA;AACV,MAAM,KAAA,CAAA,GAAA,CAAI,KAAK,MAAM,CAAA,CAAA;AAAA,KACvB;AACA,IAAA,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAAA,GACf;AACA,EAAO,OAAA,KAAA,CAAA;AACT,CAAA;AAMgB,SAAA,SAAA,CACd,aACA,OAC4B,EAAA;AAC5B,EAAM,MAAA,UAAA,GAAyC,CAC7C,KACsB,KAAA;AAEtB,IAAM,MAAA,KAAA,GAAA,CACJ,OAAS,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAA,EAAA,KAAM,IACX,GAAA,eAAA,CAAgB,OAAO,WAAW,CAAA,GAClC,SAAU,CAAA,OAAA,CAAQ,EAAE,CAAA,CAAA;AAE1B,IAAM,MAAA,QAAA,GAAW,MAAO,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAClC,IAAA,MAAM,WAAW,QAAS,CAAA,GAAA,CAAI,CAAC,IAAS,KAAA,KAAA,CAAM,IAAI,CAAW,CAAA,CAAA;AAC7D,IAAM,MAAA,KAAA,GAAQ,cAAe,CAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAElD,IAAA,MAAM,MAAS,GAAA,KAAA,CAAM,OAAQ,CAAA,CAAC,CAAS,KAAA;AACrC,MAAM,MAAA,GAAA,GAAM,UAAW,CAAA,CAAA,EAAG,QAAQ,CAAA,CAAA;AAClC,MAAM,MAAA,OAAA,GAAU,KAAM,CAAA,GAAA,CAAI,GAAG,CAAA,CAAA;AAC7B,MAAI,IAAA,OAAA,KAAY,KAAW,CAAA,EAAA,OAAO,EAAC,CAAA;AACnC,MAAO,OAAA,OAAA,CAAQ,IAAI,CAAC,CAAA,MAAc,EAAE,GAAG,CAAA,EAAG,GAAG,CAAA,EAAI,CAAA,CAAA,CAAA;AAAA,KAClD,CAAA,CAAA;AAED,IAAO,OAAA,MAAA,CAAA;AAAA,GACT,CAAA;AACA,EAAO,OAAA,UAAA,CAAA;AACT;;;;;;;;"}
@@ -1,20 +1,17 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var math = require('../math/math.js');
6
4
 
7
5
  function rate(numerator, denominator, options) {
8
6
  const numeratorFn = typeof numerator === "function" ? numerator : (d) => d[numerator];
9
7
  const denominatorFn = typeof denominator === "function" ? denominator : (d) => d[denominator];
10
- const {predicate, allowDivideByZero} = options != null ? options : {};
8
+ const { predicate, allowDivideByZero } = options != null ? options : {};
11
9
  return predicate == null ? (d, index, array) => {
12
10
  const denom = denominatorFn(d, index, array);
13
11
  const numer = numeratorFn(d, index, array);
14
12
  return math.rate(numer, denom, allowDivideByZero);
15
13
  } : (d, index, array) => {
16
- if (!predicate(d, index, array))
17
- return void 0;
14
+ if (!predicate(d, index, array)) return void 0;
18
15
  const denom = denominatorFn(d, index, array);
19
16
  const numer = numeratorFn(d, index, array);
20
17
  return math.rate(numer, denom, allowDivideByZero);
@@ -1 +1 @@
1
- {"version":3,"file":"rate.js","sources":["../../../src/item/rate.ts"],"sourcesContent":["import { rate as mathRate } from '../math/math';\n\ntype RateOptions<T> = {\n predicate?: (d: T, index: number, array: Iterable<T>) => boolean;\n allowDivideByZero?: boolean;\n};\n\n/**\n * Returns a function that computes a rate (numerator / denominator), setting the value to\n * 0 if denominator = 0 and numerator = 0.\n */\nexport function rate<T extends object>(\n numerator: keyof T | ((d: T, index: number, array: Iterable<T>) => number),\n denominator: keyof T | ((d: T, index: number, array: Iterable<T>) => number),\n options?: RateOptions<T>\n) {\n const numeratorFn =\n typeof numerator === 'function'\n ? numerator\n : (d: T) => (d[numerator] as unknown) as number;\n const denominatorFn =\n typeof denominator === 'function'\n ? denominator\n : (d: T) => (d[denominator] as unknown) as number;\n\n const { predicate, allowDivideByZero } = options ?? {};\n return predicate == null\n ? (d: T, index: number, array: Iterable<T>) => {\n const denom = denominatorFn(d, index, array);\n const numer = numeratorFn(d, index, array);\n return mathRate(numer, denom, allowDivideByZero);\n }\n : (d: T, index: number, array: Iterable<T>) => {\n if (!predicate(d, index, array)) return undefined;\n\n const denom = denominatorFn(d, index, array);\n const numer = numeratorFn(d, index, array);\n return mathRate(numer, denom, allowDivideByZero);\n };\n}\n"],"names":["mathRate"],"mappings":";;;;;;cAYE,WACA,aACA;AAEA,QAAM,cACJ,OAAO,cAAc,aACjB,YACA,CAAC,MAAU,EAAE;AACnB,QAAM,gBACJ,OAAO,gBAAgB,aACnB,cACA,CAAC,MAAU,EAAE;AAEnB,QAAM,CAAE,WAAW,qBAAsB,4BAAW;AACpD,SAAO,aAAa,OAChB,CAAC,GAAM,OAAe;AACpB,UAAM,QAAQ,cAAc,GAAG,OAAO;AACtC,UAAM,QAAQ,YAAY,GAAG,OAAO;AACpC,WAAOA,UAAS,OAAO,OAAO;AAAA,MAEhC,CAAC,GAAM,OAAe;AACpB,QAAI,CAAC,UAAU,GAAG,OAAO;AAAQ,aAAO;AAExC,UAAM,QAAQ,cAAc,GAAG,OAAO;AACtC,UAAM,QAAQ,YAAY,GAAG,OAAO;AACpC,WAAOA,UAAS,OAAO,OAAO;AAAA;AAAA;;;;"}
1
+ {"version":3,"file":"rate.js","sources":["../../../src/item/rate.ts"],"sourcesContent":["import { rate as mathRate } from '../math/math';\n\ntype RateOptions<T> = {\n predicate?: (d: T, index: number, array: Iterable<T>) => boolean;\n allowDivideByZero?: boolean;\n};\n\n/**\n * Returns a function that computes a rate (numerator / denominator), setting the value to\n * 0 if denominator = 0 and numerator = 0.\n */\nexport function rate<T extends object>(\n numerator: keyof T | ((d: T, index: number, array: Iterable<T>) => number),\n denominator: keyof T | ((d: T, index: number, array: Iterable<T>) => number),\n options?: RateOptions<T>\n) {\n const numeratorFn =\n typeof numerator === 'function'\n ? numerator\n : (d: T) => d[numerator] as unknown as number;\n const denominatorFn =\n typeof denominator === 'function'\n ? denominator\n : (d: T) => d[denominator] as unknown as number;\n\n const { predicate, allowDivideByZero } = options ?? {};\n return predicate == null\n ? (d: T, index: number, array: Iterable<T>) => {\n const denom = denominatorFn(d, index, array);\n const numer = numeratorFn(d, index, array);\n return mathRate(numer, denom, allowDivideByZero);\n }\n : (d: T, index: number, array: Iterable<T>) => {\n if (!predicate(d, index, array)) return undefined;\n\n const denom = denominatorFn(d, index, array);\n const numer = numeratorFn(d, index, array);\n return mathRate(numer, denom, allowDivideByZero);\n };\n}\n"],"names":["mathRate"],"mappings":";;;;AAWgB,SAAA,IAAA,CACd,SACA,EAAA,WAAA,EACA,OACA,EAAA;AACA,EAAM,MAAA,WAAA,GACJ,OAAO,SAAc,KAAA,UAAA,GACjB,YACA,CAAC,CAAA,KAAS,EAAE,SAAS,CAAA,CAAA;AAC3B,EAAM,MAAA,aAAA,GACJ,OAAO,WAAgB,KAAA,UAAA,GACnB,cACA,CAAC,CAAA,KAAS,EAAE,WAAW,CAAA,CAAA;AAE7B,EAAA,MAAM,EAAE,SAAA,EAAW,iBAAkB,EAAA,GAAI,4BAAW,EAAC,CAAA;AACrD,EAAA,OAAO,SAAa,IAAA,IAAA,GAChB,CAAC,CAAA,EAAM,OAAe,KAAuB,KAAA;AAC3C,IAAA,MAAM,KAAQ,GAAA,aAAA,CAAc,CAAG,EAAA,KAAA,EAAO,KAAK,CAAA,CAAA;AAC3C,IAAA,MAAM,KAAQ,GAAA,WAAA,CAAY,CAAG,EAAA,KAAA,EAAO,KAAK,CAAA,CAAA;AACzC,IAAO,OAAAA,SAAA,CAAS,KAAO,EAAA,KAAA,EAAO,iBAAiB,CAAA,CAAA;AAAA,GAEjD,GAAA,CAAC,CAAM,EAAA,KAAA,EAAe,KAAuB,KAAA;AAC3C,IAAA,IAAI,CAAC,SAAU,CAAA,CAAA,EAAG,KAAO,EAAA,KAAK,GAAU,OAAA,KAAA,CAAA,CAAA;AAExC,IAAA,MAAM,KAAQ,GAAA,aAAA,CAAc,CAAG,EAAA,KAAA,EAAO,KAAK,CAAA,CAAA;AAC3C,IAAA,MAAM,KAAQ,GAAA,WAAA,CAAY,CAAG,EAAA,KAAA,EAAO,KAAK,CAAA,CAAA;AACzC,IAAO,OAAAA,SAAA,CAAS,KAAO,EAAA,KAAA,EAAO,iBAAiB,CAAA,CAAA;AAAA,GACjD,CAAA;AACN;;;;"}
@@ -1,22 +1,25 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var innerJoin = require('./innerJoin.js');
6
4
 
7
5
  function leftJoin(itemsToJoin, options) {
8
6
  const _leftJoin = (items) => {
9
- if (!itemsToJoin.length)
10
- return items;
7
+ if (!itemsToJoin.length) return items;
11
8
  const byMap = (options == null ? void 0 : options.by) == null ? innerJoin.autodetectByMap(items, itemsToJoin) : innerJoin.makeByMap(options.by);
9
+ const joinKeys = Object.keys(byMap);
10
+ const itemKeys = joinKeys.map((jKey) => byMap[jKey]);
11
+ const index = innerJoin.buildJoinIndex(itemsToJoin, joinKeys);
12
12
  const joinObjectKeys = Object.keys(itemsToJoin[0]);
13
13
  const joined = items.flatMap((d) => {
14
- const matches = itemsToJoin.filter((j) => innerJoin.isMatch(d, j, byMap));
15
- if (matches.length) {
16
- return matches.map((j) => ({...d, ...j}));
14
+ const key = innerJoin.computeKey(d, itemKeys);
15
+ const matches = index.get(key);
16
+ if (matches !== void 0) {
17
+ return matches.map((j) => ({ ...d, ...j }));
17
18
  }
18
- const undefinedFill = Object.fromEntries(joinObjectKeys.filter((key) => d[key] == null).map((key) => [key, void 0]));
19
- return {...d, ...undefinedFill};
19
+ const undefinedFill = Object.fromEntries(
20
+ joinObjectKeys.filter((key2) => d[key2] == null).map((key2) => [key2, void 0])
21
+ );
22
+ return { ...d, ...undefinedFill };
20
23
  });
21
24
  return joined;
22
25
  };
@@ -1 +1 @@
1
- {"version":3,"file":"leftJoin.js","sources":["../../src/leftJoin.ts"],"sourcesContent":["import { Datum, TidyFn } from './types';\nimport { isMatch, makeByMap, autodetectByMap, JoinOptions } from './innerJoin';\nimport { O } from 'ts-toolbelt';\n\n/**\n * Performs a left join on two collections\n * @param itemsToJoin The rows/items to be appended to end of collection\n */\nexport function leftJoin<T extends Datum, JoinT extends Datum>(\n itemsToJoin: JoinT[],\n options?: JoinOptions<JoinT, T> | null | undefined\n): TidyFn<T, O.Merge<T, Partial<JoinT>>> {\n const _leftJoin: TidyFn<T, O.Merge<T, Partial<JoinT>>> = (\n items: T[]\n ): O.Merge<T, Partial<JoinT>>[] => {\n if (!itemsToJoin.length) return items as any;\n\n // convert by option in to a map from T key to JoinT key\n const byMap =\n options?.by == null\n ? autodetectByMap(items, itemsToJoin)\n : makeByMap(options.by);\n\n // when we miss a join, we want to explicitly add in undefined\n // so our rows all have the same keys. get those keys here.\n const joinObjectKeys = Object.keys(itemsToJoin[0]);\n\n const joined = items.flatMap((d: T) => {\n const matches = itemsToJoin.filter((j: JoinT) => isMatch(d, j, byMap));\n if (matches.length) {\n return matches.map((j: JoinT) => ({ ...d, ...j }));\n }\n\n // add in missing keys explicitly as undefined without\n // overriding existing values and while maintaining order\n // of keys\n const undefinedFill = Object.fromEntries(\n joinObjectKeys\n .filter((key) => d[key] == null)\n .map((key) => [key, undefined])\n );\n\n return { ...d, ...undefinedFill };\n });\n\n return joined;\n };\n return _leftJoin;\n}\n"],"names":["autodetectByMap","makeByMap","isMatch"],"mappings":";;;;;;kBASE,aACA;AAEA,QAAM,YAAmD,CACvD;AAEA,QAAI,CAAC,YAAY;AAAQ,aAAO;AAGhC,UAAM,QACJ,oCAAS,OAAM,OACXA,0BAAgB,OAAO,eACvBC,oBAAU,QAAQ;AAIxB,UAAM,iBAAiB,OAAO,KAAK,YAAY;AAE/C,UAAM,SAAS,MAAM,QAAQ,CAAC;AAC5B,YAAM,UAAU,YAAY,OAAO,CAAC,MAAaC,kBAAQ,GAAG,GAAG;AAC/D,UAAI,QAAQ;AACV,eAAO,QAAQ,IAAI,CAAC,WAAmB,MAAM;AAAA;AAM/C,YAAM,gBAAgB,OAAO,YAC3B,eACG,OAAO,CAAC,QAAQ,EAAE,QAAQ,MAC1B,IAAI,CAAC,QAAQ,CAAC,KAAK;AAGxB,aAAO,IAAK,MAAM;AAAA;AAGpB,WAAO;AAAA;AAET,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"leftJoin.js","sources":["../../src/leftJoin.ts"],"sourcesContent":["import { Datum, TidyFn } from './types';\nimport {\n makeByMap,\n autodetectByMap,\n JoinOptions,\n buildJoinIndex,\n computeKey,\n} from './innerJoin';\nimport { Merge } from './type-utils';\n\n/**\n * Performs a left join on two collections\n * @param itemsToJoin The rows/items to be appended to end of collection\n */\nexport function leftJoin<T extends Datum, JoinT extends Datum>(\n itemsToJoin: JoinT[],\n options?: JoinOptions<JoinT, T> | null | undefined\n): TidyFn<T, Merge<T, Partial<JoinT>>> {\n const _leftJoin: TidyFn<T, Merge<T, Partial<JoinT>>> = (\n items: T[]\n ): Merge<T, Partial<JoinT>>[] => {\n if (!itemsToJoin.length) return items as any;\n\n // convert by option in to a map from T key to JoinT key\n const byMap =\n options?.by == null\n ? autodetectByMap(items, itemsToJoin)\n : makeByMap(options.by);\n\n const joinKeys = Object.keys(byMap);\n const itemKeys = joinKeys.map((jKey) => byMap[jKey] as string);\n const index = buildJoinIndex(itemsToJoin, joinKeys);\n\n // when we miss a join, we want to explicitly add in undefined\n // so our rows all have the same keys. get those keys here.\n const joinObjectKeys = Object.keys(itemsToJoin[0]);\n\n const joined = items.flatMap((d: T) => {\n const key = computeKey(d, itemKeys);\n const matches = index.get(key);\n if (matches !== undefined) {\n return matches.map((j: JoinT) => ({ ...d, ...j }));\n }\n\n // add in missing keys explicitly as undefined without\n // overriding existing values and while maintaining order\n // of keys\n const undefinedFill = Object.fromEntries(\n joinObjectKeys\n .filter((key) => d[key] == null)\n .map((key) => [key, undefined])\n );\n\n return { ...d, ...undefinedFill };\n });\n\n return joined;\n };\n return _leftJoin;\n}\n"],"names":["autodetectByMap","makeByMap","buildJoinIndex","computeKey","key"],"mappings":";;;;AAcgB,SAAA,QAAA,CACd,aACA,OACqC,EAAA;AACrC,EAAM,MAAA,SAAA,GAAiD,CACrD,KAC+B,KAAA;AAC/B,IAAI,IAAA,CAAC,WAAY,CAAA,MAAA,EAAe,OAAA,KAAA,CAAA;AAGhC,IAAM,MAAA,KAAA,GAAA,CACJ,OAAS,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,OAAA,CAAA,EAAA,KAAM,IACX,GAAAA,yBAAA,CAAgB,OAAO,WAAW,CAAA,GAClCC,mBAAU,CAAA,OAAA,CAAQ,EAAE,CAAA,CAAA;AAE1B,IAAM,MAAA,QAAA,GAAW,MAAO,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAClC,IAAA,MAAM,WAAW,QAAS,CAAA,GAAA,CAAI,CAAC,IAAS,KAAA,KAAA,CAAM,IAAI,CAAW,CAAA,CAAA;AAC7D,IAAM,MAAA,KAAA,GAAQC,wBAAe,CAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AAIlD,IAAA,MAAM,cAAiB,GAAA,MAAA,CAAO,IAAK,CAAA,WAAA,CAAY,CAAC,CAAC,CAAA,CAAA;AAEjD,IAAA,MAAM,MAAS,GAAA,KAAA,CAAM,OAAQ,CAAA,CAAC,CAAS,KAAA;AACrC,MAAM,MAAA,GAAA,GAAMC,oBAAW,CAAA,CAAA,EAAG,QAAQ,CAAA,CAAA;AAClC,MAAM,MAAA,OAAA,GAAU,KAAM,CAAA,GAAA,CAAI,GAAG,CAAA,CAAA;AAC7B,MAAA,IAAI,YAAY,KAAW,CAAA,EAAA;AACzB,QAAO,OAAA,OAAA,CAAQ,IAAI,CAAC,CAAA,MAAc,EAAE,GAAG,CAAA,EAAG,GAAG,CAAA,EAAI,CAAA,CAAA,CAAA;AAAA,OACnD;AAKA,MAAA,MAAM,gBAAgB,MAAO,CAAA,WAAA;AAAA,QAC3B,cACG,CAAA,MAAA,CAAO,CAACC,IAAAA,KAAQ,EAAEA,IAAG,CAAA,IAAK,IAAI,CAAA,CAC9B,IAAI,CAACA,IAAAA,KAAQ,CAACA,IAAAA,EAAK,MAAS,CAAC,CAAA;AAAA,OAClC,CAAA;AAEA,MAAA,OAAO,EAAE,GAAG,CAAG,EAAA,GAAG,aAAc,EAAA,CAAA;AAAA,KACjC,CAAA,CAAA;AAED,IAAO,OAAA,MAAA,CAAA;AAAA,GACT,CAAA;AACA,EAAO,OAAA,SAAA,CAAA;AACT;;;;"}
package/dist/lib/map.js CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function map(mapFn) {
6
4
  const _map = (items) => items.map(mapFn);
7
5
  return _map;
@@ -1 +1 @@
1
- {"version":3,"file":"map.js","sources":["../../src/map.ts"],"sourcesContent":["import { TidyFn } from './types';\n\n/**\n * Maps items\n * @param mapFn Maps items from one form to another\n */\nexport function map<T extends object, OutputT>(\n mapFn: (item: T, index: number, array: T[]) => OutputT\n): TidyFn<T, OutputT> {\n const _map: TidyFn<T, OutputT> = (items: T[]) => items.map(mapFn);\n return _map;\n}\n"],"names":[],"mappings":";;;;aAOE;AAEA,QAAM,OAA2B,CAAC,UAAe,MAAM,IAAI;AAC3D,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"map.js","sources":["../../src/map.ts"],"sourcesContent":["import { TidyFn } from './types';\n\n/**\n * Maps items\n * @param mapFn Maps items from one form to another\n */\nexport function map<T extends object, OutputT>(\n mapFn: (item: T, index: number, array: T[]) => OutputT\n): TidyFn<T, OutputT> {\n const _map: TidyFn<T, OutputT> = (items: T[]) => items.map(mapFn);\n return _map;\n}\n"],"names":[],"mappings":";;AAMO,SAAS,IACd,KACoB,EAAA;AACpB,EAAA,MAAM,IAA2B,GAAA,CAAC,KAAe,KAAA,KAAA,CAAM,IAAI,KAAK,CAAA,CAAA;AAChE,EAAO,OAAA,IAAA,CAAA;AACT;;;;"}
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function rate(numerator, denominator, allowDivideByZero) {
6
4
  return numerator == null || denominator == null ? void 0 : denominator === 0 && numerator === 0 ? 0 : !allowDivideByZero && denominator === 0 ? void 0 : numerator / denominator;
7
5
  }
@@ -1 +1 @@
1
- {"version":3,"file":"math.js","sources":["../../../src/math/math.ts"],"sourcesContent":["/** Tidy math helpers */\n\n/** Compute a fraction while handling common edge cases */\nexport function rate(\n numerator: number | null | undefined,\n denominator: number | null | undefined,\n allowDivideByZero?: boolean\n): number | undefined {\n return numerator == null || denominator == null\n ? undefined\n : denominator === 0 && numerator === 0\n ? 0\n : !allowDivideByZero && denominator === 0\n ? undefined\n : numerator / denominator;\n}\n\nexport function subtract(\n a: number | null | undefined,\n b: number | null | undefined,\n nullyZero?: boolean\n) {\n return a == null || b == null\n ? nullyZero\n ? (a ?? 0) - (b ?? 0)\n : undefined\n : a - b;\n}\n\nexport function add(\n a: number | null | undefined,\n b: number | null | undefined,\n nullyZero?: boolean\n) {\n return a == null || b == null\n ? nullyZero\n ? (a ?? 0) + (b ?? 0)\n : undefined\n : a + b;\n}\n"],"names":[],"mappings":";;;;cAIE,WACA,aACA;AAEA,SAAO,aAAa,QAAQ,eAAe,OACvC,SACA,gBAAgB,KAAK,cAAc,IACnC,IACA,CAAC,qBAAqB,gBAAgB,IACtC,SACA,YAAY;AAAA;kBAIhB,GACA,GACA;AAEA,SAAO,KAAK,QAAQ,KAAK,OACrB,YACG,iBAAK,sBAAW,KACjB,SACF,IAAI;AAAA;aAIR,GACA,GACA;AAEA,SAAO,KAAK,QAAQ,KAAK,OACrB,YACG,iBAAK,sBAAW,KACjB,SACF,IAAI;AAAA;;;;;;"}
1
+ {"version":3,"file":"math.js","sources":["../../../src/math/math.ts"],"sourcesContent":["/** Tidy math helpers */\n\n/** Compute a fraction while handling common edge cases */\nexport function rate(\n numerator: number | null | undefined,\n denominator: number | null | undefined,\n allowDivideByZero?: boolean\n): number | undefined {\n return numerator == null || denominator == null\n ? undefined\n : denominator === 0 && numerator === 0\n ? 0\n : !allowDivideByZero && denominator === 0\n ? undefined\n : numerator / denominator;\n}\n\nexport function subtract(\n a: number | null | undefined,\n b: number | null | undefined,\n nullyZero?: boolean\n) {\n return a == null || b == null\n ? nullyZero\n ? (a ?? 0) - (b ?? 0)\n : undefined\n : a - b;\n}\n\nexport function add(\n a: number | null | undefined,\n b: number | null | undefined,\n nullyZero?: boolean\n) {\n return a == null || b == null\n ? nullyZero\n ? (a ?? 0) + (b ?? 0)\n : undefined\n : a + b;\n}\n"],"names":[],"mappings":";;AAGgB,SAAA,IAAA,CACd,SACA,EAAA,WAAA,EACA,iBACoB,EAAA;AACpB,EAAA,OAAO,SAAa,IAAA,IAAA,IAAQ,WAAe,IAAA,IAAA,GACvC,SACA,WAAgB,KAAA,CAAA,IAAK,SAAc,KAAA,CAAA,GACnC,IACA,CAAC,iBAAA,IAAqB,WAAgB,KAAA,CAAA,GACtC,SACA,SAAY,GAAA,WAAA,CAAA;AAClB,CAAA;AAEgB,SAAA,QAAA,CACd,CACA,EAAA,CAAA,EACA,SACA,EAAA;AACA,EAAO,OAAA,CAAA,IAAK,IAAQ,IAAA,CAAA,IAAK,IACrB,GAAA,SAAA,GAAA,CACG,gBAAK,CAAM,KAAA,CAAA,IAAA,IAAA,GAAA,CAAA,GAAK,CACjB,CAAA,GAAA,KAAA,CAAA,GACF,CAAI,GAAA,CAAA,CAAA;AACV,CAAA;AAEgB,SAAA,GAAA,CACd,CACA,EAAA,CAAA,EACA,SACA,EAAA;AACA,EAAO,OAAA,CAAA,IAAK,IAAQ,IAAA,CAAA,IAAK,IACrB,GAAA,SAAA,GAAA,CACG,gBAAK,CAAM,KAAA,CAAA,IAAA,IAAA,GAAA,CAAA,GAAK,CACjB,CAAA,GAAA,KAAA,CAAA,GACF,CAAI,GAAA,CAAA,CAAA;AACV;;;;;;"}
@@ -1,10 +1,8 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function mutate(mutateSpec) {
6
4
  const _mutate = (items) => {
7
- const mutatedItems = items.map((d) => ({...d}));
5
+ const mutatedItems = items.map((d) => ({ ...d }));
8
6
  let i = 0;
9
7
  for (const mutatedItem of mutatedItems) {
10
8
  for (const key in mutateSpec) {
@@ -1 +1 @@
1
- {"version":3,"file":"mutate.js","sources":["../../src/mutate.ts"],"sourcesContent":["import { TidyFn, NonFunctionValue, Key } from './types';\nimport { A, O } from 'ts-toolbelt';\n\ntype MutateSpecValue<T, O = any> =\n | ((item: T, index: number, array: Iterable<T>) => O)\n | NonFunctionValue;\nexport type MutateSpec<T> = Record<Key, MutateSpecValue<T>>;\nexport type ResolvedObj<Obj extends Record<Key, MutateSpecValue<any>>> = {\n [K in keyof Obj]: Obj[K] extends (...args: any) => any\n ? ReturnType<Obj[K]> extends any[]\n ? ReturnType<Obj[K]>[number]\n : ReturnType<Obj[K]>\n : Obj[K];\n};\n\ntype Mutated<T extends object, MSpec extends MutateSpec<T>> = O.Merge<\n ResolvedObj<MSpec>,\n T\n>;\n\ntype Compute<T> = A.Compute<T>;\n\n/**\n * Mutates items, one item at a time. For mutating across multiple items,\n * use mutateWithSummary.\n * @param mutateSpec\n */\nexport function mutate<T extends object, MSpec extends MutateSpec<T>>(\n mutateSpec: MSpec\n): TidyFn<T, Compute<Mutated<T, MSpec>>> {\n type MutatedT = Mutated<T, MSpec>;\n // use Compute for better intellisense (reveals all keys in obj)\n const _mutate: TidyFn<T, Compute<MutatedT>> = (\n items: T[]\n ): Compute<MutatedT>[] => {\n // create the base items to merge mutated values into\n // note we start with the original array so when we pass it as the third argument\n // to a mutate function, you get the values that have been changed so far\n const mutatedItems: MutatedT[] = items.map((d) => ({ ...d })) as MutatedT[];\n\n // we can update each item completely one at a time, since mutate doesn't\n // support looking across items. Use mutateWithSummary for that.\n let i = 0;\n for (const mutatedItem of mutatedItems) {\n for (const key in mutateSpec) {\n // get the mutated value for this item (either run the fn or use the constant)\n const mutateSpecValue = mutateSpec[key];\n const mutatedResult =\n typeof mutateSpecValue === 'function'\n ? mutateSpecValue(mutatedItem as T, i, mutatedItems as T[])\n : mutateSpecValue;\n\n mutatedItem[key as any] = mutatedResult;\n }\n\n ++i;\n }\n\n return mutatedItems as Compute<MutatedT>[];\n };\n\n return _mutate;\n}\n"],"names":[],"mappings":";;;;gBA4BE;AAIA,QAAM,UAAwC,CAC5C;AAKA,UAAM,eAA2B,MAAM,IAAI,CAAC,WAAY;AAIxD,QAAI,IAAI;AACR,eAAW,eAAe;AACxB,iBAAW,OAAO;AAEhB,cAAM,kBAAkB,WAAW;AACnC,cAAM,gBACJ,OAAO,oBAAoB,aACvB,gBAAgB,aAAkB,GAAG,gBACrC;AAEN,oBAAY,OAAc;AAAA;AAG5B,QAAE;AAAA;AAGJ,WAAO;AAAA;AAGT,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"mutate.js","sources":["../../src/mutate.ts"],"sourcesContent":["import { TidyFn, NonFunctionValue, Key } from './types';\nimport { Prettify, Merge } from './type-utils';\n\ntype MutateSpecValue<T, O = any> =\n | ((item: T, index: number, array: Iterable<T>) => O)\n | NonFunctionValue;\nexport type MutateSpec<T> = Record<Key, MutateSpecValue<T>>;\nexport type ResolvedObj<Obj extends Record<Key, MutateSpecValue<any>>> = {\n [K in keyof Obj]: Obj[K] extends (...args: any) => any\n ? ReturnType<Obj[K]> extends any[]\n ? ReturnType<Obj[K]>[number]\n : ReturnType<Obj[K]>\n : Obj[K];\n};\n\ntype Mutated<T extends object, MSpec extends MutateSpec<T>> = Merge<\n ResolvedObj<MSpec>,\n T\n>;\n\ntype Compute<T> = Prettify<T>;\n\n/**\n * Mutates items, one item at a time. For mutating across multiple items,\n * use mutateWithSummary.\n * @param mutateSpec\n */\nexport function mutate<T extends object, MSpec extends MutateSpec<T>>(\n mutateSpec: MSpec\n): TidyFn<T, Compute<Mutated<T, MSpec>>> {\n type MutatedT = Mutated<T, MSpec>;\n // use Compute for better intellisense (reveals all keys in obj)\n const _mutate: TidyFn<T, Compute<MutatedT>> = (\n items: T[]\n ): Compute<MutatedT>[] => {\n // create the base items to merge mutated values into\n // note we start with the original array so when we pass it as the third argument\n // to a mutate function, you get the values that have been changed so far\n const mutatedItems: MutatedT[] = items.map((d) => ({ ...d })) as MutatedT[];\n\n // we can update each item completely one at a time, since mutate doesn't\n // support looking across items. Use mutateWithSummary for that.\n let i = 0;\n for (const mutatedItem of mutatedItems) {\n for (const key in mutateSpec) {\n // get the mutated value for this item (either run the fn or use the constant)\n const mutateSpecValue = mutateSpec[key];\n const mutatedResult =\n typeof mutateSpecValue === 'function'\n ? mutateSpecValue(mutatedItem as T, i, mutatedItems as T[])\n : mutateSpecValue;\n\n mutatedItem[key as any] = mutatedResult;\n }\n\n ++i;\n }\n\n return mutatedItems as Compute<MutatedT>[];\n };\n\n return _mutate;\n}\n"],"names":[],"mappings":";;AA2BO,SAAS,OACd,UACuC,EAAA;AAGvC,EAAM,MAAA,OAAA,GAAwC,CAC5C,KACwB,KAAA;AAIxB,IAAM,MAAA,YAAA,GAA2B,MAAM,GAAI,CAAA,CAAC,OAAO,EAAE,GAAG,GAAI,CAAA,CAAA,CAAA;AAI5D,IAAA,IAAI,CAAI,GAAA,CAAA,CAAA;AACR,IAAA,KAAA,MAAW,eAAe,YAAc,EAAA;AACtC,MAAA,KAAA,MAAW,OAAO,UAAY,EAAA;AAE5B,QAAM,MAAA,eAAA,GAAkB,WAAW,GAAG,CAAA,CAAA;AACtC,QAAM,MAAA,aAAA,GACJ,OAAO,eAAoB,KAAA,UAAA,GACvB,gBAAgB,WAAkB,EAAA,CAAA,EAAG,YAAmB,CACxD,GAAA,eAAA,CAAA;AAEN,QAAA,WAAA,CAAY,GAAU,CAAI,GAAA,aAAA,CAAA;AAAA,OAC5B;AAEA,MAAE,EAAA,CAAA,CAAA;AAAA,KACJ;AAEA,IAAO,OAAA,YAAA,CAAA;AAAA,GACT,CAAA;AAEA,EAAO,OAAA,OAAA,CAAA;AACT;;;;"}
@@ -1,10 +1,8 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function mutateWithSummary(mutateSpec) {
6
4
  const _mutate = (items) => {
7
- const mutatedItems = items.map((d) => ({...d}));
5
+ const mutatedItems = items.map((d) => ({ ...d }));
8
6
  for (const key in mutateSpec) {
9
7
  const mutateSpecValue = mutateSpec[key];
10
8
  const mutatedResult = typeof mutateSpecValue === "function" ? mutateSpecValue(mutatedItems) : mutateSpecValue;
@@ -1 +1 @@
1
- {"version":3,"file":"mutateWithSummary.js","sources":["../../src/mutateWithSummary.ts"],"sourcesContent":["import { TidyFn, NonFunctionValue, Key } from './types';\nimport { A } from 'ts-toolbelt';\n\ntype MutateSpecValue<T, O = any> = ((items: T[]) => O[] | O) | NonFunctionValue;\nexport type MutateSummarySpec<T> = Record<Key, MutateSpecValue<T>>;\nexport type ResolvedObj<Obj extends Record<Key, MutateSpecValue<any>>> = {\n [K in keyof Obj]: Obj[K] extends (...args: any) => any\n ? ReturnType<Obj[K]> extends any[]\n ? ReturnType<Obj[K]>[number]\n : ReturnType<Obj[K]> extends Float64Array\n ? number\n : ReturnType<Obj[K]>\n : Obj[K];\n};\n\ntype Mutated<T, MSpec extends MutateSummarySpec<T>> = T & ResolvedObj<MSpec>;\n\ntype Compute<T> = A.Compute<T>;\n\n/**\n * Mutates items, looking at multiple items at a time to enable summarization.\n * For simpler, item by item mutations, use mutate.\n * @param mutateSpec\n */\nexport function mutateWithSummary<\n T extends object,\n MSpec extends MutateSummarySpec<T>\n>(mutateSpec: MSpec): TidyFn<T, Compute<Mutated<T, MSpec>>> {\n type MutatedT = Mutated<T, MSpec>;\n // use Compute for better intellisense (reveals all keys in obj)\n const _mutate: TidyFn<T, Compute<MutatedT>> = (\n items: T[]\n ): Compute<MutatedT>[] => {\n // create the base items to merge mutated values into\n const mutatedItems: MutatedT[] = items.map((d) => ({ ...d })) as MutatedT[];\n\n // create vectors for each mutated value\n for (const key in mutateSpec) {\n // convert individual values to a vector of the same value\n // this allows mutate functions to return single numbers and still work\n const mutateSpecValue = mutateSpec[key];\n const mutatedResult =\n typeof mutateSpecValue === 'function'\n ? mutateSpecValue(mutatedItems)\n : mutateSpecValue;\n const mutatedVector =\n mutatedResult?.[Symbol.iterator] && typeof mutatedResult !== 'string'\n ? mutatedResult\n : items.map(() => mutatedResult);\n\n // merge the mutated vector into the mutated items\n let i = -1;\n for (const mutatedItem of mutatedItems) {\n mutatedItem[key as keyof MutatedT] = mutatedVector[++i];\n }\n }\n\n return mutatedItems as Compute<MutatedT>[];\n };\n\n return _mutate;\n}\n"],"names":[],"mappings":";;;;2BA2BE;AAGA,QAAM,UAAwC,CAC5C;AAGA,UAAM,eAA2B,MAAM,IAAI,CAAC,WAAY;AAGxD,eAAW,OAAO;AAGhB,YAAM,kBAAkB,WAAW;AACnC,YAAM,gBACJ,OAAO,oBAAoB,aACvB,gBAAgB,gBAChB;AACN,YAAM,gBACJ,gDAAgB,OAAO,cAAa,OAAO,kBAAkB,WACzD,gBACA,MAAM,IAAI,MAAM;AAGtB,UAAI,IAAI;AACR,iBAAW,eAAe;AACxB,oBAAY,OAAyB,cAAc,EAAE;AAAA;AAAA;AAIzD,WAAO;AAAA;AAGT,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"mutateWithSummary.js","sources":["../../src/mutateWithSummary.ts"],"sourcesContent":["import { TidyFn, NonFunctionValue, Key } from './types';\nimport { Prettify } from './type-utils';\n\ntype MutateSpecValue<T, O = any> = ((items: T[]) => O[] | O) | NonFunctionValue;\nexport type MutateSummarySpec<T> = Record<Key, MutateSpecValue<T>>;\nexport type ResolvedObj<Obj extends Record<Key, MutateSpecValue<any>>> = {\n [K in keyof Obj]: Obj[K] extends (...args: any) => any\n ? ReturnType<Obj[K]> extends any[]\n ? ReturnType<Obj[K]>[number]\n : ReturnType<Obj[K]> extends Float64Array\n ? number\n : ReturnType<Obj[K]>\n : Obj[K];\n};\n\ntype Mutated<T, MSpec extends MutateSummarySpec<T>> = T & ResolvedObj<MSpec>;\n\ntype Compute<T> = Prettify<T>;\n\n/**\n * Mutates items, looking at multiple items at a time to enable summarization.\n * For simpler, item by item mutations, use mutate.\n * @param mutateSpec\n */\nexport function mutateWithSummary<\n T extends object,\n MSpec extends MutateSummarySpec<T>\n>(mutateSpec: MSpec): TidyFn<T, Compute<Mutated<T, MSpec>>> {\n type MutatedT = Mutated<T, MSpec>;\n // use Compute for better intellisense (reveals all keys in obj)\n const _mutate: TidyFn<T, Compute<MutatedT>> = (\n items: T[]\n ): Compute<MutatedT>[] => {\n // create the base items to merge mutated values into\n const mutatedItems: MutatedT[] = items.map((d) => ({ ...d })) as MutatedT[];\n\n // create vectors for each mutated value\n for (const key in mutateSpec) {\n // convert individual values to a vector of the same value\n // this allows mutate functions to return single numbers and still work\n const mutateSpecValue = mutateSpec[key];\n const mutatedResult =\n typeof mutateSpecValue === 'function'\n ? mutateSpecValue(mutatedItems)\n : mutateSpecValue;\n const mutatedVector =\n mutatedResult?.[Symbol.iterator] && typeof mutatedResult !== 'string'\n ? mutatedResult\n : items.map(() => mutatedResult);\n\n // merge the mutated vector into the mutated items\n let i = -1;\n for (const mutatedItem of mutatedItems) {\n mutatedItem[key as keyof MutatedT] = mutatedVector[++i];\n }\n }\n\n return mutatedItems as Compute<MutatedT>[];\n };\n\n return _mutate;\n}\n"],"names":[],"mappings":";;AAwBO,SAAS,kBAGd,UAA0D,EAAA;AAG1D,EAAM,MAAA,OAAA,GAAwC,CAC5C,KACwB,KAAA;AAExB,IAAM,MAAA,YAAA,GAA2B,MAAM,GAAI,CAAA,CAAC,OAAO,EAAE,GAAG,GAAI,CAAA,CAAA,CAAA;AAG5D,IAAA,KAAA,MAAW,OAAO,UAAY,EAAA;AAG5B,MAAM,MAAA,eAAA,GAAkB,WAAW,GAAG,CAAA,CAAA;AACtC,MAAA,MAAM,gBACJ,OAAO,eAAA,KAAoB,UACvB,GAAA,eAAA,CAAgB,YAAY,CAC5B,GAAA,eAAA,CAAA;AACN,MAAM,MAAA,aAAA,GAAA,CACJ,aAAgB,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,aAAA,CAAA,MAAA,CAAO,QAAa,CAAA,KAAA,OAAO,aAAkB,KAAA,QAAA,GACzD,aACA,GAAA,KAAA,CAAM,GAAI,CAAA,MAAM,aAAa,CAAA,CAAA;AAGnC,MAAA,IAAI,CAAI,GAAA,CAAA,CAAA,CAAA;AACR,MAAA,KAAA,MAAW,eAAe,YAAc,EAAA;AACtC,QAAA,WAAA,CAAY,GAAqB,CAAA,GAAI,aAAc,CAAA,EAAE,CAAC,CAAA,CAAA;AAAA,OACxD;AAAA,KACF;AAEA,IAAO,OAAA,YAAA,CAAA;AAAA,GACT,CAAA;AAEA,EAAO,OAAA,OAAA,CAAA;AACT;;;;"}
@@ -1,13 +1,11 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var select = require('./select.js');
6
4
 
7
5
  function pivotLonger(options) {
8
6
  const _pivotLonger = (items) => {
9
7
  var _a;
10
- const {namesTo, valuesTo, namesSep = "_"} = options;
8
+ const { namesTo, valuesTo, namesSep = "_" } = options;
11
9
  const cols = (_a = options.cols) != null ? _a : [];
12
10
  const colsKeys = select.processSelectors(items, cols);
13
11
  const namesToKeys = Array.isArray(namesTo) ? namesTo : [namesTo];
@@ -15,18 +13,42 @@ function pivotLonger(options) {
15
13
  const hasMultipleNamesTo = namesToKeys.length > 1;
16
14
  const hasMultipleValuesTo = valuesToKeys.length > 1;
17
15
  const longer = [];
16
+ if (!items.length) return longer;
17
+ const colsKeysSet = new Set(colsKeys);
18
+ const remainingKeys = Object.keys(items[0]).filter(
19
+ (key) => !colsKeysSet.has(key)
20
+ );
21
+ const nameValueKeysWithoutValuePrefix = hasMultipleValuesTo ? Array.from(
22
+ new Set(
23
+ colsKeys.map(
24
+ (key) => key.substring(key.indexOf(namesSep) + 1)
25
+ )
26
+ )
27
+ ) : colsKeys;
28
+ const nameValuePartsMap = hasMultipleNamesTo ? new Map(
29
+ nameValueKeysWithoutValuePrefix.map((nv) => [
30
+ nv,
31
+ nv.split(namesSep)
32
+ ])
33
+ ) : null;
34
+ const itemKeysMap = hasMultipleValuesTo ? new Map(
35
+ nameValueKeysWithoutValuePrefix.map((nv) => [
36
+ nv,
37
+ valuesToKeys.map((vk) => `${String(vk)}${namesSep}${String(nv)}`)
38
+ ])
39
+ ) : null;
18
40
  for (const item of items) {
19
- const remainingKeys = Object.keys(item).filter((key) => !colsKeys.includes(key));
20
41
  const baseObj = {};
21
42
  for (const key of remainingKeys) {
22
43
  baseObj[key] = item[key];
23
44
  }
24
- const nameValueKeysWithoutValuePrefix = hasMultipleValuesTo ? Array.from(new Set(colsKeys.map((key) => key.substring(key.indexOf(namesSep) + 1)))) : colsKeys;
25
45
  for (const nameValue of nameValueKeysWithoutValuePrefix) {
26
- const entryObj = {...baseObj};
27
- for (const valueKey of valuesToKeys) {
28
- const itemKey = hasMultipleValuesTo ? `${valueKey}${namesSep}${nameValue}` : nameValue;
29
- const nameValueParts = hasMultipleNamesTo ? nameValue.split(namesSep) : [nameValue];
46
+ const entryObj = { ...baseObj };
47
+ const nameValueParts = nameValuePartsMap ? nameValuePartsMap.get(nameValue) : [nameValue];
48
+ const itemKeys = itemKeysMap ? itemKeysMap.get(nameValue) : null;
49
+ for (let vi = 0; vi < valuesToKeys.length; vi++) {
50
+ const valueKey = valuesToKeys[vi];
51
+ const itemKey = itemKeys ? itemKeys[vi] : nameValue;
30
52
  let i = 0;
31
53
  for (const nameKey of namesToKeys) {
32
54
  const nameValuePart = nameValueParts[i++];