Tengo un objeto JavaScript unknown (llamémoslo IncompleteObject solo por legibilidad) y una matriz de IVariables que pueden ser cualquier cosa, pero en el siguiente formato:
key: string value: unknownEjemplo:
IVariables:
[ { key: 'someObject', value: { some:'value' }, { key: 'name', value: 'another value' }, { key: 'lastName', value: 'this variable exists but wont be used' } ]Objeto incompleto:
{ ID: "SGML", SortAs: "{{someObject}}", GlossTerm: "Standard Generalized Markup Language", Acronym: "The acronym is {{name}}", GlossSee: "markup" }Resultado Esperado:
{ ID: "SGML", SortAs: { some:'value' }, GlossTerm: "Standard Generalized Markup Language", Acronym: "The acronym is another value", GlossSee: "markup" }La solución que pensé fue encadenar el objeto, reemplazar todo como cadenas y luego tratar de analizar como JSON nuevamente (si falla, falla), pero me pregunto si hay una solución mejor para esto... También sé cómo haz que SortAs, por ejemplo, se convierta en un objeto y no en una cadena
¡Gracias!
* Notas:
No podrá agregar objetos durante el reemplazo de una cadena, por lo que deberá verificar si la etiqueta es una cadena completa o no de antemano:
const IVariables = [ { key: 'someObject', value: { some:'value' }}, { key: 'name', value: 'another value' }, { key: 'lastName', value: 'this variable exists but wont be used' } ]; const incompleteObject = { ID: "SGML", SortAs: "{{someObject}}", GlossTerm: "Standard Generalized Markup Language", Acronym: "The acronym is {{name}}", GlossSee: "markup {{non-existing-tag}}", blah: "{{name}} and again {{name}}" } //convert array into object const dataVariables = IVariables.reduce((a, b) => (a[b.key] = b.value, a), {}); const reg = /({{([^}]+)}})/; for(let key in incompleteObject) { const data = incompleteObject[key], variable = data.match(reg); if (!variable) continue; if (variable[1] == data) //if entire string a tag, don't use string replace incompleteObject[key] = dataVariables[variable[2]] || variable[1]; else incompleteObject[key] = data.replace(new RegExp(reg, "g"), (a, b, c) => dataVariables[c] || b) } console.log(incompleteObject);Terminé haciendo con JSON.stringfy y algunas expresiones regulares.
Así es como lo hice:
const incompleteObject = { NoVariable: "Something", JustTheObject: "{{someObject}}", JustTheString: "{{name}}", IntegerValue: "{{integer}}", StringInsideOtherString: "Bla bla bla {{name}}", ObjectInsideString: "The acronym is {{name}}", VariableThatDoesntExist: "{{thisdoesntexist}}", ArrayToTestNestedStuff: [ { JustTheObject: "{{someObject}}", JustTheString: "{{name}}" }, { JustTheObject: "{{someObject}}", JustTheString: "{{name}}" } ] } const variablesToSubstitute: Record<string, unknown> = { someObject: { some:'value' }, name: 'another value', integer: 2, lastName: 'this variable exists but wont be used' } const result = replaceVariables(incompleteObject, variablesToSubstitute) console.log(JSON.stringify(result, null, 2)) const replaceVariables = (objectToReplace: unknown, variables: Record<string, unknown>) => { let stringfiedObject = JSON.stringify(objectToReplace) stringfiedObject = replaceEntireProperty(stringfiedObject, variables) stringfiedObject = replaceSubstring(stringfiedObject, variables) const result = JSON.parse(stringfiedObject) return result } const replaceEntireProperty = (stringfiedObject: string, variables: Record<string, unknown>) => { stringfiedObject = stringfiedObject.replace(/"{{[\w]+}}"/g, (substring: string, ...args: any[]) => { const substringWithoutBracesAndComma = substring.substring(3, substring.length-3) return JSON.stringify(variables[substringWithoutBracesAndComma] ?? removeAllUnescapedCommas(substring)) }) return stringfiedObject } const replaceSubstring = (stringfiedObject: string, variables: Record<string, unknown>) => { stringfiedObject = stringfiedObject.replace(/{{[\w]+}}/g, (substring: string, ...args: any[]) => { const substringWithoutBraces = substring.substring(2, substring.length-2) return removeAllUnescapedCommas(JSON.stringify(variables[substringWithoutBraces] ?? substring)) }) return stringfiedObject } const removeAllUnescapedCommas = (stringToUnescape: string) => { return stringToUnescape.replace(/(?<!\\)\"/g, "") }Aquí también hay un repositorio de GitHub con la solución funcionando (dado que está mecanografiado, no pude agregar el fragmento de código): https://github.com/vceolin/replace-variables-inside-object