Initial commit: Aeroflot Flights Web - Angular 12 baseline

- Angular 12 application with PrimeNG components
- 5 existing Cypress e2e test suites
- SCSS styling with BEM naming convention
- i18n support (10 languages)
- Leaflet map integration
- Complete component hierarchy and routing structure

This baseline will be used for Angular → React migration.
This commit is contained in:
gnezim
2026-04-05 18:47:57 +03:00
commit 0a5ab058a6
34439 changed files with 4408974 additions and 0 deletions
@@ -0,0 +1,101 @@
/* global __react_refresh_error_overlay__, __react_refresh_socket__, __resourceQuery */
const events = require('./utils/errorEventHandlers.js');
const formatWebpackErrors = require('./utils/formatWebpackErrors.js');
const runWithRetry = require('./utils/retry.js');
// Setup error states
let isHotReload = false;
let hasRuntimeErrors = false;
/**
* Try dismissing the compile error overlay.
* This will also reset runtime error records (if any),
* because we have new source to evaluate.
* @returns {void}
*/
function tryDismissErrorOverlay() {
__react_refresh_error_overlay__.clearCompileError();
__react_refresh_error_overlay__.clearRuntimeErrors(!hasRuntimeErrors);
hasRuntimeErrors = false;
}
/**
* A function called after a compile success signal is received from Webpack.
* @returns {void}
*/
function handleCompileSuccess() {
isHotReload = true;
if (isHotReload) {
tryDismissErrorOverlay();
}
}
/**
* A function called after a compile errored signal is received from Webpack.
* @param {string[]} errors
* @returns {void}
*/
function handleCompileErrors(errors) {
isHotReload = true;
const formattedErrors = formatWebpackErrors(errors);
// Only show the first error
__react_refresh_error_overlay__.showCompileError(formattedErrors[0]);
}
/**
* Handles compilation messages from Webpack.
* Integrates with a compile error overlay.
* @param {*} message A Webpack HMR message sent via WebSockets.
* @returns {void}
*/
function compileMessageHandler(message) {
switch (message.type) {
case 'ok':
case 'still-ok':
case 'warnings': {
// TODO: Implement handling for warnings
handleCompileSuccess();
break;
}
case 'errors': {
handleCompileErrors(message.data);
break;
}
default: {
// Do nothing.
}
}
}
if (process.env.NODE_ENV !== 'production') {
if (typeof window !== 'undefined') {
function setupOverlay() {
// Only register if no other overlay have been registered
if (!window.__reactRefreshOverlayInjected && __react_refresh_socket__) {
// Registers handlers for compile errors with retry -
// This is to prevent mismatching injection order causing errors to be thrown
runWithRetry(function initSocket() {
__react_refresh_socket__.init(compileMessageHandler, __resourceQuery);
}, 3);
// Registers handlers for runtime errors
events.handleError(function handleError(error) {
hasRuntimeErrors = true;
__react_refresh_error_overlay__.handleRuntimeError(error);
});
events.handleUnhandledRejection(
function handleUnhandledPromiseRejection(error) {
hasRuntimeErrors = true;
__react_refresh_error_overlay__.handleRuntimeError(error);
},
);
// Mark overlay as injected to prevent double-injection
window.__reactRefreshOverlayInjected = true;
}
}
setupOverlay();
}
}
@@ -0,0 +1,63 @@
const ansiHTML = require('../../utils/ansi-html.js');
const entities = require('html-entities');
const theme = require('../theme.js');
const utils = require('../utils.js');
ansiHTML.setColors(theme);
/**
* @typedef {Object} CompileErrorTraceProps
* @property {string} errorMessage
*/
/**
* A formatter that turns Webpack compile error messages into highlighted HTML source traces.
* @param {Document} document
* @param {HTMLElement} root
* @param {CompileErrorTraceProps} props
* @returns {void}
*/
function CompileErrorTrace(document, root, props) {
const errorParts = props.errorMessage.split('\n');
if (errorParts.length) {
if (errorParts[0]) {
errorParts[0] = utils.formatFilename(errorParts[0]);
}
const errorMessage = errorParts.splice(1, 1)[0];
if (errorMessage) {
// Strip filename from the error message
errorParts.unshift(errorMessage.replace(/^(.*:)\s.*:(\s.*)$/, '$1$2'));
}
}
const stackContainer = document.createElement('pre');
stackContainer.innerHTML = entities.decode(
ansiHTML(
entities.encode(errorParts.join('\n'), {
level: 'html5',
mode: 'nonAscii',
}),
),
{ level: 'html5' },
);
stackContainer.style.fontFamily = [
'"Operator Mono SSm"',
'"Operator Mono"',
'"Fira Code Retina"',
'"Fira Code"',
'"FiraCode-Retina"',
'"Andale Mono"',
'"Lucida Console"',
'Menlo',
'Consolas',
'Monaco',
'monospace',
].join(', ');
stackContainer.style.margin = '0';
stackContainer.style.whiteSpace = 'pre-wrap';
root.appendChild(stackContainer);
}
module.exports = CompileErrorTrace;
@@ -0,0 +1,60 @@
const Spacer = require('./Spacer.js');
const theme = require('../theme.js');
/**
* @typedef {Object} PageHeaderProps
* @property {string} [message]
* @property {string} title
* @property {string} [topOffset]
*/
/**
* The header of the overlay.
* @param {Document} document
* @param {HTMLElement} root
* @param {PageHeaderProps} props
* @returns {void}
*/
function PageHeader(document, root, props) {
const pageHeaderContainer = document.createElement('div');
pageHeaderContainer.style.background = '#' + theme.dimgrey;
pageHeaderContainer.style.boxShadow = '0 1px 4px rgba(0, 0, 0, 0.3)';
pageHeaderContainer.style.color = '#' + theme.white;
pageHeaderContainer.style.left = '0';
pageHeaderContainer.style.right = '0';
pageHeaderContainer.style.padding = '1rem 1.5rem';
pageHeaderContainer.style.paddingLeft =
'max(1.5rem, env(safe-area-inset-left))';
pageHeaderContainer.style.paddingRight =
'max(1.5rem, env(safe-area-inset-right))';
pageHeaderContainer.style.position = 'fixed';
pageHeaderContainer.style.top = props.topOffset || '0';
const title = document.createElement('h3');
title.innerText = props.title;
title.style.color = '#' + theme.red;
title.style.fontSize = '1.125rem';
title.style.lineHeight = '1.3';
title.style.margin = '0';
pageHeaderContainer.appendChild(title);
if (props.message) {
title.style.margin = '0 0 0.5rem';
const message = document.createElement('span');
message.innerText = props.message;
message.style.color = '#' + theme.white;
message.style.wordBreak = 'break-word';
pageHeaderContainer.appendChild(message);
}
root.appendChild(pageHeaderContainer);
// This has to run after appending elements to root
// because we need to actual mounted height.
Spacer(document, root, {
space: pageHeaderContainer.offsetHeight.toString(10),
});
}
module.exports = PageHeader;
@@ -0,0 +1,93 @@
const Spacer = require('./Spacer.js');
const theme = require('../theme.js');
/**
* @typedef {Object} RuntimeErrorFooterProps
* @property {string} [initialFocus]
* @property {boolean} multiple
* @property {function(MouseEvent): void} onClickCloseButton
* @property {function(MouseEvent): void} onClickNextButton
* @property {function(MouseEvent): void} onClickPrevButton
*/
/**
* A fixed footer that handles pagination of runtime errors.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorFooterProps} props
* @returns {void}
*/
function RuntimeErrorFooter(document, root, props) {
const footer = document.createElement('div');
footer.style.backgroundColor = '#' + theme.dimgrey;
footer.style.bottom = '0';
footer.style.boxShadow = '0 -1px 4px rgba(0, 0, 0, 0.3)';
footer.style.height = '2.5rem';
footer.style.left = '0';
footer.style.right = '0';
footer.style.lineHeight = '2.5rem';
footer.style.paddingBottom = '0';
footer.style.paddingBottom = 'env(safe-area-inset-bottom)';
footer.style.position = 'fixed';
footer.style.textAlign = 'center';
footer.style.zIndex = '2';
const BUTTON_CONFIGS = {
prev: {
id: 'prev',
label: '◀ Prev',
onClick: props.onClickPrevButton,
},
close: {
id: 'close',
label: '× Close',
onClick: props.onClickCloseButton,
},
next: {
id: 'next',
label: 'Next ▶',
onClick: props.onClickNextButton,
},
};
let buttons = [BUTTON_CONFIGS.close];
if (props.multiple) {
buttons = [BUTTON_CONFIGS.prev, BUTTON_CONFIGS.close, BUTTON_CONFIGS.next];
}
/** @type {HTMLButtonElement | undefined} */
let initialFocusButton;
for (let i = 0; i < buttons.length; i += 1) {
const buttonConfig = buttons[i];
const button = document.createElement('button');
button.id = buttonConfig.id;
button.innerHTML = buttonConfig.label;
button.tabIndex = 1;
button.style.backgroundColor = '#' + theme.dimgrey;
button.style.border = 'none';
button.style.color = '#' + theme.white;
button.style.cursor = 'pointer';
button.style.fontSize = 'inherit';
button.style.height = '100%';
button.style.padding = '0.5rem 0.75rem';
button.style.width = (100 / buttons.length).toString(10) + '%';
button.addEventListener('click', buttonConfig.onClick);
if (buttonConfig.id === props.initialFocus) {
initialFocusButton = button;
}
footer.appendChild(button);
}
root.appendChild(footer);
Spacer(document, root, { space: '2.5rem' });
if (initialFocusButton) {
initialFocusButton.focus();
}
}
module.exports = RuntimeErrorFooter;
@@ -0,0 +1,38 @@
const Spacer = require('./Spacer.js');
const theme = require('../theme.js');
/**
* @typedef {Object} RuntimeErrorHeaderProps
* @property {number} currentErrorIndex
* @property {number} totalErrors
*/
/**
* A fixed header that shows the total runtime error count.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorHeaderProps} props
* @returns {void}
*/
function RuntimeErrorHeader(document, root, props) {
const header = document.createElement('div');
header.innerText =
'Error ' + (props.currentErrorIndex + 1) + ' of ' + props.totalErrors;
header.style.backgroundColor = '#' + theme.red;
header.style.color = '#' + theme.white;
header.style.fontWeight = '500';
header.style.height = '2.5rem';
header.style.left = '0';
header.style.lineHeight = '2.5rem';
header.style.position = 'fixed';
header.style.textAlign = 'center';
header.style.top = '0';
header.style.width = '100vw';
header.style.zIndex = '2';
root.appendChild(header);
Spacer(document, root, { space: '2.5rem' });
}
module.exports = RuntimeErrorHeader;
@@ -0,0 +1,80 @@
const ErrorStackParser = require('error-stack-parser');
const theme = require('../theme.js');
const utils = require('../utils.js');
/**
* @typedef {Object} RuntimeErrorStackProps
* @property {Error} error
*/
/**
* A formatter that turns runtime error stacks into highlighted HTML stacks.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorStackProps} props
* @returns {void}
*/
function RuntimeErrorStack(document, root, props) {
const stackTitle = document.createElement('h4');
stackTitle.innerText = 'Call Stack';
stackTitle.style.color = '#' + theme.white;
stackTitle.style.fontSize = '1.0625rem';
stackTitle.style.fontWeight = '500';
stackTitle.style.lineHeight = '1.3';
stackTitle.style.margin = '0 0 0.5rem';
const stackContainer = document.createElement('div');
stackContainer.style.fontSize = '0.8125rem';
stackContainer.style.lineHeight = '1.3';
stackContainer.style.whiteSpace = 'pre-wrap';
let errorStacks;
try {
errorStacks = ErrorStackParser.parse(props.error);
} catch (e) {
errorStacks = [];
stackContainer.innerHTML = 'No stack trace is available for this error!';
}
for (let i = 0; i < Math.min(errorStacks.length, 10); i += 1) {
const currentStack = errorStacks[i];
const functionName = document.createElement('code');
functionName.innerHTML =
'&emsp;' + currentStack.functionName || '(anonymous function)';
functionName.style.color = '#' + theme.yellow;
functionName.style.fontFamily = [
'"Operator Mono SSm"',
'"Operator Mono"',
'"Fira Code Retina"',
'"Fira Code"',
'"FiraCode-Retina"',
'"Andale Mono"',
'"Lucida Console"',
'Menlo',
'Consolas',
'Monaco',
'monospace',
].join(', ');
const fileName = document.createElement('div');
fileName.innerHTML =
'&emsp;&emsp;' +
utils.formatFilename(currentStack.fileName) +
':' +
currentStack.lineNumber +
':' +
currentStack.columnNumber;
fileName.style.color = '#' + theme.white;
fileName.style.fontSize = '0.6875rem';
fileName.style.marginBottom = '0.25rem';
stackContainer.appendChild(functionName);
stackContainer.appendChild(fileName);
}
root.appendChild(stackTitle);
root.appendChild(stackContainer);
}
module.exports = RuntimeErrorStack;
@@ -0,0 +1,19 @@
/**
* @typedef {Object} SpacerProps
* @property {string} space
*/
/**
* An empty element to add spacing manually.
* @param {Document} document
* @param {HTMLElement} root
* @param {SpacerProps} props
* @returns {void}
*/
function Spacer(document, root, props) {
const spacer = document.createElement('div');
spacer.style.paddingBottom = props.space;
root.appendChild(spacer);
}
module.exports = Spacer;
@@ -0,0 +1,25 @@
const CompileErrorTrace = require('../components/CompileErrorTrace.js');
const PageHeader = require('../components/PageHeader.js');
const Spacer = require('../components/Spacer.js');
/**
* @typedef {Object} CompileErrorContainerProps
* @property {string} errorMessage
*/
/**
* A container to render Webpack compilation error messages with source trace.
* @param {Document} document
* @param {HTMLElement} root
* @param {CompileErrorContainerProps} props
* @returns {void}
*/
function CompileErrorContainer(document, root, props) {
PageHeader(document, root, {
title: 'Failed to compile.',
});
CompileErrorTrace(document, root, { errorMessage: props.errorMessage });
Spacer(document, root, { space: '1rem' });
}
module.exports = CompileErrorContainer;
@@ -0,0 +1,29 @@
const PageHeader = require('../components/PageHeader.js');
const RuntimeErrorStack = require('../components/RuntimeErrorStack.js');
const Spacer = require('../components/Spacer.js');
/**
* @typedef {Object} RuntimeErrorContainerProps
* @property {Error} currentError
*/
/**
* A container to render runtime error messages with stack trace.
* @param {Document} document
* @param {HTMLElement} root
* @param {RuntimeErrorContainerProps} props
* @returns {void}
*/
function RuntimeErrorContainer(document, root, props) {
PageHeader(document, root, {
message: props.currentError.message,
title: props.currentError.name,
topOffset: '2.5rem',
});
RuntimeErrorStack(document, root, {
error: props.currentError,
});
Spacer(document, root, { space: '1rem' });
}
module.exports = RuntimeErrorContainer;
@@ -0,0 +1,351 @@
const RuntimeErrorFooter = require('./components/RuntimeErrorFooter.js');
const RuntimeErrorHeader = require('./components/RuntimeErrorHeader.js');
const CompileErrorContainer = require('./containers/CompileErrorContainer.js');
const RuntimeErrorContainer = require('./containers/RuntimeErrorContainer.js');
const theme = require('./theme.js');
const utils = require('./utils.js');
/**
* @callback RenderFn
* @returns {void}
*/
/* ===== Cached elements for DOM manipulations ===== */
/**
* The iframe that contains the overlay.
* @type {HTMLIFrameElement}
*/
let iframeRoot = null;
/**
* The document object from the iframe root, used to create and render elements.
* @type {Document}
*/
let rootDocument = null;
/**
* The root div elements will attach to.
* @type {HTMLDivElement}
*/
let root = null;
/**
* A Cached function to allow deferred render.
* @type {RenderFn | null}
*/
let scheduledRenderFn = null;
/* ===== Overlay State ===== */
/**
* The latest error message from Webpack compilation.
* @type {string}
*/
let currentCompileErrorMessage = '';
/**
* Index of the error currently shown by the overlay.
* @type {number}
*/
let currentRuntimeErrorIndex = 0;
/**
* The latest runtime error objects.
* @type {Error[]}
*/
let currentRuntimeErrors = [];
/**
* The render mode the overlay is currently in.
* @type {'compileError' | 'runtimeError' | null}
*/
let currentMode = null;
/**
* @typedef {Object} IframeProps
* @property {function(): void} onIframeLoad
*/
/**
* Creates the main `iframe` the overlay will attach to.
* Accepts a callback to be ran after iframe is initialized.
* @param {Document} document
* @param {HTMLElement} root
* @param {IframeProps} props
* @returns {HTMLIFrameElement}
*/
function IframeRoot(document, root, props) {
const iframe = document.createElement('iframe');
iframe.id = 'react-refresh-overlay';
iframe.src = 'about:blank';
iframe.style.border = 'none';
iframe.style.height = '100%';
iframe.style.left = '0';
iframe.style.minHeight = '100vh';
iframe.style.minHeight = '-webkit-fill-available';
iframe.style.position = 'fixed';
iframe.style.top = '0';
iframe.style.width = '100vw';
iframe.style.zIndex = '2147483647';
iframe.addEventListener('load', function onLoad() {
// Reset margin of iframe body
iframe.contentDocument.body.style.margin = '0';
props.onIframeLoad();
});
// We skip mounting and returns as we need to ensure
// the load event is fired after we setup the global variable
return iframe;
}
/**
* Creates the main `div` element for the overlay to render.
* @param {Document} document
* @param {HTMLElement} root
* @returns {HTMLDivElement}
*/
function OverlayRoot(document, root) {
const div = document.createElement('div');
div.id = 'react-refresh-overlay-error';
// Style the contents container
div.style.backgroundColor = '#' + theme.grey;
div.style.boxSizing = 'border-box';
div.style.color = '#' + theme.white;
div.style.fontFamily = [
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'"Helvetica Neue"',
'Helvetica',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'Segoe UI Symbol',
].join(', ');
div.style.fontSize = '0.875rem';
div.style.height = '100%';
div.style.lineHeight = '1.3';
div.style.overflow = 'auto';
div.style.padding = '1rem 1.5rem 0';
div.style.paddingTop = 'max(1rem, env(safe-area-inset-top))';
div.style.paddingRight = 'max(1.5rem, env(safe-area-inset-right))';
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
div.style.paddingLeft = 'max(1.5rem, env(safe-area-inset-left))';
div.style.width = '100vw';
root.appendChild(div);
return div;
}
/**
* Ensures the iframe root and the overlay root are both initialized before render.
* If check fails, render will be deferred until both roots are initialized.
* @param {RenderFn} renderFn A function that triggers a DOM render.
* @returns {void}
*/
function ensureRootExists(renderFn) {
if (root) {
// Overlay root is ready, we can render right away.
renderFn();
return;
}
// Creating an iframe may be asynchronous so we'll defer render.
// In case of multiple calls, function from the last call will be used.
scheduledRenderFn = renderFn;
if (iframeRoot) {
// Iframe is already ready, it will fire the load event.
return;
}
// Create the iframe root, and, the overlay root inside it when it is ready.
iframeRoot = IframeRoot(document, document.body, {
onIframeLoad: function onIframeLoad() {
rootDocument = iframeRoot.contentDocument;
root = OverlayRoot(rootDocument, rootDocument.body);
scheduledRenderFn();
},
});
// We have to mount here to ensure `iframeRoot` is set when `onIframeLoad` fires.
// This is because onIframeLoad() will be called synchronously
// or asynchronously depending on the browser.
document.body.appendChild(iframeRoot);
}
/**
* Creates the main `div` element for the overlay to render.
* @returns {void}
*/
function render() {
ensureRootExists(function () {
const currentFocus = rootDocument.activeElement;
let currentFocusId;
if (currentFocus.localName === 'button' && currentFocus.id) {
currentFocusId = currentFocus.id;
}
utils.removeAllChildren(root);
if (currentCompileErrorMessage) {
currentMode = 'compileError';
CompileErrorContainer(rootDocument, root, {
errorMessage: currentCompileErrorMessage,
});
} else if (currentRuntimeErrors.length) {
currentMode = 'runtimeError';
RuntimeErrorHeader(rootDocument, root, {
currentErrorIndex: currentRuntimeErrorIndex,
totalErrors: currentRuntimeErrors.length,
});
RuntimeErrorContainer(rootDocument, root, {
currentError: currentRuntimeErrors[currentRuntimeErrorIndex],
});
RuntimeErrorFooter(rootDocument, root, {
initialFocus: currentFocusId,
multiple: currentRuntimeErrors.length > 1,
onClickCloseButton: function onClose() {
clearRuntimeErrors();
},
onClickNextButton: function onNext() {
if (currentRuntimeErrorIndex === currentRuntimeErrors.length - 1) {
return;
}
currentRuntimeErrorIndex += 1;
ensureRootExists(render);
},
onClickPrevButton: function onPrev() {
if (currentRuntimeErrorIndex === 0) {
return;
}
currentRuntimeErrorIndex -= 1;
ensureRootExists(render);
},
});
}
});
}
/**
* Destroys the state of the overlay.
* @returns {void}
*/
function cleanup() {
// Clean up and reset all internal state.
try {
document.body.removeChild(iframeRoot);
} catch (e) {
// In case user render react app directly to body will trigger `NotFoundError` when recovery from an Error
// https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild#exceptions
}
scheduledRenderFn = null;
root = null;
iframeRoot = null;
}
/**
* Clears Webpack compilation errors and dismisses the compile error overlay.
* @returns {void}
*/
function clearCompileError() {
if (!root || currentMode !== 'compileError') {
return;
}
currentCompileErrorMessage = '';
currentMode = null;
cleanup();
}
/**
* Clears runtime error records and dismisses the runtime error overlay.
* @param {boolean} [dismissOverlay] Whether to dismiss the overlay or not.
* @returns {void}
*/
function clearRuntimeErrors(dismissOverlay) {
if (!root || currentMode !== 'runtimeError') {
return;
}
currentRuntimeErrorIndex = 0;
currentRuntimeErrors = [];
if (typeof dismissOverlay === 'undefined' || dismissOverlay) {
currentMode = null;
cleanup();
}
}
/**
* Shows the compile error overlay with the specific Webpack error message.
* @param {string} message
* @returns {void}
*/
function showCompileError(message) {
if (!message) {
return;
}
currentCompileErrorMessage = message;
render();
}
/**
* Shows the runtime error overlay with the specific error records.
* @param {Error[]} errors
* @returns {void}
*/
function showRuntimeErrors(errors) {
if (!errors || !errors.length) {
return;
}
currentRuntimeErrors = errors;
render();
}
/**
* The debounced version of `showRuntimeErrors` to prevent frequent renders
* due to rapid firing listeners.
* @param {Error[]} errors
* @returns {void}
*/
const debouncedShowRuntimeErrors = utils.debounce(showRuntimeErrors, 30);
/**
* Detects if an error is a Webpack compilation error.
* @param {Error} error The error of interest.
* @returns {boolean} If the error is a Webpack compilation error.
*/
function isWebpackCompileError(error) {
return (
/Module [A-z ]+\(from/.test(error.message) ||
/Cannot find module/.test(error.message)
);
}
/**
* Handles runtime error contexts captured with EventListeners.
* Integrates with a runtime error overlay.
* @param {Error} error A valid error object.
* @returns {void}
*/
function handleRuntimeError(error) {
if (
error &&
!isWebpackCompileError(error) &&
currentRuntimeErrors.indexOf(error) === -1
) {
currentRuntimeErrors = currentRuntimeErrors.concat(error);
}
debouncedShowRuntimeErrors(currentRuntimeErrors);
}
module.exports = Object.freeze({
clearCompileError: clearCompileError,
clearRuntimeErrors: clearRuntimeErrors,
handleRuntimeError: handleRuntimeError,
showCompileError: showCompileError,
showRuntimeErrors: showRuntimeErrors,
});
@@ -0,0 +1,39 @@
/**
* @typedef {Object} Theme
* @property {string[]} reset
* @property {string} black
* @property {string} red
* @property {string} green
* @property {string} yellow
* @property {string} blue
* @property {string} magenta
* @property {string} cyan
* @property {string} white
* @property {string} lightgrey
* @property {string} darkgrey
* @property {string} grey
* @property {string} dimgrey
*/
/**
* @type {Theme} theme
* A collection of colors to be used by the overlay.
* Partially adopted from Tomorrow Night Bright.
*/
const theme = {
reset: ['transparent', 'transparent'],
black: '000000',
red: 'D34F56',
green: 'B9C954',
yellow: 'E6C452',
blue: '7CA7D8',
magenta: 'C299D6',
cyan: '73BFB1',
white: 'FFFFFF',
lightgrey: 'C7C7C7',
darkgrey: 'A9A9A9',
grey: '474747',
dimgrey: '343434',
};
module.exports = theme;
@@ -0,0 +1,74 @@
/**
* Debounce a function to delay invoking until wait (ms) have elapsed since the last invocation.
* @param {function(...*): *} fn The function to be debounced.
* @param {number} wait Milliseconds to wait before invoking again.
* @return {function(...*): void} The debounced function.
*/
function debounce(fn, wait) {
/**
* A cached setTimeout handler.
* @type {number | undefined}
*/
let timer;
/**
* @returns {void}
*/
function debounced() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
return fn.apply(context, args);
}, wait);
}
return debounced;
}
/**
* Prettify a filename from error stacks into the desired format.
* @param {string} filename The filename to be formatted.
* @returns {string} The formatted filename.
*/
function formatFilename(filename) {
// Strip away protocol and domain for compiled files
const htmlMatch = /^https?:\/\/(.*)\/(.*)/.exec(filename);
if (htmlMatch && htmlMatch[1] && htmlMatch[2]) {
return htmlMatch[2];
}
// Strip everything before the first directory for source files
const sourceMatch = /\/.*?([^./]+[/|\\].*)$/.exec(filename);
if (sourceMatch && sourceMatch[1]) {
return sourceMatch[1].replace(/\?$/, '');
}
// Unknown filename type, use it as is
return filename;
}
/**
* Remove all children of an element.
* @param {HTMLElement} element A valid HTML element.
* @param {number} [skip] Number of elements to skip removing.
* @returns {void}
*/
function removeAllChildren(element, skip) {
/** @type {Node[]} */
const childList = Array.prototype.slice.call(
element.childNodes,
typeof skip !== 'undefined' ? skip : 0,
);
for (let i = 0; i < childList.length; i += 1) {
element.removeChild(childList[i]);
}
}
module.exports = {
debounce: debounce,
formatFilename: formatFilename,
removeAllChildren: removeAllChildren,
};
@@ -0,0 +1,35 @@
const RefreshUtils = require('./refreshUtils');
const RefreshRuntime = require('react-refresh/runtime');
function refresh(moduleId, webpackHot) {
const currentExports = RefreshUtils.getModuleExports(moduleId);
const fn = (exports) => {
var errorOverlay;
if (typeof __react_refresh_error_overlay__ !== 'undefined') {
errorOverlay = __react_refresh_error_overlay__;
}
var testMode;
if (typeof __react_refresh_test__ !== 'undefined') {
testMode = __react_refresh_test__;
}
RefreshUtils.executeRuntime(
exports,
moduleId,
webpackHot,
errorOverlay,
testMode,
);
};
if (typeof Promise !== 'undefined' && currentExports instanceof Promise) {
currentExports.then(fn);
} else {
fn(currentExports);
}
}
module.exports = {
refresh,
register: RefreshRuntime.register,
createSignatureFunctionForTransform:
RefreshRuntime.createSignatureFunctionForTransform,
};
@@ -0,0 +1,50 @@
var RefreshRuntime = require('react-refresh/runtime');
var safeThis = (function () {
// copied from core-js-pure/features/global-this
'use strict';
var check = function (it) {
return it && it.Math == Math && it;
};
// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
// eslint-disable-next-line es/no-global-this -- safe
return (
check(typeof globalThis == 'object' && globalThis) ||
check(typeof window == 'object' && window) ||
// eslint-disable-next-line no-restricted-globals -- safe
check(typeof self == 'object' && self) ||
check(typeof __webpack_require__.g == 'object' && __webpack_require__.g) ||
// eslint-disable-next-line no-new-func -- fallback
(function () {
return this;
})() ||
this ||
Function('return this')()
);
})();
if (process.env.NODE_ENV !== 'production') {
if (typeof safeThis !== 'undefined') {
var $RefreshInjected$ = '__reactRefreshInjected';
// Namespace the injected flag (if necessary) for monorepo compatibility
if (
typeof __react_refresh_library__ !== 'undefined' &&
__react_refresh_library__
) {
$RefreshInjected$ += '_' + __react_refresh_library__;
}
// Only inject the runtime if it hasn't been injected
if (!safeThis[$RefreshInjected$]) {
RefreshRuntime.injectIntoGlobalHook(safeThis);
// Empty implementation to avoid "ReferenceError: variable is not defined" in module which didn't pass builtin:react-refresh-loader
safeThis.$RefreshSig$ = () => (type) => type;
safeThis.$RefreshReg$ = () => {};
// Mark the runtime as injected to prevent double-injection
safeThis[$RefreshInjected$] = true;
}
}
}
@@ -0,0 +1,301 @@
/* global __webpack_require__ */
var Refresh = require('react-refresh/runtime');
/**
* Extracts exports from a webpack module object.
* @param {string} moduleId A Webpack module ID.
* @returns {*} An exports object from the module.
*/
function getModuleExports(moduleId) {
if (typeof moduleId === 'undefined') {
// `moduleId` is unavailable, which indicates that this module is not in the cache,
// which means we won't be able to capture any exports,
// and thus they cannot be refreshed safely.
// These are likely runtime or dynamically generated modules.
return {};
}
var maybeModule = __webpack_require__.c[moduleId];
if (typeof maybeModule === 'undefined') {
// `moduleId` is available but the module in cache is unavailable,
// which indicates the module is somehow corrupted (e.g. broken Webpacak `module` globals).
// We will warn the user (as this is likely a mistake) and assume they cannot be refreshed.
console.warn(
'[React Refresh] Failed to get exports for module: ' + moduleId + '.',
);
return {};
}
var exportsOrPromise = maybeModule.exports;
if (typeof Promise !== 'undefined' && exportsOrPromise instanceof Promise) {
return exportsOrPromise.then(function (exports) {
return exports;
});
}
return exportsOrPromise;
}
/**
* Calculates the signature of a React refresh boundary.
* If this signature changes, it's unsafe to accept the boundary.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/907d6af22ac6ebe58572be418e9253a90665ecbd/packages/metro/src/lib/polyfills/require.js#L795-L816).
* @param {*} moduleExports A Webpack module exports object.
* @returns {string[]} A React refresh boundary signature array.
*/
function getReactRefreshBoundarySignature(moduleExports) {
var signature = [];
signature.push(Refresh.getFamilyByType(moduleExports));
if (moduleExports == null || typeof moduleExports !== 'object') {
// Exit if we can't iterate over exports.
return signature;
}
for (var key in moduleExports) {
if (key === '__esModule') {
continue;
}
signature.push(key);
signature.push(Refresh.getFamilyByType(moduleExports[key]));
}
return signature;
}
/**
* Creates a helper that performs a delayed React refresh.
* @returns {function(function(): void): void} A debounced React refresh function.
*/
function createDebounceUpdate() {
/**
* A cached setTimeout handler.
* @type {number | undefined}
*/
var refreshTimeout;
/**
* Performs react refresh on a delay and clears the error overlay.
* @param {function(): void} callback
* @returns {void}
*/
function enqueueUpdate(callback) {
if (typeof refreshTimeout === 'undefined') {
refreshTimeout = setTimeout(function () {
refreshTimeout = undefined;
Refresh.performReactRefresh();
callback();
}, 30);
}
}
return enqueueUpdate;
}
/**
* Checks if all exports are likely a React component.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/febdba2383113c88296c61e28e4ef6a7f4939fda/packages/metro/src/lib/polyfills/require.js#L748-L774).
* @param {*} moduleExports A Webpack module exports object.
* @returns {boolean} Whether the exports are React component like.
*/
function isReactRefreshBoundary(moduleExports) {
if (Refresh.isLikelyComponentType(moduleExports)) {
return true;
}
if (
moduleExports === undefined ||
moduleExports === null ||
typeof moduleExports !== 'object'
) {
// Exit if we can't iterate over exports.
return false;
}
var hasExports = false;
var areAllExportsComponents = true;
for (var key in moduleExports) {
hasExports = true;
// This is the ES Module indicator flag
if (key === '__esModule') {
continue;
}
// We can (and have to) safely execute getters here,
// as Webpack manually assigns harmony exports to getters,
// without any side-effects attached.
// Ref: https://github.com/webpack/webpack/blob/b93048643fe74de2a6931755911da1212df55897/lib/MainTemplate.js#L281
var exportValue = moduleExports[key];
if (!Refresh.isLikelyComponentType(exportValue)) {
areAllExportsComponents = false;
}
}
return hasExports && areAllExportsComponents;
}
/**
* Checks if exports are likely a React component and registers them.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/febdba2383113c88296c61e28e4ef6a7f4939fda/packages/metro/src/lib/polyfills/require.js#L818-L835).
* @param {*} moduleExports A Webpack module exports object.
* @param {string} moduleId A Webpack module ID.
* @returns {void}
*/
function registerExportsForReactRefresh(moduleExports, moduleId) {
if (Refresh.isLikelyComponentType(moduleExports)) {
// Register module.exports if it is likely a component
Refresh.register(moduleExports, moduleId + ' %exports%');
}
if (
moduleExports === undefined ||
moduleExports === null ||
typeof moduleExports !== 'object'
) {
// Exit if we can't iterate over the exports.
return;
}
for (var key in moduleExports) {
// Skip registering the ES Module indicator
if (key === '__esModule') {
continue;
}
var exportValue = moduleExports[key];
if (Refresh.isLikelyComponentType(exportValue)) {
var typeID = moduleId + ' %exports% ' + key;
Refresh.register(exportValue, typeID);
}
}
}
/**
* Compares previous and next module objects to check for mutated boundaries.
*
* This implementation is based on the one in [Metro](https://github.com/facebook/metro/blob/907d6af22ac6ebe58572be418e9253a90665ecbd/packages/metro/src/lib/polyfills/require.js#L776-L792).
* @param {*} prevExports The current Webpack module exports object.
* @param {*} nextExports The next Webpack module exports object.
* @returns {boolean} Whether the React refresh boundary should be invalidated.
*/
function shouldInvalidateReactRefreshBoundary(prevExports, nextExports) {
var prevSignature = getReactRefreshBoundarySignature(prevExports);
var nextSignature = getReactRefreshBoundarySignature(nextExports);
if (prevSignature.length !== nextSignature.length) {
return true;
}
for (var i = 0; i < nextSignature.length; i += 1) {
if (prevSignature[i] !== nextSignature[i]) {
return true;
}
}
return false;
}
var enqueueUpdate = createDebounceUpdate();
function executeRuntime(
moduleExports,
moduleId,
webpackHot,
refreshOverlay,
isTest,
) {
registerExportsForReactRefresh(moduleExports, moduleId);
if (webpackHot) {
var isHotUpdate = !!webpackHot.data;
var prevExports;
if (isHotUpdate) {
prevExports = webpackHot.data.prevExports;
}
if (isReactRefreshBoundary(moduleExports)) {
webpackHot.dispose(
/**
* A callback to performs a full refresh if React has unrecoverable errors,
* and also caches the to-be-disposed module.
* @param {*} data A hot module data object from Webpack HMR.
* @returns {void}
*/
function hotDisposeCallback(data) {
// We have to mutate the data object to get data registered and cached
data.prevExports = moduleExports;
},
);
webpackHot.accept(
/**
* An error handler to allow self-recovering behaviours.
* @param {Error} error An error occurred during evaluation of a module.
* @returns {void}
*/
function hotErrorHandler(error) {
console.error(error);
if (
__reload_on_runtime_errors__ &&
isUnrecoverableRuntimeError(error)
) {
location.reload();
return;
}
if (typeof refreshOverlay !== 'undefined' && refreshOverlay) {
refreshOverlay.handleRuntimeError(error);
}
if (typeof isTest !== 'undefined' && isTest) {
if (window.onHotAcceptError) {
window.onHotAcceptError(error.message);
}
}
__webpack_require__.c[moduleId].hot.accept(hotErrorHandler);
},
);
if (isHotUpdate) {
if (
isReactRefreshBoundary(prevExports) &&
shouldInvalidateReactRefreshBoundary(prevExports, moduleExports)
) {
webpackHot.invalidate();
} else {
enqueueUpdate(
/**
* A function to dismiss the error overlay after performing React refresh.
* @returns {void}
*/
function updateCallback() {
if (typeof refreshOverlay !== 'undefined' && refreshOverlay) {
refreshOverlay.clearRuntimeErrors();
}
},
);
}
}
} else {
if (isHotUpdate && typeof prevExports !== 'undefined') {
webpackHot.invalidate();
}
}
}
}
function isUnrecoverableRuntimeError(error) {
return error.message.startsWith('RuntimeError: factory is undefined');
}
module.exports = Object.freeze({
enqueueUpdate: enqueueUpdate,
executeRuntime: executeRuntime,
getModuleExports: getModuleExports,
isReactRefreshBoundary: isReactRefreshBoundary,
shouldInvalidateReactRefreshBoundary: shouldInvalidateReactRefreshBoundary,
registerExportsForReactRefresh: registerExportsForReactRefresh,
});
@@ -0,0 +1,300 @@
/* eslint-disable */
// @ts-nocheck
/**
* The following code is modified based on mahdyar/ansi-html-community
* Added support for 24-bit RGB colors.
*/
'use strict';
module.exports = ansiHTML;
// Reference to https://github.com/sindresorhus/ansi-regex
var _regANSI =
/(?:(?:\u001b\[)|\u009b)(?:(?:[0-9]{1,3})?(?:(?:;[0-9]{0,3})*)?[A-M|f-m])|\u001b[A-M]/;
var _defColors = {
reset: ['fff', '000'], // [FOREGROUND_COLOR, BACKGROUND_COLOR]
black: '000',
red: 'ff0000',
green: '209805',
yellow: 'e8bf03',
blue: '0000ff',
magenta: 'ff00ff',
cyan: '00ffee',
lightgrey: 'f0f0f0',
darkgrey: '888',
};
var _styles = {
30: 'black',
31: 'red',
32: 'green',
33: 'yellow',
34: 'blue',
35: 'magenta',
36: 'cyan',
37: 'lightgrey',
};
var _colorMode = {
2: 'rgb',
};
var _openTags = {
1: 'font-weight:bold', // bold
2: 'opacity:0.5', // dim
3: '<i>', // italic
4: '<u>', // underscore
8: 'display:none', // hidden
9: '<del>', // delete
38: function (match) {
// color
var mode = _colorMode[match[0]];
if (mode === 'rgb') {
var r, g, b;
r = match[1];
g = match[2];
b = match[3];
match.advance(4);
return 'color: rgb(' + r + ',' + g + ',' + b + ')';
}
},
48: function (match) {
// background color
var mode = _colorMode[match[0]];
if (mode === 'rgb') {
var r, g, b;
r = match[1];
g = match[2];
b = match[3];
match.advance(4);
return 'background-color: rgb(' + r + ',' + g + ',' + b + ')';
}
},
};
var _openTagToCloseTag = {
3: '23',
4: '24',
9: '29',
};
var _closeTags = {
0: function (ansiCodes) {
if (!ansiCodes) return '</span>';
if (!ansiCodes.length) return '';
var code,
ret = '';
while ((code = ansiCodes.pop())) {
var closeTag = _openTagToCloseTag[code];
if (closeTag) {
ret += _closeTags[closeTag];
continue;
}
ret += '</span>';
}
return ret;
},
23: '</i>', // reset italic
24: '</u>', // reset underscore
29: '</del>', // reset delete
};
[21, 22, 27, 28, 39, 49].forEach(function (n) {
_closeTags[n] = '</span>';
});
/**
* Normalize ';<seq>' | '<seq>' -> '<seq>'
* @param {string | null} seq
* @returns {null | string}
*/
function normalizeSeq(seq) {
if (seq === null || seq === undefined) return null;
if (seq.startsWith(';')) {
return seq.slice(1);
}
return seq;
}
/**
* Converts text with ANSI color codes to HTML markup.
* @param {String} text
* @returns {*}
*/
function ansiHTML(text) {
// Returns the text if the string has no ANSI escape code.
if (!_regANSI.test(text)) {
return text;
}
// Cache opened sequence.
var ansiCodes = [];
// Replace with markup.
var ret = text.replace(
/\033\[(?:[0-9]{1,3})?(?:(?:;[0-9]{0,3})*)?m/g,
function (m) {
var match = m.match(/(;?\d+)/g).map(normalizeSeq);
Object.defineProperty(match, 'advance', {
value: function (count) {
this.splice(0, count);
},
});
var seq,
rep = '';
while ((seq = match[0])) {
match.advance(1);
rep += applySeq(seq);
}
return rep;
function applySeq(seq) {
var other = _openTags[seq];
if (
other &&
(other = typeof other === 'function' ? other(match) : other)
) {
// If reset signal is encountered, we have to reset everything.
var ret = '';
if (seq === '0') {
ret += _closeTags[seq](ansiCodes);
}
// If current sequence has been opened, close it.
if (!!~ansiCodes.indexOf(seq)) {
// eslint-disable-line no-extra-boolean-cast
ansiCodes.pop();
return '</span>';
}
// Open tag.
ansiCodes.push(seq);
return (
ret + (other[0] === '<' ? other : '<span style="' + other + ';">')
);
}
var ct = _closeTags[seq];
if (typeof ct === 'function') {
return ct(ansiCodes);
} else if (ct) {
// Pop sequence
ansiCodes.pop();
return ct;
}
return '';
}
},
);
// Make sure tags are closed.
var l = ansiCodes.length;
l > 0 && (ret += Array(l + 1).join('</span>'));
return ret;
}
/**
* Customize colors.
* @param {Object} colors reference to _defColors
*/
ansiHTML.setColors = function (colors) {
if (typeof colors !== 'object') {
throw new Error('`colors` parameter must be an Object.');
}
var _finalColors = {};
for (var key in _defColors) {
var hex = colors.hasOwnProperty(key) ? colors[key] : null;
if (!hex) {
_finalColors[key] = _defColors[key];
continue;
}
if ('reset' === key) {
if (typeof hex === 'string') {
hex = [hex];
}
if (
!Array.isArray(hex) ||
hex.length === 0 ||
hex.some(function (h) {
return typeof h !== 'string';
})
) {
throw new Error(
'The value of `' +
key +
'` property must be an Array and each item could only be a hex string, e.g.: FF0000',
);
}
var defHexColor = _defColors[key];
if (!hex[0]) {
hex[0] = defHexColor[0];
}
if (hex.length === 1 || !hex[1]) {
hex = [hex[0]];
hex.push(defHexColor[1]);
}
hex = hex.slice(0, 2);
} else if (typeof hex !== 'string') {
throw new Error(
'The value of `' +
key +
'` property must be a hex string, e.g.: FF0000',
);
}
_finalColors[key] = hex;
}
_setTags(_finalColors);
};
/**
* Reset colors.
*/
ansiHTML.reset = function () {
_setTags(_defColors);
};
/**
* Expose tags, including open and close.
* @type {Object}
*/
ansiHTML.tags = {};
if (Object.defineProperty) {
Object.defineProperty(ansiHTML.tags, 'open', {
get: function () {
return _openTags;
},
});
Object.defineProperty(ansiHTML.tags, 'close', {
get: function () {
return _closeTags;
},
});
} else {
ansiHTML.tags.open = _openTags;
ansiHTML.tags.close = _closeTags;
}
function _setTags(colors) {
// reset all
_openTags['0'] =
'font-weight:normal;opacity:1;color:#' +
colors.reset[0] +
';background:#' +
colors.reset[1];
// inverse
_openTags['7'] =
'color:#' + colors.reset[1] + ';background:#' + colors.reset[0];
// dark grey
_openTags['90'] = 'color:#' + colors.darkgrey;
for (var code in _styles) {
var color = _styles[code];
var oriColor = colors[color] || '000';
_openTags[code] = 'color:#' + oriColor;
code = parseInt(code);
_openTags[(code + 10).toString()] = 'background:#' + oriColor;
}
}
ansiHTML.reset();
@@ -0,0 +1,102 @@
/**
* @callback EventCallback
* @param {string | Error | null} context
* @returns {void}
*/
/**
* @callback EventHandler
* @param {Event} event
* @returns {void}
*/
/**
* A function that creates an event handler for the `error` event.
* @param {EventCallback} callback A function called to handle the error context.
* @returns {EventHandler} A handler for the `error` event.
*/
function createErrorHandler(callback) {
return function errorHandler(event) {
if (!event || !event.error) {
return callback(null);
}
if (event.error instanceof Error) {
return callback(event.error);
}
// A non-error was thrown, we don't have a trace. :(
// Look in your browser's devtools for more information
return callback(new Error(event.error));
};
}
/**
* A function that creates an event handler for the `unhandledrejection` event.
* @param {EventCallback} callback A function called to handle the error context.
* @returns {EventHandler} A handler for the `unhandledrejection` event.
*/
function createRejectionHandler(callback) {
return function rejectionHandler(event) {
if (!event || !event.reason) {
return callback(new Error('Unknown'));
}
if (event.reason instanceof Error) {
return callback(event.reason);
}
// A non-error was rejected, we don't have a trace :(
// Look in your browser's devtools for more information
return callback(new Error(event.reason));
};
}
/**
* Creates a handler that registers an EventListener on window for a valid type
* and calls a callback when the event fires.
* @param {string} eventType A valid DOM event type.
* @param {function(EventCallback): EventHandler} createHandler A function that creates an event handler.
* @returns {register} A function that registers the EventListener given a callback.
*/
function createWindowEventHandler(eventType, createHandler) {
/**
* @type {EventHandler | null} A cached event handler function.
*/
let eventHandler = null;
/**
* Unregisters an EventListener if it has been registered.
* @returns {void}
*/
function unregister() {
if (eventHandler === null) {
return;
}
window.removeEventListener(eventType, eventHandler);
eventHandler = null;
}
/**
* Registers an EventListener if it hasn't been registered.
* @param {EventCallback} callback A function called after the event handler to handle its context.
* @returns {unregister | void} A function to unregister the registered EventListener if registration is performed.
*/
function register(callback) {
if (eventHandler !== null) {
return;
}
eventHandler = createHandler(callback);
window.addEventListener(eventType, eventHandler);
return unregister;
}
return register;
}
const handleError = createWindowEventHandler('error', createErrorHandler);
const handleUnhandledRejection = createWindowEventHandler(
'unhandledrejection',
createRejectionHandler,
);
module.exports = {
handleError: handleError,
handleUnhandledRejection: handleUnhandledRejection,
};
@@ -0,0 +1,106 @@
/**
* @typedef {Object} WebpackErrorObj
* @property {string} moduleIdentifier
* @property {string} moduleName
* @property {string} message
*/
const friendlySyntaxErrorLabel = 'Syntax error:';
/**
* Checks if the error message is for a syntax error.
* @param {string} message The raw Webpack error message.
* @returns {boolean} Whether the error message is for a syntax error.
*/
function isLikelyASyntaxError(message) {
return message.indexOf(friendlySyntaxErrorLabel) !== -1;
}
/**
* Cleans up Webpack error messages.
*
* This implementation is based on the one from [create-react-app](https://github.com/facebook/create-react-app/blob/edc671eeea6b7d26ac3f1eb2050e50f75cf9ad5d/packages/react-dev-utils/formatWebpackMessages.js).
* @param {string} message The raw Webpack error message.
* @returns {string} The formatted Webpack error message.
*/
function formatMessage(message) {
let lines = message.split('\n');
// Strip Webpack-added headers off errors/warnings
// https://github.com/webpack/webpack/blob/master/lib/ModuleError.js
lines = lines.filter(function (line) {
return !/Module [A-z ]+\(from/.test(line);
});
// Remove leading newline
if (lines.length > 2 && lines[1].trim() === '') {
lines.splice(1, 1);
}
// Remove duplicated newlines
lines = lines.filter(function (line, index, arr) {
return (
index === 0 || line.trim() !== '' || line.trim() !== arr[index - 1].trim()
);
});
// Clean up the file name
lines[0] = lines[0].replace(/^(.*) \d+:\d+-\d+$/, '$1');
// Cleans up verbose "module not found" messages for files and packages.
if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {
lines = [
lines[0],
lines[1]
.replace('Error: ', '')
.replace('Module not found: Cannot find file:', 'Cannot find file:'),
];
}
message = lines.join('\n');
// Clean up syntax errors
message = message.replace('SyntaxError:', friendlySyntaxErrorLabel);
// Internal stacks are generally useless, so we strip them -
// except the stacks containing `webpack:`,
// because they're normally from user code generated by webpack.
message = message.replace(
/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm,
'',
); // at ... ...:x:y
message = message.replace(
/^\s*at\s((?!webpack:).)*<anonymous>[\s)]*(\n|$)/gm,
'',
); // at ... <anonymous>
message = message.replace(/^\s*at\s<anonymous>(\n|$)/gm, ''); // at <anonymous>
return message.trim();
}
/**
* Formats Webpack error messages into a more readable format.
* @param {Array<string | WebpackErrorObj>} errors An array of Webpack error messages.
* @returns {string[]} The formatted Webpack error messages.
*/
function formatWebpackErrors(errors) {
let formattedErrors = errors.map(function (errorObjOrMessage) {
// Webpack 5 compilation errors are in the form of descriptor objects,
// so we have to join pieces to get the format we want.
if (typeof errorObjOrMessage === 'object') {
return formatMessage(
[errorObjOrMessage.moduleName, errorObjOrMessage.message].join('\n'),
);
}
// Webpack 4 compilation errors are strings
return formatMessage(errorObjOrMessage);
});
if (formattedErrors.some(isLikelyASyntaxError)) {
// If there are any syntax errors, show just them.
formattedErrors = formattedErrors.filter(isLikelyASyntaxError);
}
return formattedErrors;
}
module.exports = formatWebpackErrors;
@@ -0,0 +1,23 @@
function runWithRetry(callback, maxRetries) {
function executeWithRetryAndTimeout(currentCount) {
try {
if (currentCount > maxRetries - 1) {
console.warn('[React Refresh] Failed to set up the socket connection.');
return;
}
callback();
} catch (err) {
setTimeout(
function () {
executeWithRetryAndTimeout(currentCount + 1);
},
Math.pow(10, currentCount),
);
}
}
executeWithRetryAndTimeout(0);
}
module.exports = runWithRetry;