@tidyjs/tidy 2.4.4 → 2.5.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 (74) hide show
  1. package/dist/es/groupBy.js +2 -1
  2. package/dist/es/groupBy.js.map +1 -1
  3. package/dist/es/helpers/isObject.js +7 -0
  4. package/dist/es/helpers/isObject.js.map +1 -0
  5. package/dist/es/index.js +1 -0
  6. package/dist/es/index.js.map +1 -1
  7. package/dist/es/item/rate.js +7 -7
  8. package/dist/es/item/rate.js.map +1 -1
  9. package/dist/es/mutate.js +5 -5
  10. package/dist/es/mutate.js.map +1 -1
  11. package/dist/es/summary/deviation.js.map +1 -1
  12. package/dist/es/summary/first.js.map +1 -1
  13. package/dist/es/summary/last.js.map +1 -1
  14. package/dist/es/summary/max.js.map +1 -1
  15. package/dist/es/summary/mean.js.map +1 -1
  16. package/dist/es/summary/meanRate.js.map +1 -1
  17. package/dist/es/summary/median.js.map +1 -1
  18. package/dist/es/summary/min.js.map +1 -1
  19. package/dist/es/summary/n.js +5 -1
  20. package/dist/es/summary/n.js.map +1 -1
  21. package/dist/es/summary/nDistinct.js +2 -1
  22. package/dist/es/summary/nDistinct.js.map +1 -1
  23. package/dist/es/summary/sum.js +7 -2
  24. package/dist/es/summary/sum.js.map +1 -1
  25. package/dist/es/summary/variance.js.map +1 -1
  26. package/dist/es/vector/cumsum.js.map +1 -1
  27. package/dist/es/vector/lag.js +1 -1
  28. package/dist/es/vector/lag.js.map +1 -1
  29. package/dist/es/vector/lead.js +1 -1
  30. package/dist/es/vector/lead.js.map +1 -1
  31. package/dist/es/vector/roll.js +4 -3
  32. package/dist/es/vector/roll.js.map +1 -1
  33. package/dist/es/vector/rowNumber.js +10 -0
  34. package/dist/es/vector/rowNumber.js.map +1 -0
  35. package/dist/lib/groupBy.js +2 -1
  36. package/dist/lib/groupBy.js.map +1 -1
  37. package/dist/lib/helpers/isObject.js +11 -0
  38. package/dist/lib/helpers/isObject.js.map +1 -0
  39. package/dist/lib/index.js +2 -0
  40. package/dist/lib/index.js.map +1 -1
  41. package/dist/lib/item/rate.js +7 -7
  42. package/dist/lib/item/rate.js.map +1 -1
  43. package/dist/lib/mutate.js +5 -5
  44. package/dist/lib/mutate.js.map +1 -1
  45. package/dist/lib/summary/deviation.js.map +1 -1
  46. package/dist/lib/summary/first.js.map +1 -1
  47. package/dist/lib/summary/last.js.map +1 -1
  48. package/dist/lib/summary/max.js.map +1 -1
  49. package/dist/lib/summary/mean.js.map +1 -1
  50. package/dist/lib/summary/meanRate.js.map +1 -1
  51. package/dist/lib/summary/median.js.map +1 -1
  52. package/dist/lib/summary/min.js.map +1 -1
  53. package/dist/lib/summary/n.js +5 -1
  54. package/dist/lib/summary/n.js.map +1 -1
  55. package/dist/lib/summary/nDistinct.js +2 -1
  56. package/dist/lib/summary/nDistinct.js.map +1 -1
  57. package/dist/lib/summary/sum.js +7 -2
  58. package/dist/lib/summary/sum.js.map +1 -1
  59. package/dist/lib/summary/variance.js.map +1 -1
  60. package/dist/lib/vector/cumsum.js.map +1 -1
  61. package/dist/lib/vector/lag.js +1 -1
  62. package/dist/lib/vector/lag.js.map +1 -1
  63. package/dist/lib/vector/lead.js +1 -1
  64. package/dist/lib/vector/lead.js.map +1 -1
  65. package/dist/lib/vector/roll.js +4 -3
  66. package/dist/lib/vector/roll.js.map +1 -1
  67. package/dist/lib/vector/rowNumber.js +14 -0
  68. package/dist/lib/vector/rowNumber.js.map +1 -0
  69. package/dist/tidy.d.ts +40 -19
  70. package/dist/umd/tidy.js +47 -22
  71. package/dist/umd/tidy.js.map +1 -1
  72. package/dist/umd/tidy.min.js +1 -1
  73. package/dist/umd/tidy.min.js.map +1 -1
  74. package/package.json +2 -2
@@ -3,6 +3,7 @@ import { assignGroupKeys } from './helpers/assignGroupKeys.js';
3
3
  import { groupMap } from './helpers/groupMap.js';
4
4
  import { groupTraversal } from './helpers/groupTraversal.js';
5
5
  import { identity } from './helpers/identity.js';
6
+ import { isObject } from './helpers/isObject.js';
6
7
  import { singleOrArray } from './helpers/singleOrArray.js';
7
8
 
