Problem Description
Write a function that takes a valid JSON object or array and returns a new immutable version of that object. This new object should throw a string error when any mutation is attempted. The error messages must follow these rules:
- Setting or deleting a key on an object must throw "Error Modifying: {key}".
- Setting or deleting an index on an array must throw "Error Modifying Index: {index}".
- Calling a mutating array method (one of [pop, push, shift, unshift, splice, sort, reverse]) must throw "Error Calling Method: {methodName}".
Key Insights
- Use Proxies (in languages that support them, e.g. JavaScript) or wrapper classes to intercept modifications.
- Recursively wrap nested objects or arrays to ensure deep immutability.
- Distinguish between object keys and array indices during property modifications.
- Intercept calls to mutating array methods and return a wrapped function that always throws the appropriate error.
Space and Time Complexity
Time Complexity: O(n) where n is the total number of properties or elements in the object. Each element is processed once during the wrapping. Space Complexity: O(n) due to the recursive wrappers and the proxy objects for each nested element.
Solution
The solution involves recursively wrapping the target object or array with a Proxy (or with custom wrapper classes in languages that lack Proxy support). The Proxy traps the following operations:
- The get trap inspects if the accessed property is a function from a list of mutating methods (for arrays). If it is, a wrapped function that always throws the appropriate error is returned.
- The set and deleteProperty traps immediately throw an error if any attempt is made to modify a property. They differentiate between objects and arrays (checking if the property represents an array index). This approach guarantees that any attempt to modify the returned object, whether on the top level or nested, will produce the required error.