mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-02 17:08:32 +00:00
* feat: add response data type selector in response viewer * chore: fixed lint issue * test: add test for resonse format change and preview. * refactor: streamline response format tests with utility functions for navigation and format switching * refactor: simplify ButtonDropdown component and enhance QueryResultTypeSelector with header and toggle switch * feat: enhance ButtonDropdown with prefix and suffix props; implement content type detection and update QueryResult for improved format handling * fix: lint errors resolved * fix: remove unnecessary blank line to resolve lint issues * fix: update response format tests * refactor: remove preview tab locator from response format tests * fix: update dependency in useEffect to include previewFormatOptions for accurate format handling * refactor: reorganize imports and enhance QueryResult component for improved format handling and error display * fix: update error messages in response format preview tests and adjust version in JSON fixture * feat: add drag detection to HtmlPreview component and update structure for improved user interaction * refactor: update ResponsePane components for improved structure and functionality; replace QueryResult with QueryResponse, enhance layout handling, and streamline response actions * refactor: remove ButtonDropdown component and associated styles; * refactor: moved ErrorAlert to ui folder * fix: lint error * feat: add data-testid attributes to Collection and CollectionItem components for improved testability * feat: hide dropdown on select in response selector * fix: update QueryResult component to use detectedContentType for format handling * test: update ResponseLayoutToggle tests to use data-testid for button selection * feat: add data-testid attribute to ResponseClear component for improved testability * refactor: implement clickResponseAction utility for streamlined response action handling in tests * feat: add data-testid attribute to ResponseCopy component for enhanced testability * fix: unwanted code in test
124 lines
4.7 KiB
JavaScript
124 lines
4.7 KiB
JavaScript
import get from 'lodash/get';
|
|
import { mockDataFunctions } from '@usebruno/common';
|
|
import { PROMPT_VARIABLE_TEXT_PATTERN } from '@usebruno/common/utils';
|
|
|
|
const CodeMirror = require('codemirror');
|
|
|
|
const pathFoundInVariables = (path, obj) => {
|
|
const value = get(obj, path);
|
|
return value !== undefined;
|
|
};
|
|
|
|
/**
|
|
* Defines a custom CodeMirror mode for Bruno variables highlighting.
|
|
* This function creates a specialized mode that can highlight both Bruno template
|
|
* variables (in the format {{variable}}) and URL path parameters (in the format /:param).
|
|
*
|
|
* @param {Object} _variables - The variables object containing data to validate against
|
|
* @param {string} mode - The base CodeMirror mode to extend (e.g., 'javascript', 'application/json')
|
|
* @param {boolean} highlightPathParams - Whether to highlight URL path parameters
|
|
* @param {boolean} highlightVariables - Whether to highlight template variables
|
|
* @returns {void} - Registers the mode with CodeMirror for later use
|
|
*/
|
|
export const defineCodeMirrorBrunoVariablesMode = (_variables, mode, highlightPathParams, highlightVariables) => {
|
|
CodeMirror.defineMode('brunovariables', function (config, parserConfig) {
|
|
const { pathParams = {}, ...variables } = _variables || {};
|
|
const variablesOverlay = {
|
|
token: function (stream) {
|
|
if (stream.match('{{', true)) {
|
|
let ch;
|
|
let word = '';
|
|
while ((ch = stream.next()) != null) {
|
|
if (ch === '}' && stream.peek() === '}') {
|
|
stream.eat('}');
|
|
|
|
// Prompt variable: starts with '?', no leading/trailing spaces, no braces
|
|
if (PROMPT_VARIABLE_TEXT_PATTERN.test(word)) {
|
|
return `variable-prompt`;
|
|
}
|
|
|
|
// Check if it's a mock variable (starts with $) and exists in mockDataFunctions
|
|
const isMockVariable = word.startsWith('$') && mockDataFunctions.hasOwnProperty(word.substring(1));
|
|
const found = isMockVariable || pathFoundInVariables(word, variables);
|
|
const status = found ? 'valid' : 'invalid';
|
|
const randomClass = `random-${(Math.random() + 1).toString(36).substring(9)}`;
|
|
return `variable-${status} ${randomClass}`;
|
|
}
|
|
word += ch;
|
|
}
|
|
}
|
|
stream.skipTo('{{') || stream.skipToEnd();
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const urlPathParamsOverlay = {
|
|
token: function (stream) {
|
|
if (stream.match('/:', true)) {
|
|
let ch;
|
|
let word = '';
|
|
while ((ch = stream.next()) != null) {
|
|
if (ch === '/' || ch === '?' || ch === '&' || ch === '=') {
|
|
stream.backUp(1);
|
|
const found = pathFoundInVariables(word, pathParams);
|
|
const status = found ? 'valid' : 'invalid';
|
|
const randomClass = `random-${(Math.random() + 1).toString(36).substring(9)}`;
|
|
return `variable-${status} ${randomClass}`;
|
|
}
|
|
word += ch;
|
|
}
|
|
|
|
// If we've consumed all characters and the word is not empty, it might be a path parameter at the end of the URL.
|
|
if (word) {
|
|
const found = pathFoundInVariables(word, pathParams);
|
|
const status = found ? 'valid' : 'invalid';
|
|
const randomClass = `random-${(Math.random() + 1).toString(36).substring(9)}`;
|
|
return `variable-${status} ${randomClass}`;
|
|
}
|
|
}
|
|
stream.skipTo('/:') || stream.skipToEnd();
|
|
return null;
|
|
}
|
|
};
|
|
|
|
let baseMode = CodeMirror.getMode(config, parserConfig.backdrop || mode);
|
|
|
|
if (highlightVariables) {
|
|
baseMode = CodeMirror.overlayMode(baseMode, variablesOverlay);
|
|
}
|
|
if (highlightPathParams) {
|
|
baseMode = CodeMirror.overlayMode(baseMode, urlPathParamsOverlay);
|
|
}
|
|
return baseMode;
|
|
});
|
|
};
|
|
|
|
export const getCodeMirrorModeBasedOnContentType = (contentType, body) => {
|
|
if (typeof body === 'object') {
|
|
return 'application/ld+json';
|
|
}
|
|
if (!contentType || typeof contentType !== 'string') {
|
|
return 'application/text';
|
|
}
|
|
|
|
if (contentType.includes('json')) {
|
|
return 'application/ld+json';
|
|
} else if (contentType.includes('javascript') || contentType.includes('ecmascript')) {
|
|
return 'application/javascript';
|
|
} else if (contentType.includes('image')) {
|
|
return 'application/image';
|
|
} else if (contentType.includes('xml')) {
|
|
return 'application/xml';
|
|
} else if (contentType.includes('html')) {
|
|
return 'application/html';
|
|
} else if (contentType.includes('text')) {
|
|
return 'application/text';
|
|
} else if (contentType.includes('application/edn')) {
|
|
return 'application/xml';
|
|
} else if (contentType.includes('yaml')) {
|
|
return 'application/yaml';
|
|
} else {
|
|
return 'application/text';
|
|
}
|
|
};
|