I need to validate, update, escape every value string in object or array in the data object, the data is always changing this the base scheme. I have this code is working, can be done better or do less depth of recursion ?
let data = {
"data": "general",
"another" : ["fbdfdfdfdfdfdfdfdf", "somestring2"],
"MyStringArray" : ["valid_type.pathdir", "/pathdir/desdss"],
"html_data": [
{
"data": [
{
"item_title": "Server Version:",
},
["fbdfdfdfdfdfdfdfdf", "somestring2"],
{
"value_title": "2.0.1"
}
]
},
{
"head_title": "Info app",
"data": [
{
"value_title": "1.0.1"
},
{
"item_title": "javascript Version:",
}
]
}
]
};
let counter = 0
let limit_recursion = 150
function funct(object) {
if ( counter > limit_recursion ) {
throw new Error("limit exceeded, maximum recursion allowed is " + limit_recursion );
}
for ( let key in object ) {
if (typeof object[key] === "string") {
object[key] = validate_escape(object[key]);
}
else if ( _has_array_to_validate_get_string(object[key]) ) { // ["valid_type.pathdir", "/pathdir/desdss"],
object[key][1] = validate_escape(object[key][0], object[key][1]);
}
else if ( Array.isArray(object[key]) && object[key].every(item => typeof item === "string") ) {
object[key].forEach((value, index) => {
object[key][index] = validate_escape(value);
});
}
else if ( Array.isArray(object[key]) && object[key].every( item => typeof item === "object" && !Array.isArray(item) ) ) {
object[key].forEach((value) => {
funct(value);
});
}
else if (typeof object[key] === 'object' && !Array.isArray(object[key]) ) {
funct(object[key])
}
else if ( Array.isArray(object[key] ) ) {
funct(object[key])
}
counter++;
}
return object;
}
About the _has_array_to_validate_get_string in here I used a array to store key and value to detect type string validation.
About the validate_escape, is internal class to do validate, update, escape.
function _has_array_to_validate_get_string(array) {
return Array.isArray(array) && array.length === 2 && typeof array[0] === "string" && array[0].includes('valid_type');
}
function validate_escape(var1, var2) {
return var1 + var2;
}
Note: This answer gets the same result as the one in your question, but I think there's likely something wrong with both of them. It fills up your object with values like "somestring2undefined"
, tacking on "undefined"
onto nearly everything, because we call validate_escape
with only a single argument. I'm guessing this is a simple fix, but I don't really understand the requirements.
Speaking of requirements, your question could really use some attention. You post a code block and ask for better versions of it, but you never explain what it does, don't include a runnable snippet when you easily could, and have this odd "undefined"
problem in it.
With two small helper functions (transform
and mapObject
), we can rewrite your function as a simple collection of {test, handle}
pairs, that do a single transformation and recur as needed.
The replacement for funct
above would look like this:
const funct = transform ([
{test: (v) => typeof v == 'string', handle: (v) => validate_escape(v)},
{test: (v) => _has_array_to_validate_get_string(v), handle: ([x, y]) => [x, validate_escape(x, y)]},
{test: (v) => Array.isArray(v), handle: (v, recur) => v.map(recur)},
{test: (v) => typeof v == 'object', handle: (v, recur) => mapObject(recur)(v)},
])
mapObject
is a fairly trivial function, applying the notion of map
to a flat object, so that, for instance,
map(n => n * n)({a: 1, b: 2, c: 3, d: 4})
would yield
{a: 1, b : 4, c: 9, d: 16}
The important function is transform
, which accepts an array of objects with test
and handle
functions. It returns a function that accepts a single value, and runs through those objects to find the first one where its test
, called with that value, returns a truthy result. Then it returns the result of calling the handle
function with your value, and with a function you can use to recursively call this same configured-transform
function. If it doesn't find a matching handler, it just returns the input value.
const transform = (handlers) => (v) =>
(handlers.find(h => h.test(v)) || ({handle: (r, v) => v})).handle(v, transform(handlers))
const mapObject = (fn) => (o) =>
Object.fromEntries(Object.entries(o).map(([k, v]) => [k, fn(v)]))
function _has_array_to_validate_get_string(array) {
return Array.isArray(array) && array.length === 2 && typeof array[0] === "string" && array[0].includes('valid_type');
}
function validate_escape(var1, var2) {
return var1 + var2;
}
const funct = transform ([
{test: (v) => typeof v == 'string', handle: (v) => validate_escape(v)},
{test: (v) => _has_array_to_validate_get_string(v), handle: ([x, y]) => [x, validate_escape(x, y)]},
{test: (v) => Array.isArray(v), handle: (v, recur) => v.map(recur)},
{test: (v) => typeof v == 'object', handle: (v, recur) => mapObject(recur)(v)},
])
const data = {data: "general", another: ["fbdfdfdfdfdfdfdfdf", "somestring2"], MyStringArray: ["valid_type.pathdir", "/pathdir/desdss"], html_data: [{data: [{item_title: "Server Version:"}, ["fbdfdfdfdfdfdfdfdf", "somestring2"], {value_title: "2.0.1"}]}, {head_title: "Info app", data: [{value_title: "1.0.1"}, {item_title: "javascript Version:"}]}]}
console.log(funct(data))
.as-console-wrapper {max-height: 100% !important; top: 0}
The first two helpers we pass to transform
are your base cases, handling a single string, and handling your two-element string arrays with a proper substring on the first one. The other two simple recur properly on arrays and objects.
Do note that this version does not mutate your original object (we're not barbarians here, right?), but instead returns an altered clone of it.