Complex, deeply nested data is painful. Let's simplify it! ✅ wildcard(
*) supported dot notation for accessing complex deeply nested data viadata_get,data_set,data_fill, &data_forget
✅ tap for side effects
✅ retry for async data fetching
✅ value for conditional function execution
✅ filled for checking if a value is not blank or empty
✅ blank for checking if a value is considered blank or empty
✅ throw_if and throw_unless for cleaning up try/catch blocks
✅ optional for safe access to potentially null or undefined objects
✅ transform for transforming a value if it's not blank, otherwise returns a default value
constdata={family: {children: [{name: "Sarah"},{name: "Tom"},{name: "Anthony"}]}};data_get("family.children.1.name",data)// "Tom"data_get("family.children.*.name",data)// ["Sarah", "Tom", "Anthony"]data_set("family.children.1.name","Tommy",data)data_get("family.children.1.name",data)// "Tommy" data_get("family.children.*",data)// [{ name: "Sarah" }, { name: "Tommy" }, { name: "Anthony" }]data_fill("family.children.1.name","Tommy",data)// ["Sarah", "Tommy", "Anthony"]data_fill("family.children.3.name","Andrew",data)data_get("family.children",data)// // [{ name: "Sarah" }, { name: "Tommy" }, { name: "Anthony" }, { name: "Andrew" }]data_get("family.children.name.*",data)// ["Sarah", "Tommy", "Anthony", "Andrew"]data_forget("family.children.1",data)data_get("family.children",data)// [{ name: "Sarah" }, { name: "Anthony" }, { name: "Andrew" }]data_forget("family.children.*",data)data_get("family.children",data)// []Safely retrieves a value from a nested object or array using dot notation.
import{data_get}from"@findhow/dotdotdata";constdata={user: {profile: {name: "John Doe",address: {city: "New York"}},posts: [{title: "First Post",comments: 5},{title: "Second Post",comments: 3}]}};console.log(data_get(data,'user.profile.name'));// "John Doe"console.log(data_get(data,'user.posts.1.title'));// "Second Post"console.log(data_get(data,'user.settings.theme','default'));// "default"console.log(data_get(data,'user.posts.*.comments'));// [5, 3]Sets a value in a nested object or array using dot notation, creating intermediate objects/arrays as needed.
import{data_set}from"@findhow/dotdotdata";letuser={};data_set(user,'profile.name','Jane Doe');data_set(user,'settings.notifications.email',true);data_set(user,'posts.0.title','My First Post');console.log(user);// {// profile: { name: 'Jane Doe' },// settings: { notifications: { email: true }},// posts: [{ title: 'My First Post' }]// }Fills a value in an object if it doesn't exist, without overwriting existing values.
import{data_fill}from"@findhow/dotdotdata";letconfig={app: {name: "MyApp",version: "1.0.0"}};data_fill(config,'app.debug',true);data_fill(config,'app.name','NewName');// Won't overwrite existing valuedata_fill(config,'database.host','localhost');console.log(config);// {// app: {// name: "MyApp",// version: "1.0.0",// debug: true// },// database: {// host: "localhost"// }// }Removes an item from an array or object using dot notation.
import{data_forget}from"@findhow/dotdotdata";letdata={user: {profile: {name: "John",age: 30},posts: [{id: 1,title: "Post 1"},{id: 2,title: "Post 2"}]}};data_forget(data,'user.profile.age');data_forget(data,'user.posts.0');console.log(data);// {// user: {// profile: { name: "John" },// posts: [{ id: 2, title: "Post 2" }]// }// }Provides safe access to properties of potentially null or undefined objects.
import{optional}from"@findhow/dotdotdata";constuser=null;console.log(optional(user)?.name?.toUpperCase());// undefined (no error thrown)constvalidUser={name: "Alice",getAge: ()=>25};console.log(optional(validUser).name);// "Alice"console.log(optional(validUser).getAge?.());// 25Checks if a value is considered blank or empty.
import{blank}from"@findhow/dotdotdata";console.log(blank(""));// trueconsole.log(blank(null));// trueconsole.log(blank(undefined));// trueconsole.log(blank([]));// trueconsole.log(blank({}));// trueconsole.log(blank(0));// falseconsole.log(blank(false));// falseChecks if a value is not blank or empty.
import{filled}from"@findhow/dotdotdata";console.log(filled("Hello"));// trueconsole.log(filled([1,2,3]));// trueconsole.log(filled({key: "value"}));// trueconsole.log(filled(""));// falseconsole.log(filled(null));// falseTransforms a value if it's not blank, otherwise returns a default value.
import{transform}from"@findhow/dotdotdata";constresult1=transform("hello",(str)=>str.toUpperCase());console.log(result1);// "HELLO"constresult2=transform("",(str)=>str.toUpperCase(),"DEFAULT");console.log(result2);// "DEFAULT"constresult3=transform(null,(val)=>val*2,()=>"COMPUTED DEFAULT");console.log(result3);// "COMPUTED DEFAULT"Attempts to execute a callback until it succeeds or the maximum attempt count is reached.
import{retry}from"@findhow/dotdotdata";constfetchData=async()=>{constresponse=awaitfetch('https://api.example.com/data');if(!response.ok)thrownewError('Failed to fetch');returnresponse.json();};try{constdata=awaitretry(fetchData,3,1000);console.log(data);}catch(error){console.error("All attempts failed:",error);}Passes the value to a callback function and returns the original value, useful for performing side effects.
import{tap}from"@findhow/dotdotdata";constresult=[1,2,3,4,5].map(n=>n*2).tap(arr=>console.log("Doubled array:",arr)).filter(n=>n>5);console.log(result);// [6, 8, 10]Throw exceptions based on conditions.
import{throw_if,throw_unless}from"@findhow/dotdotdata";functionprocessAge(age: number){throw_if(age<0,Error,"Age cannot be negative");throw_unless(age>=18,Error,"Must be at least 18 years old");console.log("Age processed successfully");}try{processAge(20);// Age processed successfullyprocessAge(15);// Throws: Error: Must be at least 18 years oldprocessAge(-5);// Throws: Error: Age cannot be negative}catch(error){console.error(error);}Returns the value if it's not a function, otherwise calls the function and returns its result.
import{value}from"@findhow/dotdotdata";console.log(value(5));// 5console.log(value(()=>10));// 10constconfig={debug: true,logLevel: ()=>process.env.LOG_LEVEL||'info'};console.log(value(config.debug));// trueconsole.log(value(config.logLevel));// 'info' (assuming process.env.LOG_LEVEL is not set)Let's walk through a scenario of managing a library system using our helper functions. This example will demonstrate how these functions can simplify complex data operations.
import{data_get,data_set,optional,transform}from"@findhow/dotdotdata";constcomplexData={users: [{id: 1,name: "Alice",details: {age: 30,city: "New York"}},{id: 2,name: "Bob",details: null},{id: 3,name: "Charlie"}],settings: {theme: "dark",notifications: {email: true,push: false}}};// Safely access nested propertiesconstaliceCity=data_get(complexData,'users.0.details.city','Unknown');console.log(aliceCity);// "New York"constbobAge=data_get(complexData,'users.1.details.age','N/A');console.log(bobAge);// "N/A"// Use optional chaining for nullable objectsconstbobDetails=optional(complexData.users[1].details);console.log(bobDetails?.age);// undefined (no error thrown)// Transform data safelyconstuserCities=complexData.users.map(user=>transform(user.details,details=>details.city,'Unknown'));console.log(userCities);// ["New York", "Unknown", "Unknown"]// Modify nested datadata_set(complexData,'users.1.details',{age: 25,city: "London"});data_set(complexData,'settings.notifications.sms',true);console.log(complexData.users[1].details);// { age: 25, city: "London" }console.log(complexData.settings.notifications);// { email: true, push: false, sms: true }import{data_get}from"@findhow/dotdotdata";constdata={user: {profile: {name: "John Doe",address: {city: "New York"}},posts: [{title: "First Post",comments: 5},{title: "Second Post",comments: 3}]}};data_get(data,'user.profile.name');// "John Doe"data_get(data,'user.posts.1.title');// "Second Post"data_get(data,'user.settings.theme','default');// "default"data_get(data,'user.posts.*.title');// ["First Post", "Second Post"]import{data_set}from"@findhow/dotdotdata";letuser={};data_set(user,'profile.name','Jane Doe');data_set(user,'settings.notifications.email',true);data_set(user,'posts.0.title','My First Post');data_set(user,'posts.1.title','My Second Post');console.log(user);// {// profile: { name: 'Jane Doe' },// settings: { notifications: { email: true }},// posts: [{ title: 'My First Post' }, { title: 'My Second Post' }]// }// data_set wildcarddata_set(user,'posts.*.title','Wildcard Post');console.log(user);// {// profile: { name: 'Jane Doe' },// settings: { notifications: { email: true }},// posts: [{ title: 'Wildcard Post' }, { title: 'Wildcard Post' }]// }import{data_fill}from"@findhow/dotdotdata";letconfig={app: {name: "MyApp",version: "1.0.0"}};data_fill(config,'app.debug',true);data_fill(config,'app.name','NewName');// Won't overwrite existing valuedata_fill(config,'database.host','localhost');console.log(config);// {// app: {// name: "MyApp",// version: "1.0.0",// debug: true// },// database: {// host: "localhost"// }// }import{data_forget}from"@findhow/dotdotdata";letdata={user: {profile: {name: "John",age: 30},posts: [{id: 1,title: "Post 1"},{id: 2,title: "Post 2"}]}};data_forget(data,'user.profile.age');data_forget(data,'user.posts.0');console.log(data);// {// user: {// profile: { name: "John" },// posts: [{ id: 2, title: "Post 2" }]// }// }import{optional}from"@findhow/dotdotdata";constuser=null;console.log(optional(user)?.name?.toUpperCase());// undefined (no error thrown)constvalidUser={name: "Alice",getAge: ()=>25};console.log(optional(validUser).name);// "Alice"console.log(optional(validUser).getAge?.());// 25