UNPKG

remeda

Version:

A utility library for JavaScript and Typescript.

1 lines 6.33 kB
{"version":3,"file":"flat.cjs","names":["lazyDataLastImpl","lazyIdentityEvaluator"],"sources":["../src/flat.ts"],"sourcesContent":["import type { IsNumericLiteral } from \"type-fest\";\nimport { lazyDataLastImpl } from \"./internal/lazyDataLastImpl\";\nimport type { IterableContainer } from \"./internal/types/IterableContainer\";\nimport type { LazyEvaluator } from \"./internal/types/LazyEvaluator\";\nimport type { LazyResult } from \"./internal/types/LazyResult\";\nimport { lazyIdentityEvaluator } from \"./internal/utilityEvaluators\";\n\ntype FlatArray<\n T,\n Depth extends number,\n Iteration extends ReadonlyArray<unknown> = [],\n> = Depth extends Iteration[\"length\"]\n ? // Stopping condition for the recursion when the array is a tuple.\n T\n : T extends readonly []\n ? // Trivial result when the array is empty.\n []\n : T extends readonly [infer Item, ...infer Rest]\n ? // Tuples could be special-cased by \"iterating\" over each item\n // separately so that we maintain more information from the input type,\n // instead of putting all values in a union.\n [\n ...(Item extends IterableContainer\n ? // If the item itself is an array we continue going deeper\n FlatArray<Item, Depth, [...Iteration, unknown]>\n : // But if it isn't we add it to the output tuple\n [Item]),\n // And we merge this with the result from the rest of the tuple.\n ...FlatArray<Rest, Depth, Iteration>,\n ]\n : // For simple arrays we compute the item type, and wrap it with an\n // array.\n Array<FlatSimpleArrayItems<T, Depth, Iteration>>;\n\n// This type is based on the built-in type for `Array.prototype.flat` from the\n// ES2019 Array typescript library, but we improved it to handle any depth\n// (avoiding the fixed `20` in the built-in type).\n// @see https://github.com/microsoft/TypeScript/blob/main/src/lib/es2019.array.d.ts#L1-L5\ntype FlatSimpleArrayItems<\n T,\n Depth extends number,\n Iteration extends ReadonlyArray<unknown> = [],\n IsDone extends boolean = false,\n> = {\n done: T;\n recur: T extends ReadonlyArray<infer InnerArr>\n ? FlatSimpleArrayItems<\n InnerArr,\n Depth,\n [...Iteration, unknown],\n // This trick allows us to continue 1 iteration more than the depth,\n // which is required to flatten the array up to depth.\n Iteration[\"length\"] extends Depth ? true : false\n >\n : T;\n}[IsDone extends true ? \"done\" : \"recur\"];\n\n/**\n * Creates a new array with all sub-array elements concatenated into it\n * recursively up to the specified depth. Equivalent to the built-in\n * `Array.prototype.flat` method.\n *\n * @param data - The items to flatten.\n * @param depth - The depth level specifying how deep a nested array structure\n * should be flattened. Defaults to 1. Non literal values (those typed as\n * `number`cannot be used. `Infinity`, `Number.POSITIVE_INFINITY` and\n * `Number.MAX_VALUE` are all typed as `number` and can't be used either. For\n * \"unlimited\" depth use a literal value that would exceed your expected\n * practical maximum nesting level.\n * @signature\n * R.flat(data)\n * R.flat(data, depth)\n * @example\n * R.flat([[1, 2], [3, 4], [5], [[6]]]); // => [1, 2, 3, 4, 5, [6]]\n * R.flat([[[1]], [[2]]], 2); // => [1, 2]\n * @dataFirst\n * @lazy\n * @category Array\n */\nexport function flat<T extends IterableContainer, Depth extends number = 1>(\n data: T,\n depth?: IsNumericLiteral<Depth> extends true ? Depth : never,\n): FlatArray<T, Depth>;\n\n/**\n * Creates a new array with all sub-array elements concatenated into it\n * recursively up to the specified depth. Equivalent to the built-in\n * `Array.prototype.flat` method.\n *\n * @param depth - The depth level specifying how deep a nested array structure\n * should be flattened. Defaults to 1.\n * @signature\n * R.flat()(data)\n * R.flat(depth)(data)\n * @example\n * R.pipe([[1, 2], [3, 4], [5], [[6]]], R.flat()); // => [1, 2, 3, 4, 5, [6]]\n * R.pipe([[[1]], [[2]]], R.flat(2)); // => [1, 2]\n * @dataLast\n * @lazy\n * @category Array\n */\nexport function flat<Depth extends number = 1>(\n depth?: IsNumericLiteral<Depth> extends true ? Depth : never,\n): <T extends IterableContainer>(data: T) => FlatArray<T, Depth>;\n\nexport function flat(\n dataOrDepth?: IterableContainer | number,\n depth?: number,\n): unknown {\n if (typeof dataOrDepth === \"object\") {\n return flatImplementation(dataOrDepth, depth);\n }\n\n return lazyDataLastImpl(\n flatImplementation,\n dataOrDepth === undefined ? [] : [dataOrDepth],\n lazyImplementation,\n );\n}\n\nconst flatImplementation = (\n data: IterableContainer,\n depth?: number,\n): IterableContainer => (depth === undefined ? data.flat() : data.flat(depth));\n\nconst lazyImplementation = (depth?: number): LazyEvaluator =>\n depth === undefined || depth === 1\n ? lazyShallow\n : depth <= 0\n ? lazyIdentityEvaluator\n : (value) =>\n Array.isArray(value)\n ? {\n next: value.flat(depth - 1),\n hasNext: true,\n hasMany: true,\n done: false,\n }\n : { next: value, hasNext: true, done: false };\n\n// This function is pulled out so that we don't generate a new arrow function\n// each time. Because it doesn't need to run with recursion it could be pulled\n// out from the lazyImplementation and be reused for all invocations.\nconst lazyShallow = <T>(value: T): LazyResult<T> =>\n Array.isArray(value)\n ? { next: value, hasNext: true, hasMany: true, done: false }\n : { next: value, hasNext: true, done: false };\n"],"mappings":"iGAyGA,SAAgB,EACd,EACA,EACS,CAKT,OAJI,OAAO,GAAgB,SAClB,EAAmB,EAAa,EAAM,CAGxCA,EAAAA,EACL,EACA,IAAgB,IAAA,GAAY,EAAE,CAAG,CAAC,EAAY,CAC9C,EACD,CAGH,MAAM,GACJ,EACA,IACuB,IAAU,IAAA,GAAY,EAAK,MAAM,CAAG,EAAK,KAAK,EAAM,CAEvE,EAAsB,GAC1B,IAAU,IAAA,IAAa,IAAU,EAC7B,EACA,GAAS,EACPC,EAAAA,EACC,GACC,MAAM,QAAQ,EAAM,CAChB,CACE,KAAM,EAAM,KAAK,EAAQ,EAAE,CAC3B,QAAS,GACT,QAAS,GACT,KAAM,GACP,CACD,CAAE,KAAM,EAAO,QAAS,GAAM,KAAM,GAAO,CAKnD,EAAkB,GACtB,MAAM,QAAQ,EAAM,CAChB,CAAE,KAAM,EAAO,QAAS,GAAM,QAAS,GAAM,KAAM,GAAO,CAC1D,CAAE,KAAM,EAAO,QAAS,GAAM,KAAM,GAAO"}