@tidyjs/tidy 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/groupBy.js.map +1 -1
- package/dist/es/helpers/assignGroupKeys.js +1 -1
- package/dist/es/helpers/assignGroupKeys.js.map +1 -1
- package/dist/es/mutate.js.map +1 -1
- package/dist/es/total.js.map +1 -1
- package/dist/lib/groupBy.js.map +1 -1
- package/dist/lib/helpers/assignGroupKeys.js +1 -1
- package/dist/lib/helpers/assignGroupKeys.js.map +1 -1
- package/dist/lib/mutate.js.map +1 -1
- package/dist/lib/total.js.map +1 -1
- package/dist/tidy.d.ts +853 -13
- package/dist/umd/tidy.js +1 -1
- package/dist/umd/tidy.js.map +1 -1
- package/dist/umd/tidy.min.js +1 -1
- package/dist/umd/tidy.min.js.map +1 -1
- package/package.json +2 -2
package/dist/es/groupBy.js.map
CHANGED
|
@@ -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 { 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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"}
|
|
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\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\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, Keys extends GK<T>>(groupKeys: Keys, fns: F<T, T1>): GroupByFn<T, T1, Keys, GroupByOptions>;\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, T7 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>, F<T6, T7>]): GroupByFn<T, T7, Keys, GroupByOptions>;\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, T6 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>]): GroupByFn<T, T6, Keys, GroupByOptions>;\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, T5 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>]): GroupByFn<T, T5, Keys, GroupByOptions>;\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, T4 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>]): GroupByFn<T, T4, Keys, GroupByOptions>;\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, T3 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>]): GroupByFn<T, T3, Keys, GroupByOptions>;\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, T2 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>]): GroupByFn<T, T2, Keys, GroupByOptions>;\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, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>]): GroupByFn<T, T1, Keys, GroupByOptions>;\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>>(groupKeys: Keys, fns: []): GroupByFn<T, T, Keys, GroupByOptions>;\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>;\n// prettier-ignore\nexport function groupBy<T extends object, Keys extends GK<T>>(groupKeys: Keys): GroupByFn<T, T, Keys, GroupByOptions>;\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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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
function assignGroupKeys(d, keys) {
|
|
2
2
|
if (d == null || typeof d !== "object" || Array.isArray(d))
|
|
3
3
|
return d;
|
|
4
|
-
const keysObj = Object.fromEntries(keys.filter((key) => typeof key[0] !== "function"));
|
|
4
|
+
const keysObj = Object.fromEntries(keys.filter((key) => typeof key[0] !== "function" && key[0] != null));
|
|
5
5
|
return Object.assign(keysObj, d);
|
|
6
6
|
}
|
|
7
7
|
|
|
@@ -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')\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;
|
|
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;;;;"}
|
package/dist/es/mutate.js.map
CHANGED
|
@@ -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> =\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>> =
|
|
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;;;;"}
|
package/dist/es/total.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"total.js","sources":["../../src/total.ts"],"sourcesContent":["import { mutate, MutateSpec } from './mutate';\nimport {\n SummarizeSpec,\n summarize,\n summarizeAll,\n summarizeAt,\n summarizeIf,\n SummaryKeyFn,\n} from './summarize';\nimport { TidyFn, Vector } from './types';\n\n/**\n * Adds a summarized total row\n */\nexport function total<\n T extends object,\n SummarizedSpec extends SummarizeSpec<T> = SummarizeSpec<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summarizeSpec: SummarizedSpec, mutateSpec: MutSpec): TidyFn<T> {\n const _total: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarize<T, SummarizedSpec>(summarizeSpec)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _total;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAll<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAll: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAll<T, F>(summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _totalAll;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalIf<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(\n predicateFn: (vector: Vector<T>) => boolean,\n summaryFn: F,\n mutateSpec: MutSpec\n): TidyFn<T> {\n const _totalIf: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeIf<T, F>(predicateFn, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _totalIf;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAt<\n T extends object,\n Keys extends (keyof T)[],\n F extends SummaryKeyFn<T, Keys[number]>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(keys: Keys, summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAt: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAt<T, Keys, F>(keys, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _totalAt;\n}\n"],"names":[],"mappings":";;;eAkBE,eAA+B;AAC/B,QAAM,SAAuB,CAAC;AAC5B,UAAM,aAAa,UAA6B,eAAe;AAC/D,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;kBAYP,WAAc;AACd,QAAM,YAA0B,CAAC;AAC/B,UAAM,aAAa,aAAmB,WAAW;AACjD,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,aACA,WACA;AAEA,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAa,YAAkB,aAAa,WAAW;AAC7D,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,MAAY,WAAc;AAC1B,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAa,YAAwB,MAAM,WAAW;AAC5D,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"total.js","sources":["../../src/total.ts"],"sourcesContent":["import { mutate, MutateSpec } from './mutate';\nimport {\n SummarizeSpec,\n summarize,\n summarizeAll,\n summarizeAt,\n summarizeIf,\n SummaryKeyFn,\n} from './summarize';\nimport { TidyFn, Vector } from './types';\n\n/**\n * Adds a summarized total row\n */\nexport function total<\n T extends object,\n SummarizedSpec extends SummarizeSpec<T> = SummarizeSpec<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summarizeSpec: SummarizedSpec, mutateSpec: MutSpec): TidyFn<T> {\n const _total: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarize<T, SummarizedSpec>(summarizeSpec)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _total;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAll<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAll: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAll<T, F>(summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _totalAll;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalIf<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(\n predicateFn: (vector: Vector<T>) => boolean,\n summaryFn: F,\n mutateSpec: MutSpec\n): TidyFn<T> {\n const _totalIf: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeIf<T, F>(predicateFn, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _totalIf;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAt<\n T extends object,\n Keys extends (keyof T)[],\n F extends SummaryKeyFn<T, Keys[number]>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(keys: Keys, summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAt: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAt<T, Keys, F>(keys, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _totalAt;\n}\n"],"names":[],"mappings":";;;eAkBE,eAA+B;AAC/B,QAAM,SAAuB,CAAC;AAC5B,UAAM,aAAa,UAA6B,eAAe;AAC/D,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;kBAYP,WAAc;AACd,QAAM,YAA0B,CAAC;AAC/B,UAAM,aAAa,aAAmB,WAAW;AACjD,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,aACA,WACA;AAEA,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAa,YAAkB,aAAa,WAAW;AAC7D,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,MAAY,WAAc;AAC1B,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAa,YAAwB,MAAM,WAAW;AAC5D,UAAM,UAAU,OAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;;;;"}
|
package/dist/lib/groupBy.js.map
CHANGED
|
@@ -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 { 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":["groupMap","assignGroupKeys","singleOrArray","isObject","group","identity","groupTraversal"],"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\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\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, Keys extends GK<T>>(groupKeys: Keys, fns: F<T, T1>): GroupByFn<T, T1, Keys, GroupByOptions>;\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, T7 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>, F<T6, T7>]): GroupByFn<T, T7, Keys, GroupByOptions>;\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, T6 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>, F<T5, T6>]): GroupByFn<T, T6, Keys, GroupByOptions>;\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, T5 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>, F<T4, T5>]): GroupByFn<T, T5, Keys, GroupByOptions>;\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, T4 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>, F<T3, T4>]): GroupByFn<T, T4, Keys, GroupByOptions>;\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, T3 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>, F<T2, T3>]): GroupByFn<T, T3, Keys, GroupByOptions>;\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, T2 extends object, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>, F<T1, T2>]): GroupByFn<T, T2, Keys, GroupByOptions>;\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, Keys extends GK<T>>(groupKeys: Keys, fns: [F<T, T1>]): GroupByFn<T, T1, Keys, GroupByOptions>;\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>>(groupKeys: Keys, fns: []): GroupByFn<T, T, Keys, GroupByOptions>;\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>;\n// prettier-ignore\nexport function groupBy<T extends object, Keys extends GK<T>>(groupKeys: Keys): GroupByFn<T, T, Keys, GroupByOptions>;\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":["groupMap","assignGroupKeys","singleOrArray","isObject","group","identity","groupTraversal"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
function assignGroupKeys(d, keys) {
|
|
6
6
|
if (d == null || typeof d !== "object" || Array.isArray(d))
|
|
7
7
|
return d;
|
|
8
|
-
const keysObj = Object.fromEntries(keys.filter((key) => typeof key[0] !== "function"));
|
|
8
|
+
const keysObj = Object.fromEntries(keys.filter((key) => typeof key[0] !== "function" && key[0] != null));
|
|
9
9
|
return Object.assign(keysObj, d);
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -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')\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;
|
|
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;;;;"}
|
package/dist/lib/mutate.js.map
CHANGED
|
@@ -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> =\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>> =
|
|
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;;;;"}
|
package/dist/lib/total.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"total.js","sources":["../../src/total.ts"],"sourcesContent":["import { mutate, MutateSpec } from './mutate';\nimport {\n SummarizeSpec,\n summarize,\n summarizeAll,\n summarizeAt,\n summarizeIf,\n SummaryKeyFn,\n} from './summarize';\nimport { TidyFn, Vector } from './types';\n\n/**\n * Adds a summarized total row\n */\nexport function total<\n T extends object,\n SummarizedSpec extends SummarizeSpec<T> = SummarizeSpec<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summarizeSpec: SummarizedSpec, mutateSpec: MutSpec): TidyFn<T> {\n const _total: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarize<T, SummarizedSpec>(summarizeSpec)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _total;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAll<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAll: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAll<T, F>(summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _totalAll;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalIf<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(\n predicateFn: (vector: Vector<T>) => boolean,\n summaryFn: F,\n mutateSpec: MutSpec\n): TidyFn<T> {\n const _totalIf: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeIf<T, F>(predicateFn, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _totalIf;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAt<\n T extends object,\n Keys extends (keyof T)[],\n F extends SummaryKeyFn<T, Keys[number]>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(keys: Keys, summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAt: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAt<T, Keys, F>(keys, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]);\n return [...items, ...mutated];\n };\n\n return _totalAt;\n}\n"],"names":["summarize","mutate","summarizeAll","summarizeIf","summarizeAt"],"mappings":";;;;;;;eAkBE,eAA+B;AAC/B,QAAM,SAAuB,CAAC;AAC5B,UAAM,aAAaA,oBAA6B,eAAe;AAC/D,UAAM,UAAUC,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;kBAYP,WAAc;AACd,QAAM,YAA0B,CAAC;AAC/B,UAAM,aAAaC,uBAAmB,WAAW;AACjD,UAAM,UAAUD,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,aACA,WACA;AAEA,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAaE,sBAAkB,aAAa,WAAW;AAC7D,UAAM,UAAUF,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,MAAY,WAAc;AAC1B,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAaG,sBAAwB,MAAM,WAAW;AAC5D,UAAM,UAAUH,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"total.js","sources":["../../src/total.ts"],"sourcesContent":["import { mutate, MutateSpec } from './mutate';\nimport {\n SummarizeSpec,\n summarize,\n summarizeAll,\n summarizeAt,\n summarizeIf,\n SummaryKeyFn,\n} from './summarize';\nimport { TidyFn, Vector } from './types';\n\n/**\n * Adds a summarized total row\n */\nexport function total<\n T extends object,\n SummarizedSpec extends SummarizeSpec<T> = SummarizeSpec<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summarizeSpec: SummarizedSpec, mutateSpec: MutSpec): TidyFn<T> {\n const _total: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarize<T, SummarizedSpec>(summarizeSpec)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _total;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAll<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAll: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAll<T, F>(summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _totalAll;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalIf<\n T extends object,\n F extends SummaryKeyFn<T>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(\n predicateFn: (vector: Vector<T>) => boolean,\n summaryFn: F,\n mutateSpec: MutSpec\n): TidyFn<T> {\n const _totalIf: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeIf<T, F>(predicateFn, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _totalIf;\n}\n\n// ----------------------------------------------------------------------------\n\n/**\n * Adds a summarized total row\n */\nexport function totalAt<\n T extends object,\n Keys extends (keyof T)[],\n F extends SummaryKeyFn<T, Keys[number]>,\n MutSpec extends MutateSpec<T> = MutateSpec<T>\n>(keys: Keys, summaryFn: F, mutateSpec: MutSpec): TidyFn<T> {\n const _totalAt: TidyFn<T, T> = (items: T[]): T[] => {\n const summarized = summarizeAt<T, Keys, F>(keys, summaryFn)(items);\n const mutated = mutate<T, MutSpec>(mutateSpec)(summarized as T[]) as T[];\n return [...items, ...mutated];\n };\n\n return _totalAt;\n}\n"],"names":["summarize","mutate","summarizeAll","summarizeIf","summarizeAt"],"mappings":";;;;;;;eAkBE,eAA+B;AAC/B,QAAM,SAAuB,CAAC;AAC5B,UAAM,aAAaA,oBAA6B,eAAe;AAC/D,UAAM,UAAUC,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;kBAYP,WAAc;AACd,QAAM,YAA0B,CAAC;AAC/B,UAAM,aAAaC,uBAAmB,WAAW;AACjD,UAAM,UAAUD,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,aACA,WACA;AAEA,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAaE,sBAAkB,aAAa,WAAW;AAC7D,UAAM,UAAUF,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;iBAaP,MAAY,WAAc;AAC1B,QAAM,WAAyB,CAAC;AAC9B,UAAM,aAAaG,sBAAwB,MAAM,WAAW;AAC5D,UAAM,UAAUH,cAAmB,YAAY;AAC/C,WAAO,CAAC,GAAG,OAAO,GAAG;AAAA;AAGvB,SAAO;AAAA;;;;;;;"}
|