feat: use handlebar to build up webhook body (#351)

This commit is contained in:
Warren 2024-03-27 15:52:02 -07:00 committed by GitHub
parent 4a85e22a3e
commit 5fc7c21c6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 101 additions and 291 deletions

View file

@ -0,0 +1,5 @@
---
'@hyperdx/api': patch
---
feat: use handlebar to build up webhook body

View file

@ -74,7 +74,7 @@
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.46.1",
"@typescript-eslint/parser": "^5.46.1",
"eslint": "^8.48.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-n": "^16.4.0",
"eslint-plugin-prettier": "^4.2.1",

View file

@ -29,7 +29,7 @@ export interface IWebhook {
// to strip the additional properties that are related to the Mongoose internal representation -> webhook.headers.toJSON()
queryParams?: MongooseMap;
headers?: MongooseMap;
body?: MongooseMap;
body?: string;
}
const WebhookSchema = new Schema<IWebhook>(
@ -63,8 +63,7 @@ const WebhookSchema = new Schema<IWebhook>(
required: false,
},
body: {
type: Map,
of: String,
type: String,
required: false,
},
},

View file

@ -23,10 +23,8 @@ import {
buildAlertMessageTemplateTitle,
buildLogSearchLink,
doesExceedThreshold,
escapeJsonValues,
expandToNestedObject,
getDefaultExternalAction,
injectIntoPlaceholders,
processAlert,
renderAlertTemplate,
roundDownToXMinutes,
@ -61,61 +59,6 @@ describe('checkAlerts', () => {
).toBe('2023-03-17T22:55:00.000Z');
});
describe('injectIntoPlaceholders', () => {
const message = {
hdxLink: 'https://www.example.com/random-testing-url1234',
title: 'Alert for "All Events" - 776 lines found',
body: '145 lines found, expected less than 1 lines',
};
const valuesToInject = {
$HDX_ALERT_URL: message.hdxLink,
$HDX_ALERT_TITLE: message.title,
$HDX_ALERT_BODY: message.body,
};
it('should correctly inject message values into placeholders', () => {
const placeholderString =
'{"text":"$HDX_ALERT_URL | $HDX_ALERT_TITLE | $HDX_ALERT_BODY"}';
const result = injectIntoPlaceholders(placeholderString, valuesToInject);
const expectedObj = {
text: `${message.hdxLink} | ${message.title} | ${message.body}`,
};
const expected = JSON.stringify(expectedObj);
expect(result).toEqual(expected);
});
it('should retain invalid placeholders if no matching valid key', () => {
const placeholderString =
'{"text":"$HDX_ALERT_LINK | $HDX_ALERT_TITLE | $HDX_ALERT_BODY"}';
const result = injectIntoPlaceholders(placeholderString, valuesToInject);
const expectedObj = {
text: `$HDX_ALERT_LINK | ${message.title} | ${message.body}`,
};
const expected = JSON.stringify(expectedObj);
expect(result).toEqual(expected);
});
it('should escape JSON values correctly', () => {
const placeholderString = 'escapetest: $HDX_ALERT_BODY';
const valuesToInject = {
$HDX_ALERT_BODY: '{"key":"value\nnew line"}',
};
const expected = 'escapetest: {\\"key\\":\\"value\\nnew line\\"}';
const result = injectIntoPlaceholders(placeholderString, valuesToInject);
expect(result).toEqual(expected);
});
});
describe('escapeJsonValues', () => {
it('should escape special JSON characters', () => {
const input = '"Simple\nEscapeJson"\tTest\\';
const expected = '\\"Simple\\nEscapeJson\\"\\tTest\\\\';
const result = escapeJsonValues(input);
expect(result).toEqual(expected);
});
});
it('buildLogSearchLink', () => {
expect(
buildLogSearchLink({
@ -632,8 +575,7 @@ describe('checkAlerts', () => {
});
expect(slack.postMessageToWebhook).toHaveBeenCalledTimes(2);
expect(slack.postMessageToWebhook).toHaveBeenNthCalledWith(
1,
expect(slack.postMessageToWebhook).toHaveBeenCalledWith(
'https://hooks.slack.com/services/123',
{
text: 'Alert for "My Search" - 10 lines found',
@ -662,8 +604,7 @@ describe('checkAlerts', () => {
],
},
);
expect(slack.postMessageToWebhook).toHaveBeenNthCalledWith(
2,
expect(slack.postMessageToWebhook).toHaveBeenCalledWith(
'https://hooks.slack.com/services/456',
{
text: 'Alert for "My Search" - 10 lines found',
@ -1284,7 +1225,9 @@ describe('checkAlerts', () => {
url: 'https://webhook.site/123',
name: 'Generic Webhook',
description: 'generic webhook description',
body: { text: '$HDX_ALERT_URL | $HDX_ALERT_TITLE' },
body: JSON.stringify({
text: '{{link}} | {{title}}',
}),
headers: {
'Content-Type': 'application/json',
'X-HyperDX-Signature': 'XXXXX-XXXXX',
@ -1349,19 +1292,14 @@ describe('checkAlerts', () => {
windowSizeInMins: 5,
});
// check if generic webhook was triggered, injected, and parsed, and sent correctly
expect(fetchMock).toHaveBeenCalledWith(
'https://webhook.site/123',
expect.objectContaining({
method: 'POST',
body: JSON.stringify({
text: `http://localhost:9090/search/${logView._id}?from=1700172600000&to=1700172900000&q=level%3Aerror+span_name%3A%22HyperDX%22 | Alert for "My Log View" - 11 lines found`,
}),
headers: {
'Content-Type': 'application/json',
'X-HyperDX-Signature': 'XXXXX-XXXXX',
},
}),
);
expect(fetchMock).toHaveBeenNthCalledWith(1, 'https://webhook.site/123', {
method: 'POST',
body: `{"text":"http://localhost:9090/search/${logView.id}?from=1700172600000&to=1700172900000&q=level%3Aerror+span_name%3A%22HyperDX%22 | Alert for "My Log View" - 11 lines found"}`,
headers: {
'Content-Type': 'application/json',
'X-HyperDX-Signature': 'XXXXX-XXXXX',
},
});
});
it('CHART alert (logs table series) - generic webhook', async () => {
@ -1405,7 +1343,9 @@ describe('checkAlerts', () => {
url: 'https://webhook.site/123',
name: 'Generic Webhook',
description: 'generic webhook description',
body: { text: '$HDX_ALERT_URL | $HDX_ALERT_TITLE' },
body: JSON.stringify({
text: '{{link}} | {{title}}',
}),
headers: { 'Content-Type': 'application/json' },
}).save();
const dashboard = await new Dashboard({
@ -1508,18 +1448,13 @@ describe('checkAlerts', () => {
expect(history2.createdAt).toEqual(new Date('2023-11-16T22:15:00.000Z'));
// check if generic webhook was triggered, injected, and parsed, and sent correctly
expect(fetchMock).toHaveBeenCalledWith(
'https://webhook.site/123',
expect.objectContaining({
method: 'POST',
body: JSON.stringify({
text: `http://localhost:9090/dashboards/${dashboard._id}?from=1700170200000&granularity=5+minute&to=1700174700000 | Alert for "Max Duration" in "My Dashboard" - 102 exceeds 10`,
}),
headers: {
'Content-Type': 'application/json',
},
}),
);
expect(fetchMock).toHaveBeenCalledWith('https://webhook.site/123', {
method: 'POST',
body: `{"text":"http://localhost:9090/dashboards/${dashboard.id}?from=1700170200000&granularity=5+minute&to=1700174700000 | Alert for "Max Duration" in "My Dashboard" - 102 exceeds 10"}`,
headers: {
'Content-Type': 'application/json',
},
});
});
it('CHART alert (metrics table series) - generic webhook', async () => {
@ -1637,7 +1572,9 @@ describe('checkAlerts', () => {
url: 'https://webhook.site/123',
name: 'Generic Webhook',
description: 'generic webhook description',
body: { text: '$HDX_ALERT_URL | $HDX_ALERT_TITLE' },
body: JSON.stringify({
text: '{{link}} | {{title}}',
}),
headers: { 'Content-Type': 'application/json' },
}).save();
const dashboard = await new Dashboard({
@ -1738,18 +1675,13 @@ describe('checkAlerts', () => {
);
// check if generic webhook was triggered, injected, and parsed, and sent correctly
expect(fetchMock).toHaveBeenCalledWith(
'https://webhook.site/123',
expect.objectContaining({
method: 'POST',
body: JSON.stringify({
text: `http://localhost:9090/dashboards/${dashboard._id}?from=1700170200000&granularity=5+minute&to=1700174700000 | Alert for "Redis Memory" in "My Dashboard" - 395.3421052631579 exceeds 10`,
}),
headers: {
'Content-Type': 'application/json',
},
}),
);
expect(fetchMock).toHaveBeenNthCalledWith(1, 'https://webhook.site/123', {
method: 'POST',
body: `{"text":"http://localhost:9090/dashboards/${dashboard.id}?from=1700170200000&granularity=5+minute&to=1700174700000 | Alert for "Redis Memory" in "My Dashboard" - 395.3421052631579 exceeds 10"}`,
headers: {
'Content-Type': 'application/json',
},
});
jest.resetAllMocks();
});

View file

@ -270,14 +270,16 @@ export const handleSendGenericWebhook = async (
// BODY
let parsedBody: Record<string, string | number | symbol> = {};
let body = '';
if (webhook.body) {
const injectedBody = injectIntoPlaceholders(JSON.stringify(webhook.body), {
$HDX_ALERT_URL: message.hdxLink,
$HDX_ALERT_TITLE: message.title,
$HDX_ALERT_BODY: message.body,
const handlebars = Handlebars.create();
body = handlebars.compile(webhook.body, {
noEscape: true,
})({
body: message.body,
link: message.hdxLink,
title: message.title,
});
parsedBody = JSON.parse(injectedBody);
}
try {
@ -285,7 +287,7 @@ export const handleSendGenericWebhook = async (
const response = await fetch(url, {
method: 'POST',
headers: headers as Record<string, string>,
body: JSON.stringify(parsedBody),
body,
});
if (!response.ok) {
@ -299,32 +301,6 @@ export const handleSendGenericWebhook = async (
}
};
type HDXGenericWebhookTemplateValues = {
$HDX_ALERT_URL?: string;
$HDX_ALERT_TITLE?: string;
$HDX_ALERT_BODY?: string;
};
export function injectIntoPlaceholders(
placeholderString: string,
valuesToInject: HDXGenericWebhookTemplateValues,
) {
return placeholderString.replace(/(\$\w+)/g, function (match) {
const replacement =
valuesToInject[match as keyof HDXGenericWebhookTemplateValues] || match;
return escapeJsonValues(replacement);
});
}
export function escapeJsonValues(value: string): string {
return value
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t');
}
export const buildAlertMessageTemplateHdxLink = ({
alert,
dashboard,

View file

@ -115,7 +115,7 @@
"@types/react-virtualized-auto-sizer": "^1.0.1",
"@typescript-eslint/eslint-plugin": "^5.52.0",
"@typescript-eslint/parser": "^5.52.0",
"eslint": "^8.34.0",
"eslint": "^8.57.0",
"eslint-config-next": "13",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-prettier": "^4.2.1",

View file

@ -159,11 +159,6 @@ export default function TeamPage() {
return;
}
if (body && !isValidJson(body)) {
toast.error('Please enter valid JSON for body');
return;
}
saveWebhook.mutate(
{
name,
@ -171,7 +166,7 @@ export default function TeamPage() {
url,
description,
headers: headers ? JSON.parse(headers) : undefined,
body: body ? JSON.parse(body) : undefined,
body,
},
{
onSuccess: () => {
@ -597,9 +592,7 @@ export default function TeamPage() {
height="100px"
extensions={[
json(),
placeholder(
'{\n\t"text": "$HDX_ALERT_URL | $HDX_ALERT_TITLE | $HDX_ALERT_BODY",\n}',
),
placeholder('{\n\t"text": "{{body}}"\n}'),
]}
theme={hdxJSONTheme}
onChange={onBodyChange}
@ -619,8 +612,17 @@ export default function TeamPage() {
</span>
<br />
<span>
<code>$HDX_ALERT_URL</code>, <code>$HDX_ALERT_TITLE</code>
, <code>$HDX_ALERT_BODY</code>
<code>
{'{{'}link{'}}'}
</code>
,{' '}
<code>
{'{{'}title{'}}'}
</code>
,{' '}
<code>
{'{{'}body{'}}'}
</code>
</span>
</Alert>
<Button

View file

@ -726,7 +726,7 @@ const api = {
description?: string;
queryParams?: Map<string, string>;
headers?: Map<string, string>;
body?: Map<string, string>;
body?: string;
}
>(async ({ service, url, name, description, queryParams, headers, body }) =>
server(`webhooks`, {

176
yarn.lock
View file

@ -1576,25 +1576,10 @@
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005"
integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==
"@eslint/eslintrc@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.4.1.tgz#af58772019a2d271b7e2d4c23ff4ddcba3ccfb3e"
integrity sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
espree "^9.4.0"
globals "^13.19.0"
ignore "^5.2.0"
import-fresh "^3.2.1"
js-yaml "^4.1.0"
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/eslintrc@^2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396"
integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==
"@eslint/eslintrc@^2.1.4":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
dependencies:
ajv "^6.12.4"
debug "^4.3.2"
@ -1606,10 +1591,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@8.48.0":
version "8.48.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb"
integrity sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==
"@eslint/js@8.57.0":
version "8.57.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f"
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
"@floating-ui/core@^1.2.3":
version "1.2.3"
@ -1756,22 +1741,13 @@
dependencies:
client-only "^0.0.1"
"@humanwhocodes/config-array@^0.11.10":
version "0.11.11"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844"
integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
minimatch "^3.0.5"
"@humanwhocodes/config-array@^0.11.8":
version "0.11.8"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
"@humanwhocodes/object-schema" "^2.0.2"
debug "^4.3.1"
minimatch "^3.0.5"
"@humanwhocodes/module-importer@^1.0.1":
@ -1779,10 +1755,10 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
"@humanwhocodes/object-schema@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@humanwhocodes/object-schema@^2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917"
integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==
"@hyperdx/browser@^0.20.0":
version "0.20.0"
@ -4755,6 +4731,11 @@
"@uiw/codemirror-extensions-basic-setup" "4.21.24"
codemirror "^6.0.0"
"@ungap/structured-clone@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406"
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
"@xobotyi/scrollbar-width@^1.9.5":
version "1.9.5"
resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d"
@ -4856,7 +4837,7 @@ acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.0.0, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.8.0:
acorn@^8.0.0, acorn@^8.2.4, acorn@^8.4.1:
version "8.8.2"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
@ -4893,7 +4874,7 @@ aggregate-error@^3.0.0:
clean-stack "^2.0.0"
indent-string "^4.0.0"
ajv@^6.10.0, ajv@^6.12.4:
ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@ -7123,14 +7104,6 @@ eslint-scope@^5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
eslint-scope@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-scope@^7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
@ -7161,63 +7134,19 @@ eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
eslint@^8.34.0:
version "8.34.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.34.0.tgz#fe0ab0ef478104c1f9ebc5537e303d25a8fb22d6"
integrity sha512-1Z8iFsucw+7kSqXNZVslXS8Ioa4u2KM7GPwuKtkTFAqZ/cHMcEaR+1+Br0wLlot49cNxIiZk5wp8EAbPcYZxTg==
dependencies:
"@eslint/eslintrc" "^1.4.1"
"@humanwhocodes/config-array" "^0.11.8"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.3.2"
doctrine "^3.0.0"
escape-string-regexp "^4.0.0"
eslint-scope "^7.1.1"
eslint-utils "^3.0.0"
eslint-visitor-keys "^3.3.0"
espree "^9.4.0"
esquery "^1.4.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
find-up "^5.0.0"
glob-parent "^6.0.2"
globals "^13.19.0"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
is-path-inside "^3.0.3"
js-sdsl "^4.1.4"
js-yaml "^4.1.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
lodash.merge "^4.6.2"
minimatch "^3.1.2"
natural-compare "^1.4.0"
optionator "^0.9.1"
regexpp "^3.2.0"
strip-ansi "^6.0.1"
strip-json-comments "^3.1.0"
text-table "^0.2.0"
eslint@^8.48.0:
version "8.48.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.48.0.tgz#bf9998ba520063907ba7bfe4c480dc8be03c2155"
integrity sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==
eslint@^8.57.0:
version "8.57.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668"
integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.6.1"
"@eslint/eslintrc" "^2.1.2"
"@eslint/js" "8.48.0"
"@humanwhocodes/config-array" "^0.11.10"
"@eslint/eslintrc" "^2.1.4"
"@eslint/js" "8.57.0"
"@humanwhocodes/config-array" "^0.11.14"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
"@ungap/structured-clone" "^1.2.0"
ajv "^6.12.4"
chalk "^4.0.0"
cross-spawn "^7.0.2"
@ -7249,15 +7178,6 @@ eslint@^8.48.0:
strip-ansi "^6.0.1"
text-table "^0.2.0"
espree@^9.4.0:
version "9.4.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd"
integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==
dependencies:
acorn "^8.8.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.3.0"
espree@^9.6.0, espree@^9.6.1:
version "9.6.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
@ -7272,13 +7192,6 @@ esprima@^4.0.0, esprima@^4.0.1:
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esquery@^1.4.0:
version "1.4.2"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.2.tgz#c6d3fee05dd665808e2ad870631f221f5617b1d1"
integrity sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==
dependencies:
estraverse "^5.1.0"
esquery@^1.4.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
@ -8475,7 +8388,7 @@ immutable@^4.0.0:
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.2.4.tgz#83260d50889526b4b531a5e293709a77f7c55a2a"
integrity sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==
import-fresh@^3.0.0, import-fresh@^3.2.1:
import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
@ -9461,11 +9374,6 @@ js-cookie@^2.2.1:
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
js-sdsl@^4.1.4:
version "4.3.0"
resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711"
integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==
js-sha3@0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
@ -11365,18 +11273,6 @@ optionator@^0.8.1:
type-check "~0.3.2"
word-wrap "~1.2.3"
optionator@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
dependencies:
deep-is "^0.1.3"
fast-levenshtein "^2.0.6"
levn "^0.4.1"
prelude-ls "^1.2.1"
type-check "^0.4.0"
word-wrap "^1.2.3"
optionator@^0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64"
@ -13574,7 +13470,7 @@ strip-indent@^3.0.0:
dependencies:
min-indent "^1.0.0"
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
@ -14770,7 +14666,7 @@ winston@^3.9.0:
triple-beam "^1.3.0"
winston-transport "^4.5.0"
word-wrap@^1.2.3, word-wrap@~1.2.3:
word-wrap@~1.2.3:
version "1.2.5"
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==