satyacode
Background
Back to js-functions

10-masala-blender.js

JavaScript
1/**
2 * 🌶️ Masala Spice Blender - Function Composition
3 *
4 * Masala factory mein spices ko process karna hai. Function composition
5 * use karke chhote chhote functions ko jodke ek bada pipeline banao.
6 *
7 * Functions:
8 *
9 *   1. pipe(...fns)
10 *      - Takes any number of functions
11 *      - Returns a NEW function that applies them LEFT to RIGHT
12 *      - pipe(f, g, h)(x) means h(g(f(x)))
13 *      - Agar no functions given, return identity function (x => x)
14 *
15 *   2. compose(...fns)
16 *      - Takes any number of functions
17 *      - Returns a NEW function that applies them RIGHT to LEFT
18 *      - compose(f, g, h)(x) means f(g(h(x)))
19 *      - Agar no functions given, return identity function (x => x)
20 *
21 *   Utility functions (simple transformations):
22 *
23 *   3. grind(spice)
24 *      - Returns: { ...spice, form: "powder" }
25 *
26 *   4. roast(spice)
27 *      - Returns: { ...spice, roasted: true, aroma: "strong" }
28 *
29 *   5. mix(spice)
30 *      - Returns: { ...spice, mixed: true }
31 *
32 *   6. pack(spice)
33 *      - Returns: { ...spice, packed: true, label: `${spice.name} Masala` }
34 *
35 *   7. createRecipe(steps)
36 *      - steps: array of step name strings, e.g., ["grind", "roast", "pack"]
37 *      - Maps step names to functions: "grind"=>grind, "roast"=>roast,
38 *        "mix"=>mix, "pack"=>pack
39 *      - Returns a piped function that applies steps in order
40 *      - Unknown step names are skipped
41 *      - Agar steps empty or not array, return identity function
42 *
43 * Hint: pipe and compose are the building blocks of functional programming.
44 *   pipe uses reduce left-to-right, compose uses reduceRight.
45 *
46 * @example
47 *   const process = pipe(grind, roast, pack);
48 *   process({ name: "Garam" })
49 *   // => { name: "Garam", form: "powder", roasted: true, aroma: "strong", packed: true, label: "Garam Masala" }
50 *
51 *   const recipe = createRecipe(["grind", "pack"]);
52 *   recipe({ name: "Haldi" })
53 *   // => { name: "Haldi", form: "powder", packed: true, label: "Haldi Masala" }
54 */
55export function pipe(...fns) {
56  if(fns.length === 0){
57    return (x)=> x
58  }
59
60  return (x)=> fns.reduce((result, fn)=> fn(result),x)
61}
62
63export function compose(...fns) {
64  if (fns.length === 0) return (x) => x
65  return (x) => fns.reduceRight((result, fn) => fn(result), x)
66}
67
68export function grind(spice) {
69   return { ...spice, form: "powder" }
70}
71
72export function roast(spice) {
73  return { ...spice, roasted: true, aroma: "strong" }
74}
75
76export function mix(spice) {
77  return { ...spice, mixed: true }
78}
79
80export function pack(spice) {
81  return { ...spice, packed: true, label: `${spice.name} Masala` }
82}
83
84export function createRecipe(steps) {
85  const stepMap = {
86    grind: grind,
87    roast: roast,
88    mix:   mix,
89    pack:  pack,
90  }
91
92  if (!Array.isArray(steps) || steps.length === 0) return (x) => x;
93  const fns = steps.filter((step) => stepMap[step]).map((step) => stepMap[step])
94
95  if (fns.length === 0) return (x) => x
96  return pipe(...fns)
97}
98