From 36882efaedeb966a653eb8ce25ddfe4202b227e7 Mon Sep 17 00:00:00 2001 From: Kaushal Sharma Date: Thu, 31 Jul 2025 19:02:18 +0530 Subject: [PATCH 1/7] jq validator --- .../jq-validator/introduction.mdx | 27 +++++ .../jq-validator/jq-validator.yml | 45 ++++++++ content/validator.js | 102 ++++++++++++++++++ docs.json | 7 ++ 4 files changed, 181 insertions(+) create mode 100644 api-reference/general-tools/jq-validator/introduction.mdx create mode 100644 api-reference/general-tools/jq-validator/jq-validator.yml create mode 100644 content/validator.js diff --git a/api-reference/general-tools/jq-validator/introduction.mdx b/api-reference/general-tools/jq-validator/introduction.mdx new file mode 100644 index 0000000..856d3a4 --- /dev/null +++ b/api-reference/general-tools/jq-validator/introduction.mdx @@ -0,0 +1,27 @@ +# JQ Validator + +This tool helps you validate JQ expressions against JSON payloads, determining if the expressions are syntactically correct and evaluating their results. + +## Try it Live + +
+
+
+ +
+
+ + +
+ +
+ + diff --git a/api-reference/general-tools/jq-validator/jq-validator.yml b/api-reference/general-tools/jq-validator/jq-validator.yml new file mode 100644 index 0000000..b274d0f --- /dev/null +++ b/api-reference/general-tools/jq-validator/jq-validator.yml @@ -0,0 +1,45 @@ +openapi: 3.0.0 +info: + title: JQ Validator API + description: API for validating and evaluating JQ expressions against JSON payloads + version: 1.0.0 +paths: + /validate: + post: + summary: Validate and evaluate a JQ expression + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - payload + - expression + properties: + payload: + type: object + description: The JSON payload to evaluate against + expression: + type: string + description: The JQ expression to validate and execute + responses: + '200': + description: Successful validation result + content: + application/json: + schema: + type: object + properties: + valid: + type: boolean + description: Whether the JQ expression is syntactically valid + result: + type: object + description: The result of evaluating the expression + success: + type: boolean + description: Whether the evaluation was successful + error: + type: string + description: Error message if validation or evaluation failed diff --git a/content/validator.js b/content/validator.js new file mode 100644 index 0000000..2c6964a --- /dev/null +++ b/content/validator.js @@ -0,0 +1,102 @@ +console.log("validator.js loaded"); + +// validator.js +document.addEventListener('DOMContentLoaded', function () { + function showValidationResult(valid, result, error) { + const out = document.getElementById('jq-validation-output'); + out.innerHTML = ''; + + // Create card container + const card = document.createElement('div'); + card.style.cssText = ` + border: 1px solid #ddd; + border-radius: 8px; + padding: 20px; + margin-top: 20px; + background-color: #f9f9f9; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + `; + + // Add validation status + if (typeof valid !== 'undefined') { + const status = document.createElement('div'); + status.innerHTML = valid ? '✓ Valid JQ expression' : '✗ Invalid JQ expression'; + status.style.marginBottom = '15px'; + card.appendChild(status); + } + + // Add result + if (typeof result !== 'undefined') { + const resultTitle = document.createElement('h4'); + resultTitle.textContent = 'Result:'; + resultTitle.style.marginBottom = '10px'; + card.appendChild(resultTitle); + + const resultPre = document.createElement('pre'); + resultPre.textContent = JSON.stringify(result, null, 2); + resultPre.style.cssText = ` + background-color: #fff; + border: 1px solid #ccc; + border-radius: 4px; + padding: 15px; + overflow-x: auto; + font-family: 'Courier New', monospace; + `; + card.appendChild(resultPre); + } + + // Add error + if (error) { + const errorDiv = document.createElement('div'); + errorDiv.innerHTML = `Error: ${error}`; + errorDiv.style.marginTop = '10px'; + card.appendChild(errorDiv); + } + + out.appendChild(card); + } + + function validateJQ() { + const payload = document.getElementById('payload').value; + const expression = document.getElementById('jq-expression-input').value; + + try { + fetch('/validate', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + payload: JSON.parse(payload), + expression: expression + }) + }) + .then(res => res.json()) + .then(data => { + showValidationResult(data.valid, data.result, data.error); + }) + .catch(err => showValidationResult(false, undefined, err && err.message)); + } catch (parseError) { + showValidationResult(false, undefined, 'Invalid JSON format'); + } + } + + // Expose validateJQ function globally + window.validateJQ = validateJQ; + + // Wait for form to be available + function attachFormHandler() { + const form = document.getElementById('submit'); + if (form) { + alert("Form found, attaching handler!"); + form.addEventListener('click', function (e) { + alert("Form found and handler attached!"); + validateJQ(); + }); + } else { + // Retry after 100ms + setTimeout(attachFormHandler, 100); + } + } + + // Start checking for form + attachFormHandler(); +}); \ No newline at end of file diff --git a/docs.json b/docs.json index d4eb18a..c412a1c 100644 --- a/docs.json +++ b/docs.json @@ -168,6 +168,13 @@ "api-reference/general-tools/medical/lab-report/delete-document", "api-reference/general-tools/medical/lab-report/register-webhook" ] + }, + { + "group": "JQ Validator", + "icon": "check", + "pages": [ + "api-reference/general-tools/jq-validator/introduction" + ] } ] }, From 922ab75ef3324848a3c40a8be64436d2344b8f6e Mon Sep 17 00:00:00 2001 From: Durgesh Mehar Date: Thu, 31 Jul 2025 15:56:56 +0530 Subject: [PATCH 2/7] Docs for medicationrequest in prescription (#345) * Docs for medicationrequest in prescription * Docs for medicationrequest in which added the dispense_quantitu * Docs for medicationrequest in which added the dispense_quantity --- api-reference/doc-tool/doc-tool.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/api-reference/doc-tool/doc-tool.yaml b/api-reference/doc-tool/doc-tool.yaml index 18c407e..9c82d71 100644 --- a/api-reference/doc-tool/doc-tool.yaml +++ b/api-reference/doc-tool/doc-tool.yaml @@ -5534,9 +5534,10 @@ paths: display: "Social History" note: [] - resource_type: "medicationrequest" - drug_id: "medanta3806727491" + partner_drug_id: "medanta3806727491" drug_status: "active" med_name: "Olmezest 40 Tablet" + snomed_id: "1234567" dose: id: "du-5550260779" value: 1.0 @@ -5549,6 +5550,9 @@ paths: unit: null value: null custom: null + period: null + period_unit: null + frequency: null dosage_instruction: custom: "1-0-0" when: null @@ -5556,6 +5560,9 @@ paths: period_unit: null frequency: null note: null + dispense_quantity: + value: 28.0 + unit: "tablet" '403': description: Forbidden From d94783b01ae0ee7cff2b4e20dff05ace6302fabe Mon Sep 17 00:00:00 2001 From: Durgesh Mehar Date: Thu, 31 Jul 2025 16:53:55 +0530 Subject: [PATCH 3/7] Durgesh/docs partner drug (#346) * Docs for medicationrequest in prescription * Docs for medicationrequest in which added the dispense_quantitu * Docs for medicationrequest in which added the dispense_quantity * Docs changes in Medicationrequest * dosage fix --------- Co-authored-by: Niharika Chaturvedi <43184138+niha9@users.noreply.github.com> --- api-reference/doc-tool/doc-tool.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/api-reference/doc-tool/doc-tool.yaml b/api-reference/doc-tool/doc-tool.yaml index 9c82d71..ff3065d 100644 --- a/api-reference/doc-tool/doc-tool.yaml +++ b/api-reference/doc-tool/doc-tool.yaml @@ -5544,22 +5544,22 @@ paths: unit: "tablet" custom: "1.0 tablet" additional_instructions: - - custom: null + - custom: "After Meal" type: "timing" duration: - unit: null - value: null - custom: null - period: null - period_unit: null - frequency: null + unit: "wk" + value: 2 + custom: "2 wk" + period: "1" + period_unit: "d" + frequency: 2 dosage_instruction: - custom: "1-0-0" - when: null - period: null - period_unit: null - frequency: null - note: null + custom: "1-0-1" + when: ["MORN","NIGHT"] + period: "1" + period_unit: "d" + frequency: 2 + note: "Take with water" dispense_quantity: value: 28.0 unit: "tablet" From 41570fc20aa377a71ad745672158befe1e753023 Mon Sep 17 00:00:00 2001 From: brundab Date: Thu, 31 Jul 2025 20:14:36 +0530 Subject: [PATCH 4/7] fixed jq button , and added separate css style script to hande results responces --- .../jq-validator/introduction.mdx | 81 +++- content/validator.js | 425 ++++++++++++++---- 2 files changed, 404 insertions(+), 102 deletions(-) diff --git a/api-reference/general-tools/jq-validator/introduction.mdx b/api-reference/general-tools/jq-validator/introduction.mdx index 856d3a4..e17e272 100644 --- a/api-reference/general-tools/jq-validator/introduction.mdx +++ b/api-reference/general-tools/jq-validator/introduction.mdx @@ -4,24 +4,67 @@ This tool helps you validate JQ expressions against JSON payloads, determining i ## Try it Live -
-
-
+
+ +
+ + +
+
+ + +
-
-
+ + +
+
- - - -
- - + \ No newline at end of file diff --git a/content/validator.js b/content/validator.js index 2c6964a..cd1ecf8 100644 --- a/content/validator.js +++ b/content/validator.js @@ -1,102 +1,361 @@ -console.log("validator.js loaded"); +// Mock JQ validation function (replaces server call) +function mockJQValidation(payload, expression) { + try { + // Handle root object access + if (expression === '.') { + return { + valid: true, + result: payload, + error: null + }; + } + + // Handle simple property access (.property) + if (expression.startsWith('.') && !expression.includes('[') && !expression.includes('|')) { + const key = expression.substring(1); + + if (key === '') { + return { + valid: true, + result: payload, + error: null + }; + } + + if (key.includes('.')) { + const keys = key.split('.'); + let current = payload; + + for (const k of keys) { + if (current && typeof current === 'object' && current.hasOwnProperty(k)) { + current = current[k]; + } else { + return { + valid: false, + result: null, + error: `Property path '${key}' not found in JSON object` + }; + } + } + return { + valid: true, + result: current, + error: null + }; + } + + if (payload && typeof payload === 'object' && payload.hasOwnProperty(key)) { + return { + valid: true, + result: payload[key], + error: null + }; + } else { + return { + valid: false, + result: null, + error: `Property '${key}' not found in JSON object` + }; + } + } + + // Handle array indexing + if (expression.match(/^\.\[\d+]$/)) { + const indexMatch = expression.match(/^\.\[(\d+)]$/); + if (indexMatch) { + const index = parseInt(indexMatch[1]); + + if (Array.isArray(payload)) { + if (index >= 0 && index < payload.length) { + return { + valid: true, + result: payload[index], + error: null + }; + } else { + return { + valid: false, + result: null, + error: `Array index ${index} is out of bounds (array length: ${payload.length})` + }; + } + } else { + return { + valid: false, + result: null, + error: `Cannot index non-array value with [${index}]` + }; + } + } + } + + // Handle length + if (expression === '.length' || expression === '. | length') { + if (Array.isArray(payload)) { + return { + valid: true, + result: payload.length, + error: null + }; + } else if (typeof payload === 'object' && payload !== null) { + return { + valid: true, + result: Object.keys(payload).length, + error: null + }; + } else { + return { + valid: false, + result: null, + error: "Cannot get length of non-array/non-object value" + }; + } + } + + // Handle keys + if (expression === '. | keys' || expression === '.keys') { + if (typeof payload === 'object' && payload !== null) { + return { + valid: true, + result: Array.isArray(payload) + ? Array.from({ length: payload.length }, (_, i) => i) + : Object.keys(payload), + error: null + }; + } else { + return { + valid: false, + result: null, + error: "Cannot get keys of non-object value" + }; + } + } + + // Handle type checking + if (expression === '. | type' || expression === '.type') { + let type; + if (payload === null) type = 'null'; + else if (Array.isArray(payload)) type = 'array'; + else if (typeof payload === 'object') type = 'object'; + else type = typeof payload; -// validator.js -document.addEventListener('DOMContentLoaded', function () { - function showValidationResult(valid, result, error) { - const out = document.getElementById('jq-validation-output'); - out.innerHTML = ''; + return { + valid: true, + result: type, + error: null + }; + } + + return { + valid: false, + result: null, + error: `JQ expression '${expression}' is not supported in demo mode. Supported: ., .property, .[index], .length, . | keys, . | type` + }; + + } catch (error) { + return { + valid: false, + result: null, + error: `Error processing expression: ${error.message}` + }; + } +} + +function showValidationResult(valid, result, error) { + const out = document.getElementById('jq-validation-output'); + if (!out) { + alert("Error: Output element not found!"); + return; + } + + out.innerHTML = ''; + + const resultsContainer = document.createElement('div'); + resultsContainer.style.cssText = ` + margin-top: 20px; + display: flex; + flex-direction: column; + gap: 15px; + `; - // Create card container - const card = document.createElement('div'); - card.style.cssText = ` + // Validation Status Card + const statusCard = document.createElement('div'); + statusCard.style.cssText = ` + border: 1px solid #ddd; + border-radius: 8px; + padding: 20px; + background-color: ${valid ? '#f0f9ff' : '#fef2f2'}; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + `; + + const statusTitle = document.createElement('h3'); + statusTitle.textContent = 'Validation Status'; + statusTitle.style.cssText = 'margin: 0 0 10px 0; color: #333;'; + statusCard.appendChild(statusTitle); + + const status = document.createElement('div'); + status.innerHTML = valid + ? '✓ Valid JQ Expression' + : '✗ Invalid JQ Expression'; + statusCard.appendChild(status); + + resultsContainer.appendChild(statusCard); + + // Result Card + if (typeof result !== 'undefined' && result !== null) { + const resultCard = document.createElement('div'); + resultCard.style.cssText = ` border: 1px solid #ddd; border-radius: 8px; padding: 20px; - margin-top: 20px; - background-color: #f9f9f9; + background-color: #f9fafb; box-shadow: 0 2px 4px rgba(0,0,0,0.1); `; - // Add validation status - if (typeof valid !== 'undefined') { - const status = document.createElement('div'); - status.innerHTML = valid ? '✓ Valid JQ expression' : '✗ Invalid JQ expression'; - status.style.marginBottom = '15px'; - card.appendChild(status); - } + const resultTitle = document.createElement('h3'); + resultTitle.textContent = 'JQ Expression Result'; + resultTitle.style.cssText = 'margin: 0 0 15px 0; color: #333;'; + resultCard.appendChild(resultTitle); - // Add result - if (typeof result !== 'undefined') { - const resultTitle = document.createElement('h4'); - resultTitle.textContent = 'Result:'; - resultTitle.style.marginBottom = '10px'; - card.appendChild(resultTitle); - - const resultPre = document.createElement('pre'); - resultPre.textContent = JSON.stringify(result, null, 2); - resultPre.style.cssText = ` - background-color: #fff; - border: 1px solid #ccc; - border-radius: 4px; - padding: 15px; - overflow-x: auto; - font-family: 'Courier New', monospace; - `; - card.appendChild(resultPre); - } + const resultPre = document.createElement('pre'); + resultPre.textContent = JSON.stringify(result, null, 2); + resultPre.style.cssText = ` + background-color: #fff; + border: 1px solid #d1d5db; + border-radius: 6px; + padding: 15px; + overflow-x: auto; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 14px; + line-height: 1.4; + margin: 0; + white-space: pre-wrap; + color: #dc2626; + `; + resultCard.appendChild(resultPre); - // Add error - if (error) { - const errorDiv = document.createElement('div'); - errorDiv.innerHTML = `Error: ${error}`; - errorDiv.style.marginTop = '10px'; - card.appendChild(errorDiv); - } + resultsContainer.appendChild(resultCard); + } + + // Error Card + if (error) { + const errorCard = document.createElement('div'); + errorCard.style.cssText = ` + border: 1px solid #fca5a5; + border-radius: 8px; + padding: 20px; + background-color: #fef2f2; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + `; + + const errorTitle = document.createElement('h3'); + errorTitle.textContent = 'Error Details'; + errorTitle.style.cssText = 'margin: 0 0 10px 0; color: #dc2626;'; + errorCard.appendChild(errorTitle); - out.appendChild(card); + const errorDiv = document.createElement('div'); + errorDiv.innerHTML = `${error}`; + errorCard.appendChild(errorDiv); + + resultsContainer.appendChild(errorCard); } - function validateJQ() { - const payload = document.getElementById('payload').value; - const expression = document.getElementById('jq-expression-input').value; - - try { - fetch('/validate', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - payload: JSON.parse(payload), - expression: expression - }) - }) - .then(res => res.json()) - .then(data => { - showValidationResult(data.valid, data.result, data.error); - }) - .catch(err => showValidationResult(false, undefined, err && err.message)); - } catch (parseError) { - showValidationResult(false, undefined, 'Invalid JSON format'); + out.appendChild(resultsContainer); +} + +function validateJQ() { + const payloadInput = document.getElementById('payload'); + const expressionInput = document.getElementById('jq-expression-input'); + + if (!payloadInput || !expressionInput) { + showValidationResult(false, undefined, 'Form elements not found'); + return; + } + + const payload = payloadInput.value.trim(); + const expression = expressionInput.value.trim(); + + if (!payload) { + showValidationResult(false, undefined, 'Please enter a JSON payload'); + return; + } + + if (!expression) { + showValidationResult(false, undefined, 'Please enter a JQ expression'); + return; + } + + try { + const parsedPayload = JSON.parse(payload); + const result = mockJQValidation(parsedPayload, expression); + showValidationResult(result.valid, result.result, result.error); + } catch (parseError) { + showValidationResult(false, undefined, 'Invalid JSON format in payload'); + } +} + +// Make validateJQ available globally +window.validateJQ = validateJQ; + +function handleSubmitClick(e) { + e.preventDefault(); + validateJQ(); +} + +// Helper function to find the submit button in the event path +function findSubmitButton(element) { + let current = element; + while (current && current !== document) { + if (current.id === 'submit') { + return current; } + current = current.parentElement; } + return null; +} - // Expose validateJQ function globally - window.validateJQ = validateJQ; - - // Wait for form to be available - function attachFormHandler() { - const form = document.getElementById('submit'); - if (form) { - alert("Form found, attaching handler!"); - form.addEventListener('click', function (e) { - alert("Form found and handler attached!"); - validateJQ(); - }); - } else { - // Retry after 100ms - setTimeout(attachFormHandler, 100); +// Initialize validator button +function initializeValidatorButton() { + const submitButton = document.getElementById('submit'); + + if (submitButton) { + submitButton.removeEventListener('click', handleSubmitClick); + submitButton.addEventListener('click', handleSubmitClick); + submitButton.style.border = "2px solid green"; + return true; + } + return false; +} + +// Try initialization with retries +function tryInitialization() { + let attempts = 0; + const maxAttempts = 50; + + const intervalId = setInterval(() => { + attempts++; + + if (initializeValidatorButton() || attempts >= maxAttempts) { + clearInterval(intervalId); } + }, 100); +} + +// Enhanced event delegation +document.addEventListener('click', function(e) { + const submitButton = findSubmitButton(e.target); + + if (submitButton) { + e.preventDefault(); + validateJQ(); } +}); - // Start checking for form - attachFormHandler(); -}); \ No newline at end of file +// Initialize when DOM is ready +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { + tryInitialization(); + }); +} else { + tryInitialization(); +} \ No newline at end of file From 56acadc4427cc49f99a9c9aa4a355bbe32357526 Mon Sep 17 00:00:00 2001 From: brundab Date: Fri, 1 Aug 2025 14:50:23 +0530 Subject: [PATCH 5/7] changes --- .../jq-validator/introduction.mdx | 18 +- content/validator.js | 716 +++++++++++------- 2 files changed, 443 insertions(+), 291 deletions(-) diff --git a/api-reference/general-tools/jq-validator/introduction.mdx b/api-reference/general-tools/jq-validator/introduction.mdx index e17e272..1bb0ae5 100644 --- a/api-reference/general-tools/jq-validator/introduction.mdx +++ b/api-reference/general-tools/jq-validator/introduction.mdx @@ -10,10 +10,10 @@ This tool helps you validate JQ expressions against JSON payloads, determining i - + >
- \ No newline at end of file + \ No newline at end of file diff --git a/content/validator.js b/content/validator.js index cd1ecf8..3f1ad53 100644 --- a/content/validator.js +++ b/content/validator.js @@ -1,20 +1,17 @@ -// Mock JQ validation function (replaces server call) -function mockJQValidation(payload, expression) { - try { - // Handle root object access - if (expression === '.') { - return { - valid: true, - result: payload, - error: null - }; - } - - // Handle simple property access (.property) - if (expression.startsWith('.') && !expression.includes('[') && !expression.includes('|')) { - const key = expression.substring(1); +// Wrap everything in an IIFE to avoid global namespace pollution +(function() { + // Prevent multiple script execution + if (window.validatorScriptLoaded) { + // Early exit if already loaded, but within a function context + return; + } + window.validatorScriptLoaded = true; - if (key === '') { + // Mock JQ validation function (replaces server call) + function mockJQValidation(payload, expression) { + try { + // Handle root object access + if (expression === '.') { return { valid: true, result: payload, @@ -22,340 +19,487 @@ function mockJQValidation(payload, expression) { }; } - if (key.includes('.')) { - const keys = key.split('.'); - let current = payload; + // Handle simple property access (.property) + if (expression.startsWith('.') && !expression.includes('[') && !expression.includes('|')) { + const key = expression.substring(1); - for (const k of keys) { - if (current && typeof current === 'object' && current.hasOwnProperty(k)) { - current = current[k]; - } else { - return { - valid: false, - result: null, - error: `Property path '${key}' not found in JSON object` - }; + if (key === '') { + return { + valid: true, + result: payload, + error: null + }; + } + + if (key.includes('.')) { + const keys = key.split('.'); + let current = payload; + + for (const k of keys) { + if (current && typeof current === 'object' && current.hasOwnProperty(k)) { + current = current[k]; + } else { + return { + valid: false, + result: null, + error: `Property path '${key}' not found in JSON object` + }; + } } + return { + valid: true, + result: current, + error: null + }; } - return { - valid: true, - result: current, - error: null - }; - } - if (payload && typeof payload === 'object' && payload.hasOwnProperty(key)) { - return { - valid: true, - result: payload[key], - error: null - }; - } else { - return { - valid: false, - result: null, - error: `Property '${key}' not found in JSON object` - }; + if (payload && typeof payload === 'object' && payload.hasOwnProperty(key)) { + return { + valid: true, + result: payload[key], + error: null + }; + } else { + return { + valid: false, + result: null, + error: `Property '${key}' not found in JSON object` + }; + } } - } - - // Handle array indexing - if (expression.match(/^\.\[\d+]$/)) { - const indexMatch = expression.match(/^\.\[(\d+)]$/); - if (indexMatch) { - const index = parseInt(indexMatch[1]); - if (Array.isArray(payload)) { - if (index >= 0 && index < payload.length) { - return { - valid: true, - result: payload[index], - error: null - }; + // Handle array indexing + if (expression.match(/^\.\[\d+]$/)) { + const indexMatch = expression.match(/^\.\[(\d+)]$/); + if (indexMatch) { + const index = parseInt(indexMatch[1]); + + if (Array.isArray(payload)) { + if (index >= 0 && index < payload.length) { + return { + valid: true, + result: payload[index], + error: null + }; + } else { + return { + valid: false, + result: null, + error: `Array index ${index} is out of bounds (array length: ${payload.length})` + }; + } } else { return { valid: false, result: null, - error: `Array index ${index} is out of bounds (array length: ${payload.length})` + error: `Cannot index non-array value with [${index}]` }; } + } + } + + // Handle length + if (expression === '.length' || expression === '. | length') { + if (Array.isArray(payload)) { + return { + valid: true, + result: payload.length, + error: null + }; + } else if (typeof payload === 'object' && payload !== null) { + return { + valid: true, + result: Object.keys(payload).length, + error: null + }; } else { return { valid: false, result: null, - error: `Cannot index non-array value with [${index}]` + error: "Cannot get length of non-array/non-object value" }; } } - } - // Handle length - if (expression === '.length' || expression === '. | length') { - if (Array.isArray(payload)) { - return { - valid: true, - result: payload.length, - error: null - }; - } else if (typeof payload === 'object' && payload !== null) { - return { - valid: true, - result: Object.keys(payload).length, - error: null - }; - } else { - return { - valid: false, - result: null, - error: "Cannot get length of non-array/non-object value" - }; + // Handle keys + if (expression === '. | keys' || expression === '.keys') { + if (typeof payload === 'object' && payload !== null) { + return { + valid: true, + result: Array.isArray(payload) + ? Array.from({ length: payload.length }, (_, i) => i) + : Object.keys(payload), + error: null + }; + } else { + return { + valid: false, + result: null, + error: "Cannot get keys of non-object value" + }; + } } - } - // Handle keys - if (expression === '. | keys' || expression === '.keys') { - if (typeof payload === 'object' && payload !== null) { + // Handle type checking + if (expression === '. | type' || expression === '.type') { + let type; + if (payload === null) type = 'null'; + else if (Array.isArray(payload)) type = 'array'; + else if (typeof payload === 'object') type = 'object'; + else type = typeof payload; + return { valid: true, - result: Array.isArray(payload) - ? Array.from({ length: payload.length }, (_, i) => i) - : Object.keys(payload), + result: type, error: null }; - } else { - return { - valid: false, - result: null, - error: "Cannot get keys of non-object value" - }; } - } - // Handle type checking - if (expression === '. | type' || expression === '.type') { - let type; - if (payload === null) type = 'null'; - else if (Array.isArray(payload)) type = 'array'; - else if (typeof payload === 'object') type = 'object'; - else type = typeof payload; + return { + valid: false, + result: null, + error: `JQ expression '${expression}' is not supported in demo mode. Supported: ., .property, .[index], .length, . | keys, . | type` + }; + } catch (error) { return { - valid: true, - result: type, - error: null + valid: false, + result: null, + error: `Error processing expression: ${error.message}` }; } - - return { - valid: false, - result: null, - error: `JQ expression '${expression}' is not supported in demo mode. Supported: ., .property, .[index], .length, . | keys, . | type` - }; - - } catch (error) { - return { - valid: false, - result: null, - error: `Error processing expression: ${error.message}` - }; } -} -function showValidationResult(valid, result, error) { - const out = document.getElementById('jq-validation-output'); - if (!out) { - alert("Error: Output element not found!"); - return; - } + function showValidationResult(valid, result, error) { + const out = document.getElementById('jq-validation-output'); + if (!out) { + return; + } + + out.innerHTML = ''; - out.innerHTML = ''; + const resultsContainer = document.createElement('div'); + resultsContainer.style.cssText = ` + margin-top: 20px; + display: flex; + flex-direction: column; + gap: 15px; + `; - const resultsContainer = document.createElement('div'); - resultsContainer.style.cssText = ` - margin-top: 20px; - display: flex; - flex-direction: column; - gap: 15px; + // Validation Status Card + const statusCard = document.createElement('div'); + statusCard.style.cssText = ` + border: 1px solid #ddd; + border-radius: 8px; + padding: 20px; + background-color: ${valid ? '#f0f9ff' : '#fef2f2'}; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); `; - // Validation Status Card - const statusCard = document.createElement('div'); - statusCard.style.cssText = ` + const statusTitle = document.createElement('h3'); + statusTitle.textContent = 'Validation Status'; + statusTitle.style.cssText = 'margin: 0 0 10px 0; color: #333;'; + statusCard.appendChild(statusTitle); + + const status = document.createElement('div'); + status.innerHTML = valid + ? '✓ Valid JQ Expression' + : '✗ Invalid JQ Expression'; + statusCard.appendChild(status); + + resultsContainer.appendChild(statusCard); + + // Result Card + if (typeof result !== 'undefined' && result !== null) { + const resultCard = document.createElement('div'); + resultCard.style.cssText = ` border: 1px solid #ddd; border-radius: 8px; padding: 20px; - background-color: ${valid ? '#f0f9ff' : '#fef2f2'}; + background-color: #f9fafb; box-shadow: 0 2px 4px rgba(0,0,0,0.1); - `; + `; + + const resultTitle = document.createElement('h3'); + resultTitle.textContent = 'JQ Expression Result'; + resultTitle.style.cssText = 'margin: 0 0 15px 0; color: #333;'; + resultCard.appendChild(resultTitle); + + const resultPre = document.createElement('pre'); + resultPre.textContent = JSON.stringify(result, null, 2); + resultPre.style.cssText = ` + background-color: #fff; + border: 1px solid #d1d5db; + border-radius: 6px; + padding: 15px; + overflow-x: auto; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 14px; + line-height: 1.4; + margin: 0; + white-space: pre-wrap; + color: #dc2626; + `; + resultCard.appendChild(resultPre); + + resultsContainer.appendChild(resultCard); + } + + // Error Card + if (error) { + const errorCard = document.createElement('div'); + errorCard.style.cssText = ` + border: 1px solid #fca5a5; + border-radius: 8px; + padding: 20px; + background-color: #fef2f2; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + `; + + const errorTitle = document.createElement('h3'); + errorTitle.textContent = 'Error Details'; + errorTitle.style.cssText = 'margin: 0 0 10px 0; color: #dc2626;'; + errorCard.appendChild(errorTitle); + + const errorDiv = document.createElement('div'); + errorDiv.innerHTML = `${error}`; + errorCard.appendChild(errorDiv); - const statusTitle = document.createElement('h3'); - statusTitle.textContent = 'Validation Status'; - statusTitle.style.cssText = 'margin: 0 0 10px 0; color: #333;'; - statusCard.appendChild(statusTitle); - - const status = document.createElement('div'); - status.innerHTML = valid - ? '✓ Valid JQ Expression' - : '✗ Invalid JQ Expression'; - statusCard.appendChild(status); - - resultsContainer.appendChild(statusCard); - - // Result Card - if (typeof result !== 'undefined' && result !== null) { - const resultCard = document.createElement('div'); - resultCard.style.cssText = ` - border: 1px solid #ddd; - border-radius: 8px; - padding: 20px; - background-color: #f9fafb; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); - `; - - const resultTitle = document.createElement('h3'); - resultTitle.textContent = 'JQ Expression Result'; - resultTitle.style.cssText = 'margin: 0 0 15px 0; color: #333;'; - resultCard.appendChild(resultTitle); - - const resultPre = document.createElement('pre'); - resultPre.textContent = JSON.stringify(result, null, 2); - resultPre.style.cssText = ` - background-color: #fff; - border: 1px solid #d1d5db; - border-radius: 6px; - padding: 15px; - overflow-x: auto; - font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; - font-size: 14px; - line-height: 1.4; - margin: 0; - white-space: pre-wrap; - color: #dc2626; - `; - resultCard.appendChild(resultPre); - - resultsContainer.appendChild(resultCard); + resultsContainer.appendChild(errorCard); + } + + out.appendChild(resultsContainer); } - // Error Card - if (error) { - const errorCard = document.createElement('div'); - errorCard.style.cssText = ` - border: 1px solid #fca5a5; - border-radius: 8px; - padding: 20px; - background-color: #fef2f2; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); - `; - - const errorTitle = document.createElement('h3'); - errorTitle.textContent = 'Error Details'; - errorTitle.style.cssText = 'margin: 0 0 10px 0; color: #dc2626;'; - errorCard.appendChild(errorTitle); - - const errorDiv = document.createElement('div'); - errorDiv.innerHTML = `${error}`; - errorCard.appendChild(errorDiv); - - resultsContainer.appendChild(errorCard); + // Store the original textarea value if available + let savedTextareaValue = ''; + + // Function to use the existing textarea or create a new one if needed + function useExistingOrCreateTextarea() { + // First, try to get the existing textarea that's in the MDX document + const existingTextarea = document.getElementById('payload'); + + // If there is an existing textarea, just ensure its visibility and return it + if (existingTextarea) { + // Save the value if it has content + if (existingTextarea.value && existingTextarea.value.trim() !== '') { + savedTextareaValue = existingTextarea.value; + } + + // Make sure it's visible and styled correctly + existingTextarea.style.display = 'block'; + existingTextarea.style.visibility = 'visible'; + existingTextarea.style.height = '200px'; + existingTextarea.style.width = '100%'; + + // If we have a saved value and the textarea is empty, restore it + if (savedTextareaValue && existingTextarea.value.trim() === '') { + existingTextarea.value = savedTextareaValue; + } else if (!savedTextareaValue && existingTextarea.value.trim() === '') { + // If no saved value and textarea is empty, add example JSON + } + + return existingTextarea; + } + + // If there's no textarea, we need to create one + + // First, find the right place to insert it + const form = document.getElementById('jq-validator-form'); + if (!form) { + return null; // Can't proceed without the form + } + + // Look for the container div for the JSON Payload + const jsonPayloadContainer = Array.from(form.querySelectorAll('div')).find(div => { + const label = div.querySelector('label'); + return label && label.textContent && label.textContent.trim().includes('JSON Payload'); + }); + + if (!jsonPayloadContainer) { + return null; // Can't find where to put the textarea + } + + // Create a new textarea + const newTextarea = document.createElement('textarea'); + newTextarea.id = 'payload'; + newTextarea.name = 'payload'; + newTextarea.placeholder = 'Enter JSON payload'; + + // Apply styles to make it visible + newTextarea.style.width = '100%'; + newTextarea.style.height = '200px'; + newTextarea.style.padding = '10px'; + newTextarea.style.border = '1px solid #ccc'; + newTextarea.style.borderRadius = '4px'; + newTextarea.style.fontFamily = 'monospace'; + newTextarea.style.fontSize = '14px'; + newTextarea.style.resize = 'vertical'; + newTextarea.style.display = 'block'; + newTextarea.style.visibility = 'visible'; + newTextarea.style.backgroundColor = '#454343'; + + // Insert after the label + const label = jsonPayloadContainer.querySelector('label'); + if (label) { + label.parentNode.insertBefore(newTextarea, label.nextSibling); + } else { + jsonPayloadContainer.appendChild(newTextarea); + } + + return newTextarea; } - out.appendChild(resultsContainer); -} + function validateJQ() { + const payloadInput = useExistingOrCreateTextarea(); + const expressionInput = document.getElementById('jq-expression-input'); -function validateJQ() { - const payloadInput = document.getElementById('payload'); - const expressionInput = document.getElementById('jq-expression-input'); + if (!payloadInput || !expressionInput) { + showValidationResult(false, undefined, 'Form elements not found'); + return; + } - if (!payloadInput || !expressionInput) { - showValidationResult(false, undefined, 'Form elements not found'); - return; + const payload = payloadInput.value.trim(); + const expression = expressionInput.value.trim(); + + if (!payload) { + showValidationResult(false, undefined, 'Please enter a JSON payload'); + return; + } + + if (!expression) { + showValidationResult(false, undefined, 'Please enter a JQ expression'); + return; + } + + try { + const parsedPayload = JSON.parse(payload); + const result = mockJQValidation(parsedPayload, expression); + showValidationResult(result.valid, result.result, result.error); + } catch (parseError) { + showValidationResult(false, undefined, 'Invalid JSON format in payload'); + } } - const payload = payloadInput.value.trim(); - const expression = expressionInput.value.trim(); + // Make validateJQ available globally + window.validateJQ = validateJQ; - if (!payload) { - showValidationResult(false, undefined, 'Please enter a JSON payload'); - return; + function handleSubmitClick(e) { + if (e) e.preventDefault(); + validateJQ(); } - if (!expression) { - showValidationResult(false, undefined, 'Please enter a JQ expression'); - return; + // Helper function to find the submit button in the event path + function findSubmitButton(element) { + let current = element; + while (current && current !== document) { + if (current.id === 'submit') { + return current; + } + current = current.parentElement; + } + return null; } - try { - const parsedPayload = JSON.parse(payload); - const result = mockJQValidation(parsedPayload, expression); - showValidationResult(result.valid, result.result, result.error); - } catch (parseError) { - showValidationResult(false, undefined, 'Invalid JSON format in payload'); + // Initialize validator button with safer approach + function initializeValidatorButton() { + const submitButton = document.getElementById('submit'); + if (submitButton) { + // Remove any existing listeners to avoid duplicates + submitButton.removeEventListener('click', handleSubmitClick); + submitButton.addEventListener('click', handleSubmitClick); + return true; + } + return false; } -} - -// Make validateJQ available globally -window.validateJQ = validateJQ; - -function handleSubmitClick(e) { - e.preventDefault(); - validateJQ(); -} - -// Helper function to find the submit button in the event path -function findSubmitButton(element) { - let current = element; - while (current && current !== document) { - if (current.id === 'submit') { - return current; + + // Use event delegation for click events + document.addEventListener('click', function(e) { + const submitButton = findSubmitButton(e.target); + if (submitButton) { + e.preventDefault(); + validateJQ(); } - current = current.parentElement; + }); + + // Use MutationObserver to detect when React removes or changes our textarea + function setupMutationObserver() { + // First ensure we have a reference point - the form + const form = document.getElementById('jq-validator-form'); + if (!form) return; + + const observer = new MutationObserver(function(mutations) { + // Check if our textarea was removed + const textareaExists = !!document.getElementById('payload'); + if (!textareaExists) { + // If textarea is gone, recreate it + useExistingOrCreateTextarea(); + } + + // Also check if the submit button needs reinitialization + initializeValidatorButton(); + }); + + // Observe the form and its descendants for changes + observer.observe(form, { + childList: true, + subtree: true, + attributes: true + }); + + // Also observe the body in case the form itself gets replaced + observer.observe(document.body, { + childList: true, + subtree: false + }); + + return observer; } - return null; -} - -// Initialize validator button -function initializeValidatorButton() { - const submitButton = document.getElementById('submit'); - - if (submitButton) { - submitButton.removeEventListener('click', handleSubmitClick); - submitButton.addEventListener('click', handleSubmitClick); - submitButton.style.border = "2px solid green"; - return true; + + // Function to periodically check and ensure textarea exists + function startPeriodicCheck() { + // Initially ensure the textarea exists + useExistingOrCreateTextarea(); + + // Then set up a periodic check + // Check every second + return setInterval(() => { + const textarea = document.getElementById('payload'); + if (!textarea || textarea.style.display === 'none' || textarea.style.visibility === 'hidden') { + useExistingOrCreateTextarea(); + } + }, 1000); } - return false; -} -// Try initialization with retries -function tryInitialization() { - let attempts = 0; - const maxAttempts = 50; + // Initialize everything needed for the validator to work + function init() { + // Immediately try to use or create the textarea + useExistingOrCreateTextarea(); - const intervalId = setInterval(() => { - attempts++; + // Set up the validation button + initializeValidatorButton(); - if (initializeValidatorButton() || attempts >= maxAttempts) { - clearInterval(intervalId); - } - }, 100); -} + // Set up mutation observer to detect DOM changes + const observer = setupMutationObserver(); -// Enhanced event delegation -document.addEventListener('click', function(e) { - const submitButton = findSubmitButton(e.target); + // Start periodic checks for the textarea + const intervalId = startPeriodicCheck(); - if (submitButton) { - e.preventDefault(); - validateJQ(); + // Store references to cleanup if needed + window.validatorCleanup = function() { + if (observer) observer.disconnect(); + if (intervalId) clearInterval(intervalId); + }; } -}); -// Initialize when DOM is ready -if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', function() { - tryInitialization(); - }); -} else { - tryInitialization(); -} \ No newline at end of file + // Start initialization when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + // DOM already loaded, initialize now + init(); + } + + // Also initialize on window load as a fallback + window.addEventListener('load', init); +})(); \ No newline at end of file From bd5acf60a228906c5f6f1f9ac4bd9e908b6da52f Mon Sep 17 00:00:00 2001 From: brundab Date: Fri, 1 Aug 2025 15:05:22 +0530 Subject: [PATCH 6/7] changes fixed --- .../jq-validator/introduction.mdx | 2 - content/validator.js | 104 +++++++----------- 2 files changed, 38 insertions(+), 68 deletions(-) diff --git a/api-reference/general-tools/jq-validator/introduction.mdx b/api-reference/general-tools/jq-validator/introduction.mdx index 1bb0ae5..a758626 100644 --- a/api-reference/general-tools/jq-validator/introduction.mdx +++ b/api-reference/general-tools/jq-validator/introduction.mdx @@ -62,8 +62,6 @@ This tool helps you validate JQ expressions against JSON payloads, determining i cursor: 'pointer', transition: 'background-color 0.2s' }} - onMouseOver={(e) => e.target.style.backgroundColor = '#2563eb'} - onMouseOut={(e) => e.target.style.backgroundColor = '#3b82f6'} > Validate JQ Expression diff --git a/content/validator.js b/content/validator.js index 3f1ad53..49c9fce 100644 --- a/content/validator.js +++ b/content/validator.js @@ -1,16 +1,45 @@ + // Wrap everything in an IIFE to avoid global namespace pollution (function() { - // Prevent multiple script execution if (window.validatorScriptLoaded) { - // Early exit if already loaded, but within a function context return; } window.validatorScriptLoaded = true; - // Mock JQ validation function (replaces server call) function mockJQValidation(payload, expression) { try { - // Handle root object access + // Handle jq command style expressions (e.g., jq '.user.name') + if (expression.startsWith('jq ')) { + const jqExpression = expression.substring(3).trim(); + + // Extract the actual expression without quotes + let actualExpression; + if ((jqExpression.startsWith("'") && jqExpression.endsWith("'")) || + (jqExpression.startsWith('"') && jqExpression.endsWith('"'))) { + actualExpression = jqExpression.substring(1, jqExpression.length - 1); + } else { + actualExpression = jqExpression; + } + + // Call the validation function with the extracted expression + const result = mockJQValidation(payload, actualExpression); + + // Return true/false instead of the actual value + if (result.valid) { + return { + valid: true, + result: true, + error: null + }; + } else { + return { + valid: true, + result: false, + error: null + }; + } + } + if (expression === '.') { return { valid: true, @@ -19,7 +48,6 @@ }; } - // Handle simple property access (.property) if (expression.startsWith('.') && !expression.includes('[') && !expression.includes('|')) { const key = expression.substring(1); @@ -169,7 +197,6 @@ }; } } - function showValidationResult(valid, result, error) { const out = document.getElementById('jq-validation-output'); if (!out) { @@ -271,62 +298,45 @@ out.appendChild(resultsContainer); } - // Store the original textarea value if available let savedTextareaValue = ''; - // Function to use the existing textarea or create a new one if needed + function useExistingOrCreateTextarea() { - // First, try to get the existing textarea that's in the MDX document const existingTextarea = document.getElementById('payload'); - - // If there is an existing textarea, just ensure its visibility and return it if (existingTextarea) { - // Save the value if it has content if (existingTextarea.value && existingTextarea.value.trim() !== '') { savedTextareaValue = existingTextarea.value; } - - // Make sure it's visible and styled correctly existingTextarea.style.display = 'block'; existingTextarea.style.visibility = 'visible'; existingTextarea.style.height = '200px'; existingTextarea.style.width = '100%'; - - // If we have a saved value and the textarea is empty, restore it if (savedTextareaValue && existingTextarea.value.trim() === '') { existingTextarea.value = savedTextareaValue; } else if (!savedTextareaValue && existingTextarea.value.trim() === '') { - // If no saved value and textarea is empty, add example JSON } return existingTextarea; } - - // If there's no textarea, we need to create one - - // First, find the right place to insert it const form = document.getElementById('jq-validator-form'); if (!form) { - return null; // Can't proceed without the form + return null; } - // Look for the container div for the JSON Payload const jsonPayloadContainer = Array.from(form.querySelectorAll('div')).find(div => { const label = div.querySelector('label'); return label && label.textContent && label.textContent.trim().includes('JSON Payload'); }); if (!jsonPayloadContainer) { - return null; // Can't find where to put the textarea + return null; } - // Create a new textarea const newTextarea = document.createElement('textarea'); newTextarea.id = 'payload'; newTextarea.name = 'payload'; newTextarea.placeholder = 'Enter JSON payload'; - // Apply styles to make it visible newTextarea.style.width = '100%'; newTextarea.style.height = '200px'; newTextarea.style.padding = '10px'; @@ -339,7 +349,6 @@ newTextarea.style.visibility = 'visible'; newTextarea.style.backgroundColor = '#454343'; - // Insert after the label const label = jsonPayloadContainer.querySelector('label'); if (label) { label.parentNode.insertBefore(newTextarea, label.nextSibling); @@ -381,15 +390,12 @@ } } - // Make validateJQ available globally window.validateJQ = validateJQ; function handleSubmitClick(e) { if (e) e.preventDefault(); validateJQ(); } - - // Helper function to find the submit button in the event path function findSubmitButton(element) { let current = element; while (current && current !== document) { @@ -401,11 +407,9 @@ return null; } - // Initialize validator button with safer approach function initializeValidatorButton() { const submitButton = document.getElementById('submit'); if (submitButton) { - // Remove any existing listeners to avoid duplicates submitButton.removeEventListener('click', handleSubmitClick); submitButton.addEventListener('click', handleSubmitClick); return true; @@ -413,7 +417,6 @@ return false; } - // Use event delegation for click events document.addEventListener('click', function(e) { const submitButton = findSubmitButton(e.target); if (submitButton) { @@ -421,33 +424,23 @@ validateJQ(); } }); - - // Use MutationObserver to detect when React removes or changes our textarea function setupMutationObserver() { - // First ensure we have a reference point - the form const form = document.getElementById('jq-validator-form'); if (!form) return; - const observer = new MutationObserver(function(mutations) { - // Check if our textarea was removed + const observer = new MutationObserver(function() { + // Removed 'mutations' parameter since it's not being used const textareaExists = !!document.getElementById('payload'); if (!textareaExists) { - // If textarea is gone, recreate it useExistingOrCreateTextarea(); } - - // Also check if the submit button needs reinitialization initializeValidatorButton(); }); - - // Observe the form and its descendants for changes observer.observe(form, { childList: true, subtree: true, attributes: true }); - - // Also observe the body in case the form itself gets replaced observer.observe(document.body, { childList: true, subtree: false @@ -456,13 +449,8 @@ return observer; } - // Function to periodically check and ensure textarea exists function startPeriodicCheck() { - // Initially ensure the textarea exists useExistingOrCreateTextarea(); - - // Then set up a periodic check - // Check every second return setInterval(() => { const textarea = document.getElementById('payload'); if (!textarea || textarea.style.display === 'none' || textarea.style.visibility === 'hidden') { @@ -470,36 +458,20 @@ } }, 1000); } - - // Initialize everything needed for the validator to work function init() { - // Immediately try to use or create the textarea useExistingOrCreateTextarea(); - - // Set up the validation button initializeValidatorButton(); - - // Set up mutation observer to detect DOM changes const observer = setupMutationObserver(); - - // Start periodic checks for the textarea const intervalId = startPeriodicCheck(); - - // Store references to cleanup if needed window.validatorCleanup = function() { if (observer) observer.disconnect(); if (intervalId) clearInterval(intervalId); }; } - - // Start initialization when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { - // DOM already loaded, initialize now init(); } - - // Also initialize on window load as a fallback window.addEventListener('load', init); })(); \ No newline at end of file From ced1b00d203ddadf8025920af806094c07ab325e Mon Sep 17 00:00:00 2001 From: brundab Date: Fri, 1 Aug 2025 16:19:32 +0530 Subject: [PATCH 7/7] fixed expression validator and button style --- .../jq-validator/introduction.mdx | 13 +- content/validator.js | 320 +++++++++++++++++- 2 files changed, 329 insertions(+), 4 deletions(-) diff --git a/api-reference/general-tools/jq-validator/introduction.mdx b/api-reference/general-tools/jq-validator/introduction.mdx index a758626..3e486fe 100644 --- a/api-reference/general-tools/jq-validator/introduction.mdx +++ b/api-reference/general-tools/jq-validator/introduction.mdx @@ -47,7 +47,6 @@ This tool helps you validate JQ expressions against JSON payloads, determining i }} /> -