Skip to content

Commit

Permalink
implemented the jq modifications with a temporary keyWord
Browse files Browse the repository at this point in the history
  • Loading branch information
pazhersh committed May 20, 2024
1 parent 844daf1 commit 8de9fdf
Show file tree
Hide file tree
Showing 2 changed files with 352 additions and 182 deletions.
122 changes: 93 additions & 29 deletions lib/template.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const jq = require('./jq');
const jq = require("./jq");

const findInsideDoubleBracesIndices = (input) => {
let wrappingQuote = null;
Expand All @@ -8,7 +8,7 @@ const findInsideDoubleBracesIndices = (input) => {
for (let i = 0; i < input.length; i += 1) {
const char = input[i];

if (insideDoubleBracesStart && char === '\\') {
if (insideDoubleBracesStart && char === "\\") {
// If next character is escaped, skip it
i += 1;
}
Expand All @@ -19,40 +19,62 @@ const findInsideDoubleBracesIndices = (input) => {
} else if (wrappingQuote === char) {
wrappingQuote = null;
}
} else if (!wrappingQuote && char === '{' && i > 0 && input[i - 1] === '{') {
} else if (
!wrappingQuote &&
char === "{" &&
i > 0 &&
input[i - 1] === "{"
) {
// if opening double braces that not wrapped with quotes
if (insideDoubleBracesStart) {
throw new Error(`Found double braces in index ${i - 1} inside other one in index ${insideDoubleBracesStart - '{{'.length}`);
throw new Error(
`Found double braces in index ${i - 1} inside other one in index ${
insideDoubleBracesStart - "{{".length
}`
);
}
insideDoubleBracesStart = i + 1;
if (input[i + 1] === '{') {
if (input[i + 1] === "{") {
// To overcome three "{" in a row considered as two different opening double braces
i += 1;
}
} else if (!wrappingQuote && char === '}' && i > 0 && input[i - 1] === '}') {
} else if (
!wrappingQuote &&
char === "}" &&
i > 0 &&
input[i - 1] === "}"
) {
// if closing double braces that not wrapped with quotes
if (insideDoubleBracesStart) {
indices.push({start: insideDoubleBracesStart, end: i - 1});
indices.push({ start: insideDoubleBracesStart, end: i - 1 });
insideDoubleBracesStart = null;
if (input[i + 1] === '}') {
if (input[i + 1] === "}") {
// To overcome three "}" in a row considered as two different closing double braces
i += 1;
}
} else {
throw new Error(`Found closing double braces in index ${i - 1} without opening double braces`);
throw new Error(
`Found closing double braces in index ${
i - 1
} without opening double braces`
);
}
}
}

if (insideDoubleBracesStart) {
throw new Error(`Found opening double braces in index ${insideDoubleBracesStart - '{{'.length} without closing double braces`);
throw new Error(
`Found opening double braces in index ${
insideDoubleBracesStart - "{{".length
} without closing double braces`
);
}

return indices;
}
};

const render = (inputJson, template, execOptions = {}) => {
if (typeof template !== 'string') {
if (typeof template !== "string") {
return null;
}
const indices = findInsideDoubleBracesIndices(template);
Expand All @@ -62,51 +84,93 @@ const render = (inputJson, template, execOptions = {}) => {
}

const firstIndex = indices[0];
if (indices.length === 1 && template.trim().startsWith('{{') && template.trim().endsWith('}}')) {
if (
indices.length === 1 &&
template.trim().startsWith("{{") &&
template.trim().endsWith("}}")
) {
// If entire string is a template, evaluate and return the result with the original type
return jq.exec(inputJson, template.slice(firstIndex.start, firstIndex.end), execOptions);
return jq.exec(
inputJson,
template.slice(firstIndex.start, firstIndex.end),
execOptions
);
}

let result = template.slice(0, firstIndex.start - '{{'.length); // Initiate result with string until first template start index
let result = template.slice(0, firstIndex.start - "{{".length); // Initiate result with string until first template start index
indices.forEach((index, i) => {
const jqResult = jq.exec(inputJson, template.slice(index.start, index.end), execOptions);
const jqResult = jq.exec(
inputJson,
template.slice(index.start, index.end),
execOptions
);
result +=
// Add to the result the stringified evaluated jq of the current template
(typeof jqResult === 'string' ? jqResult : JSON.stringify(jqResult)) +
(typeof jqResult === "string" ? jqResult : JSON.stringify(jqResult)) +
// Add to the result from template end index. if last template index - until the end of string, else until next start index
template.slice(
index.end + '}}'.length,
i + 1 === indices.length ? template.length : indices[i + 1].start - '{{'.length,
index.end + "}}".length,
i + 1 === indices.length
? template.length
: indices[i + 1].start - "{{".length
);
});

return result;
}
};

const renderRecursively = (inputJson, template, execOptions = {}) => {
if (typeof template === 'string') {
if (typeof template === "string") {
return render(inputJson, template, execOptions);
}
if (Array.isArray(template)) {
return template.map((value) => renderRecursively(inputJson, value, execOptions));
return template.map((value) =>
renderRecursively(inputJson, value, execOptions)
);
}
if (typeof template === 'object' && template !== null) {
if (typeof template === "object" && template !== null) {
return Object.fromEntries(
Object.entries(template).flatMap(([key, value]) => {
const MY_KEYWORD_ESCAPED = "tempSpreadKeyword\\(\\)";
const keywordMatcher = `\\{\\{\\s*${MY_KEYWORD_ESCAPED}\\s*\\}\\}`;

if (key.match(keywordMatcher)) {
const evaluatedValue = renderRecursively(
inputJson,
value,
execOptions
);
if (typeof evaluatedValue !== "object") {
throw new Error(
`Evaluated value should be an object if the key is ${key}. Original value: ${value}, evaluated to: ${JSON.stringify(
evaluatedValue
)}`
);
}
return Object.entries(evaluatedValue);
}

const evaluatedKey = renderRecursively(inputJson, key, execOptions);
if (!['undefined', 'string'].includes(typeof evaluatedKey) && evaluatedKey !== null) {
if (
!["undefined", "string"].includes(typeof evaluatedKey) &&
evaluatedKey !== null
) {
throw new Error(
`Evaluated object key should be undefined, null or string. Original key: ${key}, evaluated to: ${JSON.stringify(evaluatedKey)}`,
`Evaluated object key should be undefined, null or string. Original key: ${key}, evaluated to: ${JSON.stringify(
evaluatedKey
)}`
);
}
return evaluatedKey ? [[evaluatedKey, renderRecursively(inputJson, value, execOptions)]] : [];
}),
return evaluatedKey
? [[evaluatedKey, renderRecursively(inputJson, value, execOptions)]]
: [];
})
);
}

return template;
}
};

module.exports = {
renderRecursively
renderRecursively,
};
Loading

0 comments on commit 8de9fdf

Please sign in to comment.