Overview
The PathResolver handles safe resolution of dot-notation paths in nested data structures. It provides caching, security features, and protection against common vulnerabilities.
The PathResolver is automatically used by the Rule Engine for all data access. You rarely need to
interact with it directly.
Features
Dot Notation Access nested data with simple path strings like user.profile.email
Security First Built-in protection against prototype pollution and malicious access
Performance Caching LRU cache for frequently accessed paths
Array Access Support for array index notation like users[0].name
Path Syntax
Basic Paths
const data = {
user: {
name: 'John Doe' ,
profile: {
email: 'john@example.com' ,
settings: {
theme: 'dark' ,
},
},
},
};
// Access nested properties
engine . resolvePath ( data , 'user.name' ); // 'John Doe'
engine . resolvePath ( data , 'user.profile.email' ); // 'john@example.com'
engine . resolvePath ( data , 'user.profile.settings.theme' ); // 'dark'
Array Paths
const data = {
users: [
{ name: 'Alice' , age: 30 },
{ name: 'Bob' , age: 25 },
],
tags: [ 'admin' , 'verified' ],
};
// Array index access
engine . resolvePath ( data , 'users[0].name' ); // 'Alice'
engine . resolvePath ( data , 'users[1].age' ); // 25
engine . resolvePath ( data , 'tags[0]' ); // 'admin'
Undefined Paths
const data = { user: { name: 'John' } };
// Non-existent paths return undefined
engine . resolvePath ( data , 'user.email' ); // undefined
engine . resolvePath ( data , 'user.profile.theme' ); // undefined
engine . resolvePath ( data , 'missing.path' ); // undefined
Security Features
Prototype Pollution Protection
The PathResolver automatically blocks access to dangerous prototype properties.
const maliciousData = {
__proto__: { isAdmin: true },
constructor: { prototype: { role: 'admin' } },
};
// These paths are blocked
engine . resolvePath ( maliciousData , '__proto__.isAdmin' ); // undefined
engine . resolvePath ( maliciousData , 'constructor.prototype.role' ); // undefined
Blocked Properties:
__proto__
constructor
prototype
Function Access Prevention
const data = {
user: { name: 'John' },
dangerousFunc : () => {
/* malicious code */
},
utils: {
helper : () => {
/* code */
},
},
};
// Functions are blocked by default
engine . resolvePath ( data , 'dangerousFunc' ); // undefined
engine . resolvePath ( data , 'utils.helper' ); // undefined
Caching
The PathResolver uses an LRU cache to optimize performance:
const config = {
enableCache: true , // Enable path caching
maxCacheSize: 500 , // Maximum cached paths
};
const engine = createRuleEngine ( config );
// First access - cache miss
engine . resolvePath ( data , 'user.profile.email' ); // Cached
// Second access - cache hit (faster)
engine . resolvePath ( data , 'user.profile.email' ); // From cache
Cache hit rates typically exceed 95% in production workloads, significantly improving performance.
Configuration
Enable LRU caching for path resolution
Maximum number of paths to cache
Allow access to prototype properties (dangerous - keep false in production)
Allow resolution of function properties
Direct Usage
While the PathResolver is used automatically by the engine, you can access it directly:
import { PathResolver } from 'rule-engine-js' ;
const resolver = new PathResolver ({
enableCache: true ,
maxCacheSize: 1000 ,
});
const data = {
user: {
profile: {
name: 'Jane Doe' ,
email: 'jane@example.com' ,
},
},
};
const name = resolver . resolvePath ( data , 'user.profile.name' );
console . log ( name ); // 'Jane Doe'
// Get cache stats
const stats = resolver . getCacheStats ();
console . log ( stats ); // { size: 1, maxSize: 1000 }
// Clear cache
resolver . clearCache ();
Consistent Paths Use consistent path strings to maximize cache hits
Shallow Access Prefer shallower paths when possible for faster resolution
Avoid Deep Nesting Excessive nesting (>5 levels) impacts performance
Monitor Cache Check cache stats to optimize cache size
Common Patterns
Safe Property Access
// Instead of this (can throw errors)
const email = data . user . profile . email ;
// Use PathResolver (safe)
const email = engine . resolvePath ( data , 'user.profile.email' , 'default@example.com' );
Dynamic Path Building
function getUserField ( userId , field ) {
const path = `users[ ${ userId } ]. ${ field } ` ;
return engine . resolvePath ( data , path );
}
const name = getUserField ( 0 , 'name' );
const email = getUserField ( 0 , 'email' );
Validation
function validatePaths ( data , requiredPaths ) {
return requiredPaths . every (( path ) => engine . resolvePath ( data , path ) !== undefined );
}
const isValid = validatePaths ( userData , [ 'user.email' , 'user.profile.name' , 'user.settings.theme' ]);
Next Steps