8
9
  function groupBy(groupKeys, fns, options) {
@@ -72,7 +73,7 @@ function makeGrouped(items, groupKeys) {
72
73
  const keyCache = new Map();
73
74
  return (d) => {
74
75
  const keyValue = keyFn(d);
75
- const keyValueOf = typeof keyValue === "object" ? keyValue.valueOf() : keyValue;
76
+ const keyValueOf = isObject(keyValue) ? keyValue.valueOf() : keyValue;
76
77
  if (keyCache.has(keyValueOf)) {
77
78
  return keyCache.get(keyValueOf);
78
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"groupBy.js","sources":["../../src/groupBy.ts"],"sourcesContent":["import { group } from 'd3-array';\nimport { A, O } from 'ts-toolbelt';\nimport { assignGroupKeys } from './helpers/assignGroupKeys';\nimport { groupMap } from './helpers/groupMap';\nimport { groupTraversal } from './helpers/groupTraversal';\nimport { identity } from './helpers/identity';\nimport { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { Grouped, GroupKey, TidyGroupExportFn, Key, TidyFn } from './types';\n\n/** [key, values] where values could be more nested entries */\ntype EntriesOutput = [any, any][];\ntype EntriesObjectOutput = { key: Key; values: any }[];\n\n/** nested objects: { [key]: values } */\ntype ObjectOutput = Record<Key, any>;\n\n/** nested keys: e.g. [key, key, key, [key, key, [key]]] */\ntype KeysOutput = any[];\n\n/** nested values: e.g. [[value1_1, value1_2], [value2_1, value2_2]] */\ntype ValuesOutput = any[];\n\nexport type LevelSpec = {\n id?: string;\n createEmptySubgroup: () => any;\n addSubgroup: (\n parentGrouped: any,\n newSubgroup: any,\n key: any,\n level: number\n ) => void;\n addLeaf: (parentGrouped: any, key: any, values: any[], level: number) => void;\n};\n\n/**\n * Options to affect export type\n */\ninterface GroupByOptions {\n /** whether to merge group keys back into the objects */\n readonly addGroupKeys?: boolean;\n\n // -- export related -- //\n /** export method */\n readonly export?:\n | 'grouped'\n | 'entries'\n | 'entries-object'\n | 'object'\n | 'map'\n | 'keys'\n | 'values'\n | 'levels'\n | 'ungrouped';\n /** if all nested levels should be brought to a single top level */\n readonly flat?: boolean;\n /** when flat is true, how to flatten nested keys */\n readonly compositeKey?: (keys: any[]) => string;\n /** whether the leaf sets consist of just one item (typical after summarize).\n * if true, uses the first element in the leaf set instead of an array\n */\n readonly single?: boolean;\n /** operation called on each leaf during export to map it to a different value\n * (default: identity)\n */\n readonly mapLeaf?: (value: any) => any;\n /** operation called on each leaf set to map the array of values to a different value.\n * Similar to `rollup` from d3-collection nest or d3-array\n * (default: identity)\n */\n readonly mapLeaves?: (values: any[]) => any;\n /** [entries only] operation called on entries to map from [key, values] to\n * whatever the output of this is (e.g. `{ key, values }`)\n * (default: identity)\n */\n readonly mapEntry?: (entry: [any, any], level: number) => any;\n\n /** [required for levels] specifies the export operation for each level of the grouping */\n readonly levels?: (\n | 'entries'\n | 'entries-object'\n | 'object'\n | 'map'\n | 'keys'\n | 'values'\n | LevelSpec\n )[];\n}\n\n// aliases to make overloads shorter\ntype GK<T extends object> = SingleOrArray<keyof T | ((d: T) => any)>;\ntype F<I extends object, O extends object> = TidyFn<I, O>;\n\n// merge back in group keys to output types\ntype MergeGroupKeys<\n T extends object,\n Out extends object,\n Keys extends GK<T>\n> = Keys extends keyof T\n ? O.Merge<Pick<T, Keys>, Out>\n : Keys extends (keyof T)[]\n ? O.Merge<Pick<T, Keys[number]>, Out>\n : Out;\n\n// do not merge in group keys if explicitly said not to\ntype WithGroupKeys<\n T extends object,\n Out extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions | undefined\n> = NonNullable<Opts>['addGroupKeys'] extends false\n ? Out\n : MergeGroupKeys<T, Out, Keys>;\n\n/**\n * output varies based on export options\n */\ntype GroupByOutput<\n T extends object,\n O extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions | undefined\n> = A.Compute<\n NonNullable<Opts>['export'] extends 'grouped'\n ? Grouped<WithGroupKeys<T, O, Keys, Opts>>\n : NonNullable<Opts>['export'] extends 'entries'\n ? EntriesOutput\n : NonNullable<Opts>['export'] extends 'entries-object'\n ? EntriesObjectOutput\n : NonNullable<Opts>['export'] extends 'object'\n ? ObjectOutput\n : NonNullable<Opts>['export'] extends 'map'\n ? Map<any, any>\n : NonNullable<Opts>['export'] extends 'keys'\n ? KeysOutput\n : NonNullable<Opts>['export'] extends 'values'\n ? ValuesOutput\n : NonNullable<Opts>['export'] extends 'levels'\n ? any\n : WithGroupKeys<T, O, Keys, Opts>[]\n>;\n\ntype GroupByFn<\n T extends object,\n O extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions\n> = Opts['export'] extends\n | 'grouped'\n | 'entries'\n | 'entries-object'\n | 'object'\n | 'map'\n | 'keys'\n | 'values'\n | 'levels'\n ? TidyGroupExportFn<T, GroupByOutput<T, O, Keys, Opts>>\n : // default is no export, ungrouped and back in simple form\n TidyFn<T, WithGroupKeys<T, O, Keys, Opts>>;\n\n/**\n * Nests the data by the specified groupings\n */\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: F<T, T1>, options?: Opts): GroupByFn<T, T1, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, T5 extends object, T6 extends object, T7 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>, F<T6, T7>], options?: Opts): GroupByFn<T, T7, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, T5 extends object, T6 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>], options?: Opts): GroupByFn<T, T6, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, T5 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>], options?: Opts): GroupByFn<T, T5, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>], options?: Opts): GroupByFn<T, T4, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>], options?: Opts): GroupByFn<T, T3, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>], options?: Opts): GroupByFn<T, T2, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>], options?: Opts): GroupByFn<T, T1, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [], options?: Opts): GroupByFn<T, T, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, options?: Opts): GroupByFn<T, T, Keys, Opts>;\nexport function groupBy<\n T extends object,\n O extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions\n>(\n groupKeys: Keys,\n fns: TidyFn<any, any>[] | TidyFn<any, any>,\n options?: Opts\n): GroupByFn<T, O, Keys, Opts> {\n if (typeof fns === 'function') {\n fns = [fns];\n } else if (arguments.length === 2 && fns != null && !Array.isArray(fns)) {\n options = fns as any;\n }\n\n const _groupBy: GroupByFn<T, O, Keys, Opts> = ((items: T[]) => {\n // form into a nested map\n const grouped = makeGrouped(items, groupKeys);\n\n // run group functions\n const results = runFlow(\n grouped,\n fns as TidyFn<any, any>[],\n options?.addGroupKeys\n );\n\n // export\n if (options?.export) {\n switch (options.export) {\n case 'grouped':\n return results;\n case 'levels':\n return exportLevels(results, options);\n case 'entries-obj' as any:\n case 'entriesObject' as any:\n return exportLevels(results, {\n ...options,\n export: 'levels',\n levels: ['entries-object'],\n });\n default:\n return exportLevels(results, {\n ...options,\n export: 'levels',\n levels: [options.export],\n });\n }\n }\n\n // export === 'ungrouped' or nully:\n const ungrouped = ungroup(results, options?.addGroupKeys);\n return ungrouped as any;\n }) as GroupByFn<T, O, Keys, Opts>;\n // (_groupBy as any).tidyType = 'group-export';\n\n return _groupBy;\n}\n// convenient export option configs\ngroupBy.grouped = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'grouped' } as const);\ngroupBy.entries = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'entries' } as const);\ngroupBy.entriesObject = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'entries-object' } as const);\ngroupBy.object = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'object' } as const);\ngroupBy.map = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'map' } as const);\ngroupBy.keys = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'keys' } as const);\ngroupBy.values = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'values' } as const);\ngroupBy.levels = (options?: Omit<GroupByOptions, 'export'>) =>\n ({ ...options, export: 'levels' } as const);\n\nfunction runFlow<T extends object>(\n items: Grouped<T>,\n fns?: TidyFn<any, any>[],\n addGroupKeys?: boolean\n) {\n let result: any = items;\n if (!fns?.length) return result;\n\n for (const fn of fns) {\n if (!fn) continue;\n\n // otherwise break it up and call it on each leaf set\n result = groupMap(result, (items, keys) => {\n // ensure we kept the group keys in the object\n // (necessary for e.g. summarize which may remove them)\n const context = { groupKeys: keys };\n let leafItemsMapped = fn(items, context);\n if (addGroupKeys !== false) {\n leafItemsMapped = leafItemsMapped.map((item: T) =>\n assignGroupKeys(item, keys)\n );\n }\n\n return leafItemsMapped;\n });\n }\n\n return result;\n}\n\nfunction makeGrouped<T extends object>(\n items: T[],\n groupKeys: SingleOrArray<keyof T | ((d: T) => any)>\n): Grouped<T> {\n // convert string based keys to functions and keep the key name with the key value in a tuple\n const groupKeyFns = singleOrArray(groupKeys).map((key, i) => {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n // use a cache so we don't generate new keys for the same tuple\n const keyCache = new Map();\n return (d: T) => {\n const keyValue = keyFn(d);\n\n const keyValueOf =\n typeof keyValue === 'object' ? keyValue.valueOf() : keyValue;\n // used cache tuple if available\n if (keyCache.has(keyValueOf)) {\n return keyCache.get(keyValueOf) as GroupKey;\n }\n\n const keyWithName = [key, keyValue];\n keyCache.set(keyValueOf, keyWithName);\n\n return keyWithName;\n };\n });\n\n const grouped = group(items, ...groupKeyFns);\n return grouped;\n}\n\n/**\n * flattens a grouped collection back to a simple array\n */\nfunction ungroup<T extends object>(\n grouped: Grouped<T>,\n addGroupKeys: boolean | undefined\n): T[] {\n // flatten the groups\n const items: T[] = [];\n\n groupTraversal(grouped, items, [], identity, (root, keys, values) => {\n // ensure we have group keys on items (in case runFlow didn't run)\n let valuesToAdd = values;\n if (addGroupKeys !== false) {\n valuesToAdd = values.map((d) => assignGroupKeys(d, keys));\n }\n root.push(...valuesToAdd);\n });\n\n return items;\n}\n\n// -----------------------------------------------------------------------\n// --- EXPORTS -----------------------------------------------------------\n// -----------------------------------------------------------------------\nconst defaultCompositeKey = (keys: any[]) => keys.join('/');\n\nfunction processFromGroupsOptions<T extends object>(options: GroupByOptions) {\n const {\n flat,\n single,\n mapLeaf = identity,\n mapLeaves = identity,\n addGroupKeys,\n } = options;\n let compositeKey: (keys: any[]) => string;\n if (options.flat) {\n compositeKey = options.compositeKey! ?? defaultCompositeKey;\n }\n\n const groupFn = (values: T[], keys: any[]) => {\n return single\n ? mapLeaf(\n addGroupKeys === false ? values[0] : assignGroupKeys(values[0], keys)\n )\n : mapLeaves(\n values.map((d) =>\n mapLeaf(addGroupKeys === false ? d : assignGroupKeys(d, keys))\n )\n );\n };\n\n const keyFn = flat\n ? (keys: GroupKey[]) => compositeKey(keys.map((d) => d[1]))\n : (keys: GroupKey[]) => keys[keys.length - 1][1];\n\n return { groupFn, keyFn };\n}\n\n// -- Levels -------------------------------------------------------------\nfunction exportLevels<T extends object>(\n grouped: Grouped<T>,\n options: GroupByOptions\n): any {\n type NestedEntries<T> = Array<[any, NestedEntries<T> | T[]]>;\n type NestedObject<T> = { [key: string]: NestedObject<T> | T[] };\n\n const { groupFn, keyFn } = processFromGroupsOptions(options);\n let { mapEntry = identity } = options;\n const { levels = ['entries'] } = options;\n\n const levelSpecs: LevelSpec[] = [];\n for (const levelOption of levels) {\n switch (levelOption) {\n // entries / entries-object -----------------------------------------\n case 'entries':\n case 'entries-object':\n case 'entries-obj' as any:\n case 'entriesObject' as any: {\n const levelMapEntry =\n (levelOption === 'entries-object' ||\n levelOption === ('entries-obj' as any) ||\n levelOption === ('entriesObject' as any)) &&\n options.mapEntry == null\n ? ([key, values]: any) => ({ key, values })\n : mapEntry;\n\n levelSpecs.push({\n id: 'entries',\n createEmptySubgroup: () => [],\n addSubgroup: (\n parentGrouped: NestedEntries<T>,\n newSubgroup: any,\n key: any,\n level: number\n ) => {\n parentGrouped.push(levelMapEntry([key, newSubgroup], level));\n },\n\n addLeaf: (\n parentGrouped: NestedEntries<T>,\n key: any,\n values: T[],\n level: number\n ) => {\n parentGrouped.push(levelMapEntry([key, values], level));\n },\n });\n break;\n }\n // map -------------------------------------------------------------\n case 'map':\n levelSpecs.push({\n id: 'map',\n createEmptySubgroup: () => new Map(),\n addSubgroup: (\n parentGrouped: Map<any, any>,\n newSubgroup: any,\n key: any\n ) => {\n parentGrouped.set(key, newSubgroup);\n },\n\n addLeaf: (parentGrouped: Map<any, any>, key: any, values: T[]) => {\n parentGrouped.set(key, values);\n },\n });\n break;\n\n // object ----------------------------------------------------------\n case 'object':\n levelSpecs.push({\n id: 'object',\n createEmptySubgroup: () => ({}),\n addSubgroup: (\n parentGrouped: NestedObject<T>,\n newSubgroup: any,\n key: any\n ) => {\n parentGrouped[key] = newSubgroup;\n },\n\n addLeaf: (parentGrouped: NestedObject<T>, key: any, values: T[]) => {\n parentGrouped[key] = values;\n },\n });\n break;\n\n // keys ------------------------------------------------------------\n case 'keys':\n levelSpecs.push({\n id: 'keys',\n createEmptySubgroup: () => [],\n addSubgroup: (parentGrouped: any, newSubgroup: any, key: any) => {\n parentGrouped.push([key, newSubgroup]);\n },\n\n addLeaf: (parentGrouped: any, key: any) => {\n parentGrouped.push(key);\n },\n });\n break;\n\n // values ----------------------------------------------------------\n case 'values':\n levelSpecs.push({\n id: 'values',\n createEmptySubgroup: () => [],\n addSubgroup: (parentGrouped: any, newSubgroup: any) => {\n parentGrouped.push(newSubgroup);\n },\n\n addLeaf: (parentGrouped: any, key: any, values: T[]) => {\n parentGrouped.push(values);\n },\n });\n break;\n\n // custom ----------------------------------------------------------\n default: {\n // LevelSpec obj already\n if (typeof levelOption === 'object') {\n levelSpecs.push(levelOption);\n }\n }\n }\n }\n\n // add subgroup\n const addSubgroup = (parentGrouped: any, keys: any[], level: number): any => {\n if (options.flat) {\n return parentGrouped;\n }\n\n const levelSpec = levelSpecs[level] ?? levelSpecs[levelSpecs.length - 1];\n const nextLevelSpec = levelSpecs[level + 1] ?? levelSpec;\n const newSubgroup = nextLevelSpec.createEmptySubgroup();\n levelSpec!.addSubgroup(parentGrouped, newSubgroup, keyFn(keys), level);\n return newSubgroup;\n };\n\n // add leaves\n const addLeaf = (\n parentGrouped: any,\n keys: any[],\n values: T[],\n level: number\n ) => {\n const levelSpec = levelSpecs[level] ?? levelSpecs[levelSpecs.length - 1];\n levelSpec!.addLeaf(\n parentGrouped,\n keyFn(keys),\n groupFn(values, keys),\n level\n );\n };\n\n const initialOutputObject = levelSpecs[0]!.createEmptySubgroup();\n return groupTraversal(grouped, initialOutputObject, [], addSubgroup, addLeaf);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"groupBy.js","sources":["../../src/groupBy.ts"],"sourcesContent":["import { group } from 'd3-array';\nimport { A, O } from 'ts-toolbelt';\nimport { assignGroupKeys } from './helpers/assignGroupKeys';\nimport { groupMap } from './helpers/groupMap';\nimport { groupTraversal } from './helpers/groupTraversal';\nimport { identity } from './helpers/identity';\nimport { isObject } from './helpers/isObject';\nimport { SingleOrArray, singleOrArray } from './helpers/singleOrArray';\nimport { Grouped, GroupKey, TidyGroupExportFn, Key, TidyFn } from './types';\n\n/** [key, values] where values could be more nested entries */\ntype EntriesOutput = [any, any][];\ntype EntriesObjectOutput = { key: Key; values: any }[];\n\n/** nested objects: { [key]: values } */\ntype ObjectOutput = Record<Key, any>;\n\n/** nested keys: e.g. [key, key, key, [key, key, [key]]] */\ntype KeysOutput = any[];\n\n/** nested values: e.g. [[value1_1, value1_2], [value2_1, value2_2]] */\ntype ValuesOutput = any[];\n\nexport type LevelSpec = {\n id?: string;\n createEmptySubgroup: () => any;\n addSubgroup: (\n parentGrouped: any,\n newSubgroup: any,\n key: any,\n level: number\n ) => void;\n addLeaf: (parentGrouped: any, key: any, values: any[], level: number) => void;\n};\n\n/**\n * Options to affect export type\n */\ninterface GroupByOptions {\n /** whether to merge group keys back into the objects */\n readonly addGroupKeys?: boolean;\n\n // -- export related -- //\n /** export method */\n readonly export?:\n | 'grouped'\n | 'entries'\n | 'entries-object'\n | 'object'\n | 'map'\n | 'keys'\n | 'values'\n | 'levels'\n | 'ungrouped';\n /** if all nested levels should be brought to a single top level */\n readonly flat?: boolean;\n /** when flat is true, how to flatten nested keys */\n readonly compositeKey?: (keys: any[]) => string;\n /** whether the leaf sets consist of just one item (typical after summarize).\n * if true, uses the first element in the leaf set instead of an array\n */\n readonly single?: boolean;\n /** operation called on each leaf during export to map it to a different value\n * (default: identity)\n */\n readonly mapLeaf?: (value: any) => any;\n /** operation called on each leaf set to map the array of values to a different value.\n * Similar to `rollup` from d3-collection nest or d3-array\n * (default: identity)\n */\n readonly mapLeaves?: (values: any[]) => any;\n /** [entries only] operation called on entries to map from [key, values] to\n * whatever the output of this is (e.g. `{ key, values }`)\n * (default: identity)\n */\n readonly mapEntry?: (entry: [any, any], level: number) => any;\n\n /** [required for levels] specifies the export operation for each level of the grouping */\n readonly levels?: (\n | 'entries'\n | 'entries-object'\n | 'object'\n | 'map'\n | 'keys'\n | 'values'\n | LevelSpec\n )[];\n}\n\n// aliases to make overloads shorter\ntype GK<T extends object> = SingleOrArray<keyof T | ((d: T) => any)>;\ntype F<I extends object, O extends object> = TidyFn<I, O>;\n\n// merge back in group keys to output types\ntype MergeGroupKeys<\n T extends object,\n Out extends object,\n Keys extends GK<T>\n> = Keys extends keyof T\n ? O.Merge<Pick<T, Keys>, Out>\n : Keys extends (keyof T)[]\n ? O.Merge<Pick<T, Keys[number]>, Out>\n : Out;\n\n// do not merge in group keys if explicitly said not to\ntype WithGroupKeys<\n T extends object,\n Out extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions | undefined\n> = NonNullable<Opts>['addGroupKeys'] extends false\n ? Out\n : MergeGroupKeys<T, Out, Keys>;\n\n/**\n * output varies based on export options\n */\ntype GroupByOutput<\n T extends object,\n O extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions | undefined\n> = A.Compute<\n NonNullable<Opts>['export'] extends 'grouped'\n ? Grouped<WithGroupKeys<T, O, Keys, Opts>>\n : NonNullable<Opts>['export'] extends 'entries'\n ? EntriesOutput\n : NonNullable<Opts>['export'] extends 'entries-object'\n ? EntriesObjectOutput\n : NonNullable<Opts>['export'] extends 'object'\n ? ObjectOutput\n : NonNullable<Opts>['export'] extends 'map'\n ? Map<any, any>\n : NonNullable<Opts>['export'] extends 'keys'\n ? KeysOutput\n : NonNullable<Opts>['export'] extends 'values'\n ? ValuesOutput\n : NonNullable<Opts>['export'] extends 'levels'\n ? any\n : WithGroupKeys<T, O, Keys, Opts>[]\n>;\n\ntype GroupByFn<\n T extends object,\n O extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions\n> = Opts['export'] extends\n | 'grouped'\n | 'entries'\n | 'entries-object'\n | 'object'\n | 'map'\n | 'keys'\n | 'values'\n | 'levels'\n ? TidyGroupExportFn<T, GroupByOutput<T, O, Keys, Opts>>\n : // default is no export, ungrouped and back in simple form\n TidyFn<T, WithGroupKeys<T, O, Keys, Opts>>;\n\n/**\n * Nests the data by the specified groupings\n */\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: F<T, T1>, options?: Opts): GroupByFn<T, T1, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, T5 extends object, T6 extends object, T7 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>, F<T6, T7>], options?: Opts): GroupByFn<T, T7, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, T5 extends object, T6 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>], options?: Opts): GroupByFn<T, T6, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, T5 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>], options?: Opts): GroupByFn<T, T5, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, T4 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>], options?: Opts): GroupByFn<T, T4, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, T3 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>], options?: Opts): GroupByFn<T, T3, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, T2 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>], options?: Opts): GroupByFn<T, T2, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, T1 extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [F<T, T1>], options?: Opts): GroupByFn<T, T1, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, fns: [], options?: Opts): GroupByFn<T, T, Keys, Opts>;\n// prettier-ignore\nexport function groupBy<T extends object, Keys extends GK<T>, Opts extends GroupByOptions>(groupKeys: Keys, options?: Opts): GroupByFn<T, T, Keys, Opts>;\nexport function groupBy<\n T extends object,\n O extends object,\n Keys extends GK<T>,\n Opts extends GroupByOptions\n>(\n groupKeys: Keys,\n fns: TidyFn<any, any>[] | TidyFn<any, any>,\n options?: Opts\n): GroupByFn<T, O, Keys, Opts> {\n if (typeof fns === 'function') {\n fns = [fns];\n } else if (arguments.length === 2 && fns != null && !Array.isArray(fns)) {\n options = fns as any;\n }\n\n const _groupBy: GroupByFn<T, O, Keys, Opts> = ((items: T[]) => {\n // form into a nested map\n const grouped = makeGrouped(items, groupKeys);\n\n // run group functions\n const results = runFlow(\n grouped,\n fns as TidyFn<any, any>[],\n options?.addGroupKeys\n );\n\n // export\n if (options?.export) {\n switch (options.export) {\n case 'grouped':\n return results;\n case 'levels':\n return exportLevels(results, options);\n case 'entries-obj' as any:\n case 'entriesObject' as any:\n return exportLevels(results, {\n ...options,\n export: 'levels',\n levels: ['entries-object'],\n });\n default:\n return exportLevels(results, {\n ...options,\n export: 'levels',\n levels: [options.export],\n });\n }\n }\n\n // export === 'ungrouped' or nully:\n const ungrouped = ungroup(results, options?.addGroupKeys);\n return ungrouped as any;\n }) as GroupByFn<T, O, Keys, Opts>;\n // (_groupBy as any).tidyType = 'group-export';\n\n return _groupBy;\n}\n// convenient export option configs\ngroupBy.grouped = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'grouped' } as const);\ngroupBy.entries = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'entries' } as const);\ngroupBy.entriesObject = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'entries-object' } as const);\ngroupBy.object = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'object' } as const);\ngroupBy.map = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'map' } as const);\ngroupBy.keys = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'keys' } as const);\ngroupBy.values = (options?: Omit<GroupByOptions, 'export' | 'levels'>) =>\n ({ ...options, export: 'values' } as const);\ngroupBy.levels = (options?: Omit<GroupByOptions, 'export'>) =>\n ({ ...options, export: 'levels' } as const);\n\nfunction runFlow<T extends object>(\n items: Grouped<T>,\n fns?: TidyFn<any, any>[],\n addGroupKeys?: boolean\n) {\n let result: any = items;\n if (!fns?.length) return result;\n\n for (const fn of fns) {\n if (!fn) continue;\n\n // otherwise break it up and call it on each leaf set\n result = groupMap(result, (items, keys) => {\n // ensure we kept the group keys in the object\n // (necessary for e.g. summarize which may remove them)\n const context = { groupKeys: keys };\n let leafItemsMapped = fn(items, context);\n if (addGroupKeys !== false) {\n leafItemsMapped = leafItemsMapped.map((item: T) =>\n assignGroupKeys(item, keys)\n );\n }\n\n return leafItemsMapped;\n });\n }\n\n return result;\n}\n\nfunction makeGrouped<T extends object>(\n items: T[],\n groupKeys: SingleOrArray<keyof T | ((d: T) => any)>\n): Grouped<T> {\n // convert string based keys to functions and keep the key name with the key value in a tuple\n const groupKeyFns = singleOrArray(groupKeys).map((key, i) => {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n // use a cache so we don't generate new keys for the same tuple\n const keyCache = new Map();\n return (d: T) => {\n const keyValue = keyFn(d);\n\n const keyValueOf = isObject(keyValue) ? keyValue.valueOf() : keyValue;\n // used cache tuple if available\n if (keyCache.has(keyValueOf)) {\n return keyCache.get(keyValueOf) as GroupKey;\n }\n\n const keyWithName = [key, keyValue];\n keyCache.set(keyValueOf, keyWithName);\n\n return keyWithName;\n };\n });\n\n const grouped = group(items, ...groupKeyFns);\n return grouped;\n}\n\n/**\n * flattens a grouped collection back to a simple array\n */\nfunction ungroup<T extends object>(\n grouped: Grouped<T>,\n addGroupKeys: boolean | undefined\n): T[] {\n // flatten the groups\n const items: T[] = [];\n\n groupTraversal(grouped, items, [], identity, (root, keys, values) => {\n // ensure we have group keys on items (in case runFlow didn't run)\n let valuesToAdd = values;\n if (addGroupKeys !== false) {\n valuesToAdd = values.map((d) => assignGroupKeys(d, keys));\n }\n root.push(...valuesToAdd);\n });\n\n return items;\n}\n\n// -----------------------------------------------------------------------\n// --- EXPORTS -----------------------------------------------------------\n// -----------------------------------------------------------------------\nconst defaultCompositeKey = (keys: any[]) => keys.join('/');\n\nfunction processFromGroupsOptions<T extends object>(options: GroupByOptions) {\n const {\n flat,\n single,\n mapLeaf = identity,\n mapLeaves = identity,\n addGroupKeys,\n } = options;\n let compositeKey: (keys: any[]) => string;\n if (options.flat) {\n compositeKey = options.compositeKey! ?? defaultCompositeKey;\n }\n\n const groupFn = (values: T[], keys: any[]) => {\n return single\n ? mapLeaf(\n addGroupKeys === false ? values[0] : assignGroupKeys(values[0], keys)\n )\n : mapLeaves(\n values.map((d) =>\n mapLeaf(addGroupKeys === false ? d : assignGroupKeys(d, keys))\n )\n );\n };\n\n const keyFn = flat\n ? (keys: GroupKey[]) => compositeKey(keys.map((d) => d[1]))\n : (keys: GroupKey[]) => keys[keys.length - 1][1];\n\n return { groupFn, keyFn };\n}\n\n// -- Levels -------------------------------------------------------------\nfunction exportLevels<T extends object>(\n grouped: Grouped<T>,\n options: GroupByOptions\n): any {\n type NestedEntries<T> = Array<[any, NestedEntries<T> | T[]]>;\n type NestedObject<T> = { [key: string]: NestedObject<T> | T[] };\n\n const { groupFn, keyFn } = processFromGroupsOptions(options);\n let { mapEntry = identity } = options;\n const { levels = ['entries'] } = options;\n\n const levelSpecs: LevelSpec[] = [];\n for (const levelOption of levels) {\n switch (levelOption) {\n // entries / entries-object -----------------------------------------\n case 'entries':\n case 'entries-object':\n case 'entries-obj' as any:\n case 'entriesObject' as any: {\n const levelMapEntry =\n (levelOption === 'entries-object' ||\n levelOption === ('entries-obj' as any) ||\n levelOption === ('entriesObject' as any)) &&\n options.mapEntry == null\n ? ([key, values]: any) => ({ key, values })\n : mapEntry;\n\n levelSpecs.push({\n id: 'entries',\n createEmptySubgroup: () => [],\n addSubgroup: (\n parentGrouped: NestedEntries<T>,\n newSubgroup: any,\n key: any,\n level: number\n ) => {\n parentGrouped.push(levelMapEntry([key, newSubgroup], level));\n },\n\n addLeaf: (\n parentGrouped: NestedEntries<T>,\n key: any,\n values: T[],\n level: number\n ) => {\n parentGrouped.push(levelMapEntry([key, values], level));\n },\n });\n break;\n }\n // map -------------------------------------------------------------\n case 'map':\n levelSpecs.push({\n id: 'map',\n createEmptySubgroup: () => new Map(),\n addSubgroup: (\n parentGrouped: Map<any, any>,\n newSubgroup: any,\n key: any\n ) => {\n parentGrouped.set(key, newSubgroup);\n },\n\n addLeaf: (parentGrouped: Map<any, any>, key: any, values: T[]) => {\n parentGrouped.set(key, values);\n },\n });\n break;\n\n // object ----------------------------------------------------------\n case 'object':\n levelSpecs.push({\n id: 'object',\n createEmptySubgroup: () => ({}),\n addSubgroup: (\n parentGrouped: NestedObject<T>,\n newSubgroup: any,\n key: any\n ) => {\n parentGrouped[key] = newSubgroup;\n },\n\n addLeaf: (parentGrouped: NestedObject<T>, key: any, values: T[]) => {\n parentGrouped[key] = values;\n },\n });\n break;\n\n // keys ------------------------------------------------------------\n case 'keys':\n levelSpecs.push({\n id: 'keys',\n createEmptySubgroup: () => [],\n addSubgroup: (parentGrouped: any, newSubgroup: any, key: any) => {\n parentGrouped.push([key, newSubgroup]);\n },\n\n addLeaf: (parentGrouped: any, key: any) => {\n parentGrouped.push(key);\n },\n });\n break;\n\n // values ----------------------------------------------------------\n case 'values':\n levelSpecs.push({\n id: 'values',\n createEmptySubgroup: () => [],\n addSubgroup: (parentGrouped: any, newSubgroup: any) => {\n parentGrouped.push(newSubgroup);\n },\n\n addLeaf: (parentGrouped: any, key: any, values: T[]) => {\n parentGrouped.push(values);\n },\n });\n break;\n\n // custom ----------------------------------------------------------\n default: {\n // LevelSpec obj already\n if (typeof levelOption === 'object') {\n levelSpecs.push(levelOption);\n }\n }\n }\n }\n\n // add subgroup\n const addSubgroup = (parentGrouped: any, keys: any[], level: number): any => {\n if (options.flat) {\n return parentGrouped;\n }\n\n const levelSpec = levelSpecs[level] ?? levelSpecs[levelSpecs.length - 1];\n const nextLevelSpec = levelSpecs[level + 1] ?? levelSpec;\n const newSubgroup = nextLevelSpec.createEmptySubgroup();\n levelSpec!.addSubgroup(parentGrouped, newSubgroup, keyFn(keys), level);\n return newSubgroup;\n };\n\n // add leaves\n const addLeaf = (\n parentGrouped: any,\n keys: any[],\n values: T[],\n level: number\n ) => {\n const levelSpec = levelSpecs[level] ?? levelSpecs[levelSpecs.length - 1];\n levelSpec!.addLeaf(\n parentGrouped,\n keyFn(keys),\n groupFn(values, keys),\n level\n );\n };\n\n const initialOutputObject = levelSpecs[0]!.createEmptySubgroup();\n return groupTraversal(grouped, initialOutputObject, [], addSubgroup, addLeaf);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ function isObject(obj) {
2
+ const type = typeof obj;
3
+ return obj != null && (type === "object" || type === "function");
4
+ }
5
+
6
+ export { isObject };
7
+ //# sourceMappingURL=isObject.js.map
@@ -0,0 +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;;;;"}
package/dist/es/index.js CHANGED
@@ -32,6 +32,7 @@ export { cumsum } from './vector/cumsum.js';
32
32
  export { roll } from './vector/roll.js';
33
33
  export { lag } from './vector/lag.js';
34
34
  export { lead } from './vector/lead.js';
35
+ export { rowNumber } from './vector/rowNumber.js';
35
36
  export { sum } from './summary/sum.js';
36
37
  export { min } from './summary/min.js';
37
38
  export { max } from './summary/max.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -4,15 +4,15 @@ function rate(numerator, denominator, options) {
4
4
  const numeratorFn = typeof numerator === "function" ? numerator : (d) => d[numerator];
5
5
  const denominatorFn = typeof denominator === "function" ? denominator : (d) => d[denominator];
6
6
  const {predicate, allowDivideByZero} = options != null ? options : {};
7
- return predicate == null ? (d) => {
8
- const denom = denominatorFn(d);
9
- const numer = numeratorFn(d);
7
+ return predicate == null ? (d, index, array) => {
8
+ const denom = denominatorFn(d, index, array);
9
+ const numer = numeratorFn(d, index, array);
10
10
  return rate$1(numer, denom, allowDivideByZero);
11
- } : (d) => {
12
- if (!predicate(d))
11
+ } : (d, index, array) => {
12
+ if (!predicate(d, index, array))
13
13
  return void 0;
14
- const denom = denominatorFn(d);
15
- const numer = numeratorFn(d);
14
+ const denom = denominatorFn(d, index, array);
15
+ const numer = numeratorFn(d, index, array);
16
16
  return rate$1(numer, denom, allowDivideByZero);
17
17
  };
18
18
  }
@@ -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) => 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) => number),\n denominator: keyof T | ((d: 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) => {\n const denom = denominatorFn(d);\n const numer = numeratorFn(d);\n return mathRate(numer, denom, allowDivideByZero);\n }\n : (d: T) => {\n if (!predicate(d)) return undefined;\n\n const denom = denominatorFn(d);\n const numer = numeratorFn(d);\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;AACC,UAAM,QAAQ,cAAc;AAC5B,UAAM,QAAQ,YAAY;AAC1B,WAAOA,OAAS,OAAO,OAAO;AAAA,MAEhC,CAAC;AACC,QAAI,CAAC,UAAU;AAAI,aAAO;AAE1B,UAAM,QAAQ,cAAc;AAC5B,UAAM,QAAQ,YAAY;AAC1B,WAAOA,OAAS,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":";;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,OAAS,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,OAAS,OAAO,OAAO;AAAA;AAAA;;;;"}
package/dist/es/mutate.js CHANGED
@@ -1,14 +1,14 @@
1
1
  function mutate(mutateSpec) {
2
2
  const _mutate = (items) => {
3
- const mutatedItems = [];
4
- for (const item of items) {
5
- const mutatedItem = {...item};
3
+ const mutatedItems = items.map((d) => ({...d}));
4
+ let i = 0;
5
+ for (const mutatedItem of mutatedItems) {
6
6
  for (const key in mutateSpec) {
7
7
  const mutateSpecValue = mutateSpec[key];
8
- const mutatedResult = typeof mutateSpecValue === "function" ? mutateSpecValue(mutatedItem) : mutateSpecValue;
8
+ const mutatedResult = typeof mutateSpecValue === "function" ? mutateSpecValue(mutatedItem, i, mutatedItems) : mutateSpecValue;
9
9
  mutatedItem[key] = mutatedResult;
10
10
  }
11
- mutatedItems.push(mutatedItem);
11
+ ++i;
12
12
  }
13
13
  return mutatedItems;
14
14
  };
@@ -1 +1 @@
1
- {"version":3,"file":"mutate.js","sources":["../../src/mutate.ts"],"sourcesContent":["import { TidyFn, NonFunctionValue, Key } from './types';\nimport { A } from 'ts-toolbelt';\n\ntype MutateSpecValue<T, O = any> = ((item: T) => O) | 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, MSpec extends MutateSpec<T>> = T & ResolvedObj<MSpec>;\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 const mutatedItems: 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 for (const item of items) {\n const mutatedItem = { ...item } as MutatedT;\n\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)\n : mutateSpecValue;\n\n mutatedItem[key as keyof MutatedT] = mutatedResult;\n }\n\n mutatedItems.push(mutatedItem);\n }\n\n return mutatedItems as Compute<MutatedT>[];\n };\n\n return _mutate;\n}\n"],"names":[],"mappings":"gBAuBE;AAIA,QAAM,UAAwC,CAC5C;AAGA,UAAM,eAA2B;AAIjC,eAAW,QAAQ;AACjB,YAAM,cAAc,IAAK;AAEzB,iBAAW,OAAO;AAEhB,cAAM,kBAAkB,WAAW;AACnC,cAAM,gBACJ,OAAO,oBAAoB,aACvB,gBAAgB,eAChB;AAEN,oBAAY,OAAyB;AAAA;AAGvC,mBAAa,KAAK;AAAA;AAGpB,WAAO;AAAA;AAGT,SAAO;AAAA;;;;"}
1
+ {"version":3,"file":"mutate.js","sources":["../../src/mutate.ts"],"sourcesContent":["import { TidyFn, NonFunctionValue, Key } from './types';\nimport { A } 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, MSpec extends MutateSpec<T>> = T & ResolvedObj<MSpec>;\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, i, mutatedItems)\n : mutateSpecValue;\n\n mutatedItem[key as keyof MutatedT] = mutatedResult;\n }\n\n ++i;\n }\n\n return mutatedItems as Compute<MutatedT>[];\n };\n\n return _mutate;\n}\n"],"names":[],"mappings":"gBAyBE;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,aAAa,GAAG,gBAChC;AAEN,oBAAY,OAAyB;AAAA;AAGvC,QAAE;AAAA;AAGJ,WAAO;AAAA;AAGT,SAAO;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"deviation.js","sources":["../../../src/summary/deviation.ts"],"sourcesContent":["import { deviation as d3deviation } from 'd3-array';\n\n/**\n * Returns a function that computes the deviation over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function deviation<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3deviation(items, keyFn);\n}\n"],"names":["d3deviation"],"mappings":";;mBAM4C;AAC1C,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,YAAY,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"deviation.js","sources":["../../../src/summary/deviation.ts"],"sourcesContent":["import { deviation as d3deviation } from 'd3-array';\n\n/**\n * Returns a function that computes the deviation over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function deviation<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => number)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3deviation(items, keyFn);\n}\n"],"names":["d3deviation"],"mappings":";;mBAOE;AAEA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,YAAY,OAAO;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"first.js","sources":["../../../src/summary/first.ts"],"sourcesContent":["/**\n * Returns a function that returns the first value for the specified key\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function first<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => (items.length ? keyFn(items[0]) : undefined);\n}\n"],"names":[],"mappings":"eAIwC;AACtC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAgB,MAAM,SAAS,MAAM,MAAM,MAAM;AAAA;;;;"}
1
+ {"version":3,"file":"first.js","sources":["../../../src/summary/first.ts"],"sourcesContent":["/**\n * Returns a function that returns the first value for the specified key\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function first<T extends object>(key: keyof T | ((d: T) => any)) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n return (items: T[]) => (items.length ? keyFn(items[0]) : undefined);\n}\n"],"names":[],"mappings":"eAIwC;AACtC,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,SAAO,CAAC,UAAgB,MAAM,SAAS,MAAM,MAAM,MAAM;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"last.js","sources":["../../../src/summary/last.ts"],"sourcesContent":["/**\n * Returns a function that returns the last value for the specified key\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function last<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) =>\n items.length ? keyFn(items[items.length - 1]) : undefined;\n}\n"],"names":[],"mappings":"cAIuC;AACrC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UACN,MAAM,SAAS,MAAM,MAAM,MAAM,SAAS,MAAM;AAAA;;;;"}
1
+ {"version":3,"file":"last.js","sources":["../../../src/summary/last.ts"],"sourcesContent":["/**\n * Returns a function that returns the last value for the specified key\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function last<T extends object>(key: keyof T | ((d: T) => any)) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n return (items: T[]) =>\n items.length ? keyFn(items[items.length - 1]) : undefined;\n}\n"],"names":[],"mappings":"cAIuC;AACrC,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,SAAO,CAAC,UACN,MAAM,SAAS,MAAM,MAAM,MAAM,SAAS,MAAM;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"max.js","sources":["../../../src/summary/max.ts"],"sourcesContent":["import { max as d3max } from 'd3-array';\n\n/**\n * Returns a function that computes the max over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function max<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3max(items, keyFn);\n}\n"],"names":["d3max"],"mappings":";;aAMsC;AACpC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,MAAM,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"max.js","sources":["../../../src/summary/max.ts"],"sourcesContent":["import { max as d3max } from 'd3-array';\n\n/**\n * Returns a function that computes the max over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function max<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => number)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3max(items, keyFn);\n}\n"],"names":["d3max"],"mappings":";;aAOE;AAEA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,MAAM,OAAO;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"mean.js","sources":["../../../src/summary/mean.ts"],"sourcesContent":["import { mean as meanInternal } from '../helpers/summation';\n\n/**\n * Returns a function that computes the mean over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function mean<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => meanInternal(items, keyFn);\n}\n"],"names":["meanInternal"],"mappings":";;cAMuC;AACrC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,OAAa,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"mean.js","sources":["../../../src/summary/mean.ts"],"sourcesContent":["import { mean as meanInternal } from '../helpers/summation';\n\n/**\n * Returns a function that computes the mean over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function mean<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => number)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => meanInternal(items, keyFn);\n}\n"],"names":["meanInternal"],"mappings":";;cAOE;AAEA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,OAAa,OAAO;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"meanRate.js","sources":["../../../src/summary/meanRate.ts"],"sourcesContent":["import { fsum } from 'd3-array';\nimport { rate } from '../math/math';\n\n/**\n * Returns a function that computes the mean of a rate over an array of items\n * @param numerator A string key of the object or an accessor converting the object to a number\n * @param denominator A string key of the object or an accessor converting the object to a number\n */\nexport function meanRate<T extends object>(\n numerator: keyof T | ((d: T) => number),\n denominator: keyof T | ((d: T) => number)\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 return (items: T[]) => {\n const numerator = fsum(items, numeratorFn);\n const denominator = fsum(items, denominatorFn);\n return rate(numerator, denominator);\n };\n}\n"],"names":[],"mappings":";;;kBASE,WACA;AAEA,QAAM,cACJ,OAAO,cAAc,aACjB,YACA,CAAC,MAAU,EAAE;AACnB,QAAM,gBACJ,OAAO,gBAAgB,aACnB,cACA,CAAC,MAAU,EAAE;AAEnB,SAAO,CAAC;AACN,UAAM,aAAY,KAAK,OAAO;AAC9B,UAAM,eAAc,KAAK,OAAO;AAChC,WAAO,KAAK,YAAW;AAAA;AAAA;;;;"}
1
+ {"version":3,"file":"meanRate.js","sources":["../../../src/summary/meanRate.ts"],"sourcesContent":["import { fsum } from 'd3-array';\nimport { rate } from '../math/math';\n\n/**\n * Returns a function that computes the mean of a rate over an array of items\n * @param numerator A string key of the object or an accessor converting the object to a number\n * @param denominator A string key of the object or an accessor converting the object to a number\n */\nexport function meanRate<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) {\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 return (items: T[]) => {\n const numerator = fsum(items, numeratorFn);\n const denominator = fsum(items, denominatorFn);\n return rate(numerator, denominator);\n };\n}\n"],"names":[],"mappings":";;;kBASE,WACA;AAEA,QAAM,cACJ,OAAO,cAAc,aACjB,YACA,CAAC,MAAU,EAAE;AACnB,QAAM,gBACJ,OAAO,gBAAgB,aACnB,cACA,CAAC,MAAU,EAAE;AAEnB,SAAO,CAAC;AACN,UAAM,aAAY,KAAK,OAAO;AAC9B,UAAM,eAAc,KAAK,OAAO;AAChC,WAAO,KAAK,YAAW;AAAA;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"median.js","sources":["../../../src/summary/median.ts"],"sourcesContent":["import { median as d3median } from 'd3-array';\n\n/**\n * Returns a function that computes the median over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function median<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3median(items, keyFn);\n}\n"],"names":["d3median"],"mappings":";;gBAMyC;AACvC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,SAAS,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"median.js","sources":["../../../src/summary/median.ts"],"sourcesContent":["import { median as d3median } from 'd3-array';\n\n/**\n * Returns a function that computes the median over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function median<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => number)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3median(items, keyFn);\n}\n"],"names":["d3median"],"mappings":";;gBAOE;AAEA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,SAAS,OAAO;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"min.js","sources":["../../../src/summary/min.ts"],"sourcesContent":["import { min as d3min } from 'd3-array';\n\n/**\n * Returns a function that computes the min over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function min<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3min(items, keyFn);\n}\n"],"names":["d3min"],"mappings":";;aAMsC;AACpC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,MAAM,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"min.js","sources":["../../../src/summary/min.ts"],"sourcesContent":["import { min as d3min } from 'd3-array';\n\n/**\n * Returns a function that computes the min over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function min<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => number)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3min(items, keyFn);\n}\n"],"names":["d3min"],"mappings":";;aAOE;AAEA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,MAAM,OAAO;AAAA;;;;"}
@@ -1,4 +1,8 @@
1
- function n() {
1
+ function n(options) {
2
+ if (options == null ? void 0 : options.predicate) {
3
+ const predicate = options.predicate;
4
+ return (items) => items.reduce((n2, d, i) => predicate(d, i, items) ? n2 + 1 : n2, 0);
5
+ }
2
6
  return (items) => items.length;
3
7
  }
4
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"n.js","sources":["../../../src/summary/n.ts"],"sourcesContent":["/**\n * Returns a function that computes the count over an array of items\n */\nexport function n() {\n return (items: any[]) => items.length;\n}\n"],"names":[],"mappings":";AAIE,SAAO,CAAC,UAAiB,MAAM;AAAA;;;;"}
1
+ {"version":3,"file":"n.js","sources":["../../../src/summary/n.ts"],"sourcesContent":["type NOptions<T> = {\n predicate?: (d: T, index: number, array: Iterable<T>) => boolean;\n};\n\n/**\n * Returns a function that computes the count over an array of items\n */\nexport function n<T>(options?: NOptions<T>) {\n if (options?.predicate) {\n const predicate = options.predicate;\n return (items: T[]) =>\n items.reduce((n, d, i) => (predicate(d, i, items) ? n + 1 : n), 0);\n }\n\n return (items: T[]) => items.length;\n}\n"],"names":[],"mappings":"WAOqB;AACnB,MAAI,mCAAS;AACX,UAAM,YAAY,QAAQ;AAC1B,WAAO,CAAC,UACN,MAAM,OAAO,CAAC,IAAG,GAAG,MAAO,UAAU,GAAG,GAAG,SAAS,KAAI,IAAI,IAAI;AAAA;AAGpE,SAAO,CAAC,UAAe,MAAM;AAAA;;;;"}
@@ -3,8 +3,9 @@ function nDistinct(key, options = {}) {
3
3
  return (items) => {
4
4
  const uniques = new Map();
5
5
  let count = 0;
6
+ let i = 0;
6
7
  for (const item of items) {
7
- const value = keyFn(item);
8
+ const value = keyFn(item, i++, items);
8
9
  if (!uniques.has(value)) {
9
10
  if (!options.includeUndefined && value === void 0 || options.includeNull === false && value === null) {
10
11
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"nDistinct.js","sources":["../../../src/summary/nDistinct.ts"],"sourcesContent":["/**\n * Returns a function that computes the distinct count for a key\n * over an array of items. By default it counts nulls but not undefined\n */\nexport function nDistinct<T extends object>(\n key: keyof T | ((d: T) => any),\n options: { includeNull?: boolean; includeUndefined?: boolean } = {}\n) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n return (items: T[]) => {\n const uniques = new Map();\n let count = 0;\n\n for (const item of items) {\n const value = keyFn(item);\n\n if (!uniques.has(value)) {\n // default includes null but not undefined\n if (\n (!options.includeUndefined && value === undefined) ||\n (options.includeNull === false && value === null)\n ) {\n continue;\n }\n\n count += 1;\n uniques.set(value, true);\n }\n }\n\n return count;\n };\n}\n"],"names":[],"mappings":"mBAKE,KACA,UAAiE;AAEjE,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,SAAO,CAAC;AACN,UAAM,UAAU,IAAI;AACpB,QAAI,QAAQ;AAEZ,eAAW,QAAQ;AACjB,YAAM,QAAQ,MAAM;AAEpB,UAAI,CAAC,QAAQ,IAAI;AAEf,YACG,CAAC,QAAQ,oBAAoB,UAAU,UACvC,QAAQ,gBAAgB,SAAS,UAAU;AAE5C;AAAA;AAGF,iBAAS;AACT,gBAAQ,IAAI,OAAO;AAAA;AAAA;AAIvB,WAAO;AAAA;AAAA;;;;"}
1
+ {"version":3,"file":"nDistinct.js","sources":["../../../src/summary/nDistinct.ts"],"sourcesContent":["/**\n * Returns a function that computes the distinct count for a key\n * over an array of items. By default it counts nulls but not undefined\n */\nexport function nDistinct<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => any),\n options: { includeNull?: boolean; includeUndefined?: boolean } = {}\n) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n return (items: T[]) => {\n const uniques = new Map();\n let count = 0;\n\n let i = 0;\n for (const item of items) {\n const value = keyFn(item, i++, items);\n\n if (!uniques.has(value)) {\n // default includes null but not undefined\n if (\n (!options.includeUndefined && value === undefined) ||\n (options.includeNull === false && value === null)\n ) {\n continue;\n }\n\n count += 1;\n uniques.set(value, true);\n }\n }\n\n return count;\n };\n}\n"],"names":[],"mappings":"mBAKE,KACA,UAAiE;AAEjE,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,SAAO,CAAC;AACN,UAAM,UAAU,IAAI;AACpB,QAAI,QAAQ;AAEZ,QAAI,IAAI;AACR,eAAW,QAAQ;AACjB,YAAM,QAAQ,MAAM,MAAM,KAAK;AAE/B,UAAI,CAAC,QAAQ,IAAI;AAEf,YACG,CAAC,QAAQ,oBAAoB,UAAU,UACvC,QAAQ,gBAAgB,SAAS,UAAU;AAE5C;AAAA;AAGF,iBAAS;AACT,gBAAQ,IAAI,OAAO;AAAA;AAAA;AAIvB,WAAO;AAAA;AAAA;;;;"}
@@ -1,7 +1,12 @@
1
1
  import { fsum } from 'd3-array';
2
2
 
3
- function sum(key) {
4
- const keyFn = typeof key === "function" ? key : (d) => d[key];
3
+ function sum(key, options) {
4
+ let keyFn = typeof key === "function" ? key : (d) => d[key];
5
+ if (options == null ? void 0 : options.predicate) {
6
+ const originalKeyFn = keyFn;
7
+ const predicate = options.predicate;
8
+ keyFn = (d, index, array) => predicate(d, index, array) ? originalKeyFn(d, index, array) : 0;
9
+ }
5
10
  return (items) => fsum(items, keyFn);
6
11
  }
7
12
 
@@ -1 +1 @@
1
- {"version":3,"file":"sum.js","sources":["../../../src/summary/sum.ts"],"sourcesContent":["import { fsum } from 'd3-array';\n\n/**\n * Returns a function that computes the sum over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function sum<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => fsum(items, keyFn);\n}\n"],"names":[],"mappings":";;aAMsC;AACpC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAe,KAAK,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"sum.js","sources":["../../../src/summary/sum.ts"],"sourcesContent":["import { fsum } from 'd3-array';\n\ntype SumOptions<T> = {\n predicate?: (d: T, index: number, array: Iterable<T>) => boolean;\n};\n\n/**\n * Returns a function that computes the sum over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function sum<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => number),\n options?: SumOptions<T>\n) {\n let keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n if (options?.predicate) {\n const originalKeyFn = keyFn;\n const predicate = options.predicate;\n keyFn = (d: T, index: number, array: Iterable<T>) =>\n predicate(d, index, array) ? originalKeyFn(d, index, array) : 0;\n }\n\n return (items: T[]) => fsum(items, keyFn);\n}\n"],"names":[],"mappings":";;aAWE,KACA;AAEA,MAAI,QACF,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,MAAI,mCAAS;AACX,UAAM,gBAAgB;AACtB,UAAM,YAAY,QAAQ;AAC1B,YAAQ,CAAC,GAAM,OAAe,UAC5B,UAAU,GAAG,OAAO,SAAS,cAAc,GAAG,OAAO,SAAS;AAAA;AAGlE,SAAO,CAAC,UAAe,KAAK,OAAO;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"variance.js","sources":["../../../src/summary/variance.ts"],"sourcesContent":["import { variance as d3variance } from 'd3-array';\n\n/**\n * Returns a function that computes the variance over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function variance<T extends object>(key: keyof T | ((d: T) => number)) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3variance(items, keyFn);\n}\n"],"names":["d3variance"],"mappings":";;kBAM2C;AACzC,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,WAAW,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"variance.js","sources":["../../../src/summary/variance.ts"],"sourcesContent":["import { variance as d3variance } from 'd3-array';\n\n/**\n * Returns a function that computes the variance over an array of items\n * @param key A string key of the object or an accessor converting the object to a number\n */\nexport function variance<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => number)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n return (items: T[]) => d3variance(items, keyFn);\n}\n"],"names":["d3variance"],"mappings":";;kBAOE;AAEA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAEjD,SAAO,CAAC,UAAeA,WAAW,OAAO;AAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"cumsum.js","sources":["../../../src/vector/cumsum.ts"],"sourcesContent":["import { fcumsum } from '../helpers/summation';\n\nexport function cumsum<T extends object>(\n key: keyof T | ((d: T) => number | null | undefined)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n // note returns Float64Array not a normal array\n return (items: T[]) => fcumsum(items, keyFn);\n}\n"],"names":[],"mappings":";;gBAGE;AAEA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAGjD,SAAO,CAAC,UAAe,QAAQ,OAAO;AAAA;;;;"}
1
+ {"version":3,"file":"cumsum.js","sources":["../../../src/vector/cumsum.ts"],"sourcesContent":["import { fcumsum } from '../helpers/summation';\n\nexport function cumsum<T extends object>(\n key:\n | keyof T\n | ((d: T, index: number, array: Iterable<T>) => number | null | undefined)\n) {\n const keyFn =\n typeof key === 'function' ? key : (d: T) => (d[key] as unknown) as number;\n\n // note returns Float64Array not a normal array\n return (items: T[]) => fcumsum(items, keyFn);\n}\n"],"names":[],"mappings":";;gBAGE;AAIA,QAAM,QACJ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAU,EAAE;AAGjD,SAAO,CAAC,UAAe,QAAQ,OAAO;AAAA;;;;"}
@@ -4,7 +4,7 @@ function lag(key, options) {
4
4
  return (items) => {
5
5
  return items.map((_, i) => {
6
6
  const lagItem = items[i - n];
7
- return lagItem == null ? defaultValue : keyFn(lagItem);
7
+ return lagItem == null ? defaultValue : keyFn(lagItem, i, items);
8
8
  });
9
9
  };
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"lag.js","sources":["../../../src/vector/lag.ts"],"sourcesContent":["type LagOptions = {\n /** Number of positions to lag by (default: 1) */\n n?: number;\n /** The default value for non-existent rows. */\n default?: any;\n};\n\n/**\n * Returns a function that lags a vector by a specified offset (n). Useful for\n * finding previous values to compute deltas with later.\n * @param key The key or accessor to lag\n * @param options Options to configure roll. e.g. whether to run on partial windows.\n */\nexport function lag<T extends object>(\n key: keyof T | ((d: T) => any),\n options?: LagOptions | undefined | null\n) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n const { n = 1, default: defaultValue } = options ?? {};\n\n return (items: any[]) => {\n return items.map((_, i) => {\n const lagItem = items[i - n];\n return lagItem == null ? defaultValue : keyFn(lagItem);\n });\n };\n}\n"],"names":[],"mappings":"aAcE,KACA;AAEA,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,QAAM,CAAE,IAAI,GAAG,SAAS,gBAAiB,4BAAW;AAEpD,SAAO,CAAC;AACN,WAAO,MAAM,IAAI,CAAC,GAAG;AACnB,YAAM,UAAU,MAAM,IAAI;AAC1B,aAAO,WAAW,OAAO,eAAe,MAAM;AAAA;AAAA;AAAA;;;;"}
1
+ {"version":3,"file":"lag.js","sources":["../../../src/vector/lag.ts"],"sourcesContent":["type LagOptions = {\n /** Number of positions to lag by (default: 1) */\n n?: number;\n /** The default value for non-existent rows. */\n default?: any;\n};\n\n/**\n * Returns a function that lags a vector by a specified offset (n). Useful for\n * finding previous values to compute deltas with later.\n * @param key The key or accessor to lag\n * @param options Options to configure roll. e.g. whether to run on partial windows.\n */\nexport function lag<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => any),\n options?: LagOptions | undefined | null\n) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n const { n = 1, default: defaultValue } = options ?? {};\n\n return (items: T[]) => {\n return items.map((_, i) => {\n const lagItem = items[i - n];\n return lagItem == null ? defaultValue : keyFn(lagItem, i, items);\n });\n };\n}\n"],"names":[],"mappings":"aAcE,KACA;AAEA,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,QAAM,CAAE,IAAI,GAAG,SAAS,gBAAiB,4BAAW;AAEpD,SAAO,CAAC;AACN,WAAO,MAAM,IAAI,CAAC,GAAG;AACnB,YAAM,UAAU,MAAM,IAAI;AAC1B,aAAO,WAAW,OAAO,eAAe,MAAM,SAAS,GAAG;AAAA;AAAA;AAAA;;;;"}
@@ -4,7 +4,7 @@ function lead(key, options) {
4
4
  return (items) => {
5
5
  return items.map((_, i) => {
6
6
  const leadItem = items[i + n];
7
- return leadItem == null ? defaultValue : keyFn(leadItem);
7
+ return leadItem == null ? defaultValue : keyFn(leadItem, i, items);
8
8
  });
9
9
  };
10
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"lead.js","sources":["../../../src/vector/lead.ts"],"sourcesContent":["type LeadOptions = {\n /** Number of positions to lead by (default: 1) */\n n?: number;\n /** The default value for non-existent rows. */\n default?: any;\n};\n\n/**\n * Returns a functions that leads a vector by a specified offset (n). Useful for\n * finding next values for computing deltas with.\n * @param key The key or accessor to lead\n * @param options Options to configure roll. e.g. whether to run on partial windows.\n */\nexport function lead<T extends object>(\n key: keyof T | ((d: T) => any),\n options?: LeadOptions | undefined | null\n) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n const { n = 1, default: defaultValue } = options ?? {};\n\n return (items: any[]) => {\n return items.map((_, i) => {\n const leadItem = items[i + n];\n return leadItem == null ? defaultValue : keyFn(leadItem);\n });\n };\n}\n"],"names":[],"mappings":"cAcE,KACA;AAEA,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,QAAM,CAAE,IAAI,GAAG,SAAS,gBAAiB,4BAAW;AAEpD,SAAO,CAAC;AACN,WAAO,MAAM,IAAI,CAAC,GAAG;AACnB,YAAM,WAAW,MAAM,IAAI;AAC3B,aAAO,YAAY,OAAO,eAAe,MAAM;AAAA;AAAA;AAAA;;;;"}
1
+ {"version":3,"file":"lead.js","sources":["../../../src/vector/lead.ts"],"sourcesContent":["type LeadOptions = {\n /** Number of positions to lead by (default: 1) */\n n?: number;\n /** The default value for non-existent rows. */\n default?: any;\n};\n\n/**\n * Returns a functions that leads a vector by a specified offset (n). Useful for\n * finding next values for computing deltas with.\n * @param key The key or accessor to lead\n * @param options Options to configure roll. e.g. whether to run on partial windows.\n */\nexport function lead<T extends object>(\n key: keyof T | ((d: T, index: number, array: Iterable<T>) => any),\n options?: LeadOptions | undefined | null\n) {\n const keyFn = typeof key === 'function' ? key : (d: T) => d[key];\n\n const { n = 1, default: defaultValue } = options ?? {};\n\n return (items: T[]) => {\n return items.map((_, i) => {\n const leadItem = items[i + n];\n return leadItem == null ? defaultValue : keyFn(leadItem, i, items);\n });\n };\n}\n"],"names":[],"mappings":"cAcE,KACA;AAEA,QAAM,QAAQ,OAAO,QAAQ,aAAa,MAAM,CAAC,MAAS,EAAE;AAE5D,QAAM,CAAE,IAAI,GAAG,SAAS,gBAAiB,4BAAW;AAEpD,SAAO,CAAC;AACN,WAAO,MAAM,IAAI,CAAC,GAAG;AACnB,YAAM,WAAW,MAAM,IAAI;AAC3B,aAAO,YAAY,OAAO,eAAe,MAAM,UAAU,GAAG;AAAA;AAAA;AAAA;;;;"}
@@ -1,9 +1,10 @@
1
1
  function roll(width, rollFn, options) {
2
- const {partial = false} = options != null ? options : {};
2
+ const {partial = false, align = "right"} = options != null ? options : {};
3
+ const halfWidth = Math.floor(width / 2);
3
4
  return (items) => {
4
5
  return items.map((_, i) => {
5
- const endIndex = i;
6
- if (!partial && endIndex - width + 1 < 0) {
6
+ const endIndex = align === "right" ? i : align === "center" ? i + halfWidth : i + width - 1;
7
+ if (!partial && (endIndex - width + 1 < 0 || endIndex >= items.length)) {
7
8
  return void 0;
8
9
  }
9
10
  const startIndex = Math.max(0, endIndex - width + 1);
@@ -1 +1 @@
1
- {"version":3,"file":"roll.js","sources":["../../../src/vector/roll.ts"],"sourcesContent":["type RollOptions = {\n partial?: boolean;\n};\n\n/**\n * Returns a function that computes the a rolling value (e.g. moving average) by\n * applying a function over a window of data\n * @param width The size of the window\n * @param rollFn The function to apply to the window (should reduce to a single value)\n * @param options Options to configure roll. e.g. whether to run on partial windows.\n */\nexport function roll<T extends object>(\n width: number,\n rollFn: (itemsInWindow: T[], endIndex: number) => any,\n options?: RollOptions | undefined | null\n) {\n const { partial = false } = options ?? {};\n\n return (items: any[]) => {\n return items.map((_, i) => {\n const endIndex = i;\n\n // partial window and we don't allow partial computation, return undefined\n if (!partial && endIndex - width + 1 < 0) {\n return undefined;\n }\n\n const startIndex = Math.max(0, endIndex - width + 1);\n const itemsInWindow = items.slice(startIndex, endIndex + 1);\n\n // reduce them to a single value\n return rollFn(itemsInWindow, endIndex);\n });\n };\n}\n"],"names":[],"mappings":"cAYE,OACA,QACA;AAEA,QAAM,CAAE,UAAU,SAAU,4BAAW;AAEvC,SAAO,CAAC;AACN,WAAO,MAAM,IAAI,CAAC,GAAG;AACnB,YAAM,WAAW;AAGjB,UAAI,CAAC,WAAW,WAAW,QAAQ,IAAI;AACrC,eAAO;AAAA;AAGT,YAAM,aAAa,KAAK,IAAI,GAAG,WAAW,QAAQ;AAClD,YAAM,gBAAgB,MAAM,MAAM,YAAY,WAAW;AAGzD,aAAO,OAAO,eAAe;AAAA;AAAA;AAAA;;;;"}
1
+ {"version":3,"file":"roll.js","sources":["../../../src/vector/roll.ts"],"sourcesContent":["type RollOptions = {\n partial?: boolean;\n /** which direction the window is aligned to (default: right, looking back)\n * - right: current row is the last item [1,2,**3**]\n * - left: current row is the first item [**1**,2,3]\n * - center: current row is the center item [1,**2**,3]\n */\n align?: 'left' | 'center' | 'right';\n};\n\n/**\n * Returns a function that computes the a rolling value (e.g. moving average) by\n * applying a function over a window of data\n * @param width The size of the window\n * @param rollFn The function to apply to the window (should reduce to a single value)\n * @param options Options to configure roll. e.g. whether to run on partial windows.\n */\nexport function roll<T extends object>(\n width: number,\n rollFn: (itemsInWindow: T[], endIndex: number) => any,\n options?: RollOptions | undefined | null\n) {\n const { partial = false, align = 'right' } = options ?? {};\n\n const halfWidth = Math.floor(width / 2);\n\n return (items: any[]) => {\n return items.map((_, i) => {\n const endIndex =\n align === 'right'\n ? i\n : align === 'center'\n ? i + halfWidth\n : i + width - 1;\n\n // partial window and we don't allow partial computation, return undefined\n if (!partial && (endIndex - width + 1 < 0 || endIndex >= items.length)) {\n return undefined;\n }\n\n const startIndex = Math.max(0, endIndex - width + 1);\n const itemsInWindow = items.slice(startIndex, endIndex + 1);\n\n // reduce them to a single value\n return rollFn(itemsInWindow, endIndex);\n });\n };\n}\n"],"names":[],"mappings":"cAkBE,OACA,QACA;AAEA,QAAM,CAAE,UAAU,OAAO,QAAQ,WAAY,4BAAW;AAExD,QAAM,YAAY,KAAK,MAAM,QAAQ;AAErC,SAAO,CAAC;AACN,WAAO,MAAM,IAAI,CAAC,GAAG;AACnB,YAAM,WACJ,UAAU,UACN,IACA,UAAU,WACV,IAAI,YACJ,IAAI,QAAQ;AAGlB,UAAI,CAAC,uBAAuB,QAAQ,IAAI,KAAK,YAAY,MAAM;AAC7D,eAAO;AAAA;AAGT,YAAM,aAAa,KAAK,IAAI,GAAG,WAAW,QAAQ;AAClD,YAAM,gBAAgB,MAAM,MAAM,YAAY,WAAW;AAGzD,aAAO,OAAO,eAAe;AAAA;AAAA;AAAA;;;;"}
@@ -0,0 +1,10 @@
1
+ function rowNumber(options) {
2
+ var _a;
3
+ const startAt = (_a = options == null ? void 0 : options.startAt) != null ? _a : 0;
4
+ return (items) => {
5
+ return items.map((_, i) => i + startAt);
6
+ };
7
+ }
8
+
9
+ export { rowNumber };
10
+ //# sourceMappingURL=rowNumber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rowNumber.js","sources":["../../../src/vector/rowNumber.ts"],"sourcesContent":["type RowNumberOptions = {\n /** what to start row numbers at, default is 0 */\n startAt?: number;\n};\n\n/**\n * Returns a vector of row numbers, starting at 0\n */\nexport function rowNumber<T>(options?: RowNumberOptions) {\n const startAt = options?.startAt ?? 0;\n return (items: T[]) => {\n return items.map((_, i) => i + startAt);\n };\n}\n"],"names":[],"mappings":"mBAQ6B;AAR7B;AASE,QAAM,UAAU,yCAAS,YAAT,YAAoB;AACpC,SAAO,CAAC;AACN,WAAO,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI;AAAA;AAAA;;;;"}
@@ -7,6 +7,7 @@ var assignGroupKeys = require('./helpers/assignGroupKeys.js');
7
7
  var groupMap = require('./helpers/groupMap.js');
8
8
  var groupTraversal = require('./helpers/groupTraversal.js');
9
9
  var identity = require('./helpers/identity.js');
10
+ var isObject = require('./helpers/isObject.js');
10
11
  var singleOrArray = require('./helpers/singleOrArray.js');
11
12
 
12
13
  function groupBy(groupKeys, fns, options) {
@@ -76,7 +77,7 @@ function makeGrouped(items, groupKeys) {
76
77
  const keyCache = new Map();
77
78
  return (d) => {
78
79
  const keyValue = keyFn(d);
79
- const keyValueOf = typeof keyValue === "object" ? keyValue.valueOf() : keyValue;
80
+ const keyValueOf = isObject.isObject(keyValue) ? keyValue.valueOf() : keyValue;
80
81
  if (keyCache.has(keyValueOf)) {
81
82
  return keyCache.get(keyValueOf);
82
83
  }