243 examples

Memory leak

Unused memory accumulates without proper release.

[ FAQ1 ]

What is a memory leak?

A memory leak happens when allocated memory remains occupied indefinitely due to improper memory management, preventing the memory from being reused by the program. In languages like C or C++, this typically results from forgetting to explicitly free allocated heap memory. In languages with automatic garbage collection, like Java or JavaScript, memory leaks occur when lingering references (retain cycles) prevent objects from being garbage-collected. Over time, these leaks accumulate, gradually consuming available memory, reducing performance, and potentially causing application crashes or system instability.
[ FAQ2 ]

How to fix a memory leak

To fix memory leaks, first identify leaks using profiling tools such as Valgrind, Instruments, or built-in developer tools provided by your runtime environment. In manual memory management languages (e.g., C or C++), ensure all allocated heap memory is explicitly freed when no longer needed. For garbage-collected languages, break retain cycles by properly nullifying or removing object references to allow automatic garbage collection to reclaim unused memory. Additionally, follow good programming practices, such as using smart pointers in C++ or minimizing unnecessary object creation in Java, to proactively prevent leaks. Regularly profiling your application helps detect leaks early, preserving performance and system stability.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared at module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Cache is stored in module-level variables - could lead to memory leaks in long-running processes since it's never cleared
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
}
Greptile
greptile
logic: potential memory leak - missing cleanup function to remove click event listener
suggested fix
+ const handleClick = () => {
+ setShowSurvey(!showSurvey)
+ }
+ addEventListener(widget, 'click', handleClick)
+ widget?.setAttribute('PHWidgetSurveyClickListener', 'true')
+ return () => {
+ widget?.removeEventListener('click', handleClick)
+ }
+ }
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
+import { useMemoizedFn } from 'ahooks';
+import { useBusterAssetsContextSelector } from '../../Assets/BusterAssetsProvider';
+import { IBusterMetric } from '../interfaces';
+import { useBusterWebSocket } from '../../BusterWebSocket';
+import { BusterMetric } from '@/api/asset_interfaces';
+import { RustApiError } from '@/api/buster_rest/errors';
+import { resolveEmptyMetric } from '../helpers';
+import React from 'react';
+
+export const useMetricSubscribe = ({
+ metricsRef,
+ onInitializeMetric,
+ setMetrics
+}: {
+ metricsRef: React.MutableRefObject<Record<string, IBusterMetric>>;
+ onInitializeMetric: (metric: BusterMetric) => void;
+ setMetrics: (newMetrics: Record<string, IBusterMetric>) => void;
+}) => {
+ const busterSocket = useBusterWebSocket();
+ const getAssetPassword = useBusterAssetsContextSelector((state) => state.getAssetPassword);
+ const setAssetPasswordError = useBusterAssetsContextSelector(
+ (state) => state.setAssetPasswordError
+ );
+
+ const _onGetMetricState = useMemoizedFn((metric: BusterMetric) => {
+ onInitializeMetric(metric);
+ });
+
+ const _onGetMetricStateError = useMemoizedFn((_error: any, metricId: string) => {
+ const error = _error as RustApiError;
+ setAssetPasswordError(metricId, error.message || 'An error occurred');
+ });
+
+ const _setLoadingMetric = useMemoizedFn((metricId: string) => {
+ const metrics = metricsRef.current || {};
+ metrics[metricId] = resolveEmptyMetric(
+ {
+ ...metrics[metricId],
+ fetching: true
+ },
+ metricId
+ );
+
+ setMetrics(metrics);
+
+ return metrics[metricId];
+ });
+
+ const subscribeToMetric = useMemoizedFn(async ({ metricId }: { metricId: string }) => {
+ const { password } = getAssetPassword(metricId);
+ const foundMetric: undefined | IBusterMetric = metricsRef.current[metricId];
+
+ if (foundMetric && (foundMetric?.fetching || foundMetric?.fetched)) {
+ return foundMetric;
+ }
+
+ _setLoadingMetric(metricId);
+
+ return await busterSocket.emitAndOnce({
+ emitEvent: {
+ route: '/metrics/get',
+ payload: {
+ id: metricId,
+ password
+ }
+ },
+ responseEvent: {
+ route: '/metrics/get:updateMetricState',
+ callback: _onGetMetricState,
+ onError: (error) => _onGetMetricStateError(error, metricId)
+ }
+ });
+ });
+
+ const unsubscribeToMetricEvents = useMemoizedFn(({ metricId }: { metricId: string }) => {
+ busterSocket.off({
+ route: '/metrics/get:updateMetricState',
+ callback: onInitializeMetric
+ });
+ busterSocket.off({
+ route: '/metrics/update:updateMetricState',
+ callback: onInitializeMetric
+ });
+ });
Greptile
greptile
logic: Unsubscribe is using onInitializeMetric for both routes but _onGetMetricState was used for subscription. This mismatch could cause memory leaks.
suggested fix
const unsubscribeToMetricEvents = useMemoizedFn(({ metricId }: { metricId: string }) => {
busterSocket.off({
route: '/metrics/get:updateMetricState',
+ callback: _onGetMetricState
});
busterSocket.off({
route: '/metrics/update:updateMetricState',
+ callback: _onGetMetricState
});
});
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: The eslintCache is populated with null values but never cleaned up, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
style: Potential memory leak - eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
Greptile
greptile
logic: Memory leak potential - changedFiles array is spread twice unnecessarily. Use await listChangedFiles() directly.
suggested fix
+ changedFiles = await listChangedFiles();
changedFiles.forEach(file => {
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Cache is stored in module-level variables which persist between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely without cleanup mechanism
diff block
+#
+# This is a picoweb example showing a Server Side Events (SSE) aka
+# EventSource handling. Each connecting client gets its own events,
+# independent from other connected clients.
+#
+import uasyncio
+import picoweb
+
+
+def index(req, resp):
+ yield from picoweb.start_response(resp)
+ yield from resp.awrite("""\
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+var source = new EventSource("events");
+source.onmessage = function(event) {
+ document.getElementById("result").innerHTML += event.data + "<br>";
+}
+source.onerror = function(error) {
+ console.log(error);
+ document.getElementById("result").innerHTML += "EventSource error:" + error + "<br>";
+}
+</script>
+</head>
+<body>
+<div id="result"></div>
+</body>
+</html>
+""")
+
+def events(req, resp):
+ print("Event source connected")
+ yield from resp.awrite("HTTP/1.0 200 OK\r\n")
+ yield from resp.awrite("Content-Type: text/event-stream\r\n")
+ yield from resp.awrite("\r\n")
+ i = 0
+ try:
+ while True:
+ yield from resp.awrite("data: %d\n\n" % i)
+ yield from uasyncio.sleep(1)
+ i += 1
Greptile
greptile
logic: Potential memory leak - counter 'i' grows indefinitely. Consider implementing a maximum value or reset mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
style: The eslintCache is initialized but never cleared between runs. Consider adding a mechanism to reset or limit the cache size to prevent memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is not cleared between runs, which could lead to memory leaks in long-running processes
diff block
return true;
}
+float* gaussian_kernel(const int radius) {
+ int size = (radius*2)+1;
+ float norm = 1.f/(std::sqrt(2.f*M_PI)*radius);
+ float* gaussian_kernel = new float[size];
+ float coeff = -1.f/(2.f*radius*radius);
+
+ float sum = 0.f;
+ for (int i=0; i<size; i++) {
+ gaussian_kernel[i] = norm * exp(powl(i-radius,2)*coeff);
+ sum += gaussian_kernel[i];
+ }
+ for (int i=size; i--; gaussian_kernel[i] /= sum);
+ return gaussian_kernel;
+}
Greptile
greptile
style: gaussian_kernel function should be a private member of TGAImage to prevent memory leaks if called directly
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Cache is populated but never cleared, which could lead to memory leaks in long-running processes
diff block
+import { EventEmitter } from 'events';
+import { uIOhook, UiohookKeyboardEvent, UiohookMouseEvent, UiohookWheelEvent } from 'uiohook-napi';
+
+type KeyboardMouseEvent = {
+ keydown: (event: UiohookKeyboardEvent) => void;
+ input: (event: UiohookKeyboardEvent) => void;
+ keyup: (event: UiohookKeyboardEvent) => void;
+ click: (event: UiohookMouseEvent) => void;
+ wheel: (event: UiohookWheelEvent) => void;
+ mouseup: (event: UiohookMouseEvent) => void;
+ mousedown: (event: UiohookMouseEvent) => void;
+ mousemove: (event: UiohookMouseEvent) => void;
+}
+
+type EventNames = keyof KeyboardMouseEvent;
+
+export default class KeyboardMouse extends EventEmitter {
+ constructor() {
+ super();
+
+ uIOhook.on('keydown', (e: UiohookKeyboardEvent) => {
+ this.emit('keydown', e);
+ });
+
+ uIOhook.on('input', (e: UiohookKeyboardEvent) => {
+ this.emit('input', e);
+ });
+
+ uIOhook.on('keyup', (e: UiohookKeyboardEvent) => {
+ this.emit('keyup', e);
+ });
+
+ uIOhook.on('click', (e: UiohookMouseEvent) => {
+ this.emit('click', e);
+ });
+
+ uIOhook.on('wheel', (e: UiohookWheelEvent) => {
+ this.emit('wheel', e);
+ });
+
+ uIOhook.on('mouseup', (e: UiohookMouseEvent) => {
+ this.emit('mouseup', e);
+ });
+
+ uIOhook.on('mousedown', (e: UiohookMouseEvent) => {
+ this.emit('mousedown', e);
+ });
+ uIOhook.on('mousemove', (e: UiohookMouseEvent) => {
+ this.emit('mousemove', e);
+ });
+ }
Greptile
greptile
logic: Event listeners are attached in constructor but never removed. Need to implement cleanup in stop() or destructor to prevent memory leaks.
suggested fix
constructor() {
super();
+ this.handleKeydown = (e: UiohookKeyboardEvent) => this.emit('keydown', e);
+ this.handleInput = (e: UiohookKeyboardEvent) => this.emit('input', e);
+ this.handleKeyup = (e: UiohookKeyboardEvent) => this.emit('keyup', e);
+ this.handleClick = (e: UiohookMouseEvent) => this.emit('click', e);
+ this.handleWheel = (e: UiohookWheelEvent) => this.emit('wheel', e);
+ this.handleMouseup = (e: UiohookMouseEvent) => this.emit('mouseup', e);
+ this.handleMousedown = (e: UiohookMouseEvent) => this.emit('mousedown', e);
+ this.handleMousemove = (e: UiohookMouseEvent) => this.emit('mousemove', e);
+ uIOhook.on('keydown', this.handleKeydown);
+ uIOhook.on('input', this.handleInput);
+ uIOhook.on('keyup', this.handleKeyup);
+ uIOhook.on('click', this.handleClick);
+ uIOhook.on('wheel', this.handleWheel);
+ uIOhook.on('mouseup', this.handleMouseup);
+ uIOhook.on('mousedown', this.handleMousedown);
+ uIOhook.on('mousemove', this.handleMousemove);
}
diff block
onActorLoaded={(actor) =>
setTimeout(() => {
actor.setAnimation('wave')
- // Always start out facing right so that the data processing popover is more readable
- actor.direction = 'right'
+ // If the data processing popover is present, make the hedgehog face towards that bubble
+ // Otherwise, make it face left, which looks better in the side panel
+ actor.direction = dataProcessingAccepted ? 'left' : 'right'
}, 100)
}
Greptile
greptile
logic: setTimeout without cleanup could cause memory leaks if component unmounts before timeout completes. Consider using useEffect with cleanup.
suggested fix
+ onActorLoaded={(actor) => {
+ const timeoutId = setTimeout(() => {
+ actor.setAnimation('wave')
// If the data processing popover is present, make the hedgehog face towards that bubble
// Otherwise, make it face left, which looks better in the side panel
actor.direction = dataProcessingAccepted ? 'left' : 'right'
+ }, 100)
+ return () => clearTimeout(timeoutId)
+ }}
diff block
+import { AssistantStreamChunk } from "../../AssistantStream";
+import { ToolCallStreamController } from "../../modules/tool-call";
+import { AssistantTransformStream } from "../../utils/stream/AssistantTransformStream";
+import { PipeableTransformStream } from "../../utils/stream/PipeableTransformStream";
+import { DataStreamChunk, DataStreamStreamChunkType } from "./chunk-types";
+import { LineDecoderStream } from "../../utils/stream/LineDecoderStream";
+import {
+ DataStreamChunkDecoder,
+ DataStreamChunkEncoder,
+} from "./serialization";
+import {
+ AssistantMetaStreamChunk,
+ AssistantMetaTransformStream,
+} from "../../utils/stream/AssistantMetaTransformStream";
+
+export class DataStreamEncoder {
+ private _transformStream: PipeableTransformStream<
+ AssistantStreamChunk,
+ Uint8Array
+ >;
+
+ public get writable() {
+ return this._transformStream.writable;
+ }
+ public get readable() {
+ return this._transformStream.readable;
+ }
+
+ constructor() {
+ this._transformStream = new PipeableTransformStream<
+ AssistantStreamChunk,
+ Uint8Array
+ >((readable) => {
+ const transform = new TransformStream<
+ AssistantMetaStreamChunk,
+ DataStreamChunk
+ >({
+ transform(chunk, controller) {
+ const type = chunk.type;
+ switch (type) {
+ case "part": {
+ const part = chunk.part;
+ if (part.type === "tool-call") {
+ const { type, ...value } = part;
+ controller.enqueue({
+ type: DataStreamStreamChunkType.StartToolCall,
+ value,
+ });
+ }
+ if (part.type === "source") {
+ const { type, ...value } = part;
+ controller.enqueue({
+ type: DataStreamStreamChunkType.Source,
+ value,
+ });
+ }
+ break;
+ }
+ case "text-delta": {
+ const part = chunk.meta;
+ switch (part.type) {
+ case "text": {
+ controller.enqueue({
+ type: DataStreamStreamChunkType.TextDelta,
+ value: chunk.textDelta,
+ });
+ break;
+ }
+ case "reasoning": {
+ controller.enqueue({
+ type: DataStreamStreamChunkType.ReasoningDelta,
+ value: chunk.textDelta,
+ });
+ break;
+ }
+ case "tool-call": {
+ controller.enqueue({
+ type: DataStreamStreamChunkType.ToolCallDelta,
+ value: {
+ toolCallId: part.toolCallId,
+ argsTextDelta: chunk.textDelta,
+ },
+ });
+ break;
+ }
+ default:
+ throw new Error(
+ `Unsupported part type for text-delta: ${part.type}`,
+ );
+ }
+ break;
+ }
+ case "result": {
+ // Only tool-call parts can have results.
+ const part = chunk.meta;
+ if (part.type !== "tool-call") {
+ throw new Error(
+ `Result chunk on non-tool-call part not supported: ${part.type}`,
+ );
+ }
+ controller.enqueue({
+ type: DataStreamStreamChunkType.ToolCallResult,
+ value: {
+ toolCallId: part.toolCallId,
+ result: chunk.result,
+ },
+ });
+ break;
+ }
+ case "step-start": {
+ const { type, ...value } = chunk;
+ controller.enqueue({
+ type: DataStreamStreamChunkType.StartStep,
+ value,
+ });
+ break;
+ }
+ case "step-finish": {
+ const { type, ...value } = chunk;
+ controller.enqueue({
+ type: DataStreamStreamChunkType.FinishStep,
+ value,
+ });
+ break;
+ }
+ case "finish": {
+ const { type, ...value } = chunk;
+ controller.enqueue({
+ type: DataStreamStreamChunkType.FinishMessage,
+ value,
+ });
+ break;
+ }
+ case "error": {
+ controller.enqueue({
+ type: DataStreamStreamChunkType.Error,
+ value: chunk.error,
+ });
+ break;
+ }
+ case "annotations": {
+ controller.enqueue({
+ type: DataStreamStreamChunkType.Annotation,
+ value: chunk.annotations,
+ });
+ break;
+ }
+ case "data": {
+ controller.enqueue({
+ type: DataStreamStreamChunkType.Data,
+ value: chunk.data,
+ });
+ break;
+ }
+ default: {
+ const exhaustiveCheck: never = type;
+ throw new Error(`Unsupported chunk type: ${exhaustiveCheck}`);
+ }
+ }
+ },
+ });
+
+ return readable
+ .pipeThrough(new AssistantMetaTransformStream())
+ .pipeThrough(transform)
+ .pipeThrough(new DataStreamChunkEncoder())
+ .pipeThrough(new TextEncoderStream());
+ });
+ }
+}
+
+export class DataStreamDecoder {
+ private _transformStream;
+
+ public get writable() {
+ return this._transformStream.writable;
+ }
+
+ public get readable() {
+ return this._transformStream.readable;
+ }
+
+ constructor() {
+ this._transformStream = new PipeableTransformStream<
+ Uint8Array,
+ AssistantStreamChunk
+ >((readable) => {
+ const toolCallControllers = new Map<string, ToolCallStreamController>();
Greptile
greptile
logic: toolCallControllers map is never cleaned up - potential memory leak if tool calls accumulate
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
suggested fix
+ if (onlyChanged && changedFiles === null) {
try {
+ // Clear previous cache before new run
+ eslintCache.clear();
changedFiles = [...await listChangedFiles()];
changedFiles.forEach(file => {
if (!eslintCache.has(file)) {
eslintCache.set(file, null);
}
});
} catch (error) {
console.error('Error getting changed files:', error);
throw error;
}
}
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - the eslintCache grows indefinitely as new files are checked. Consider implementing a cache clearing mechanism.
diff block
loadNextDataSuccess: ({ response }) => {
props.onData?.(response)
},
+ resetLoadingTimer: () => {
+ if (cache.loadingTimer) {
+ window.clearInterval(cache.loadingTimer)
+ cache.loadingTimer = null
+ }
+
+ if (values.dataLoading) {
+ const startTime = Date.now()
+ cache.loadingTimer = window.setInterval(() => {
+ const seconds = Math.floor((Date.now() - startTime) / 1000)
+ actions.setLoadingTime(seconds)
+ }, 1000)
+ }
+ },
Greptile
greptile
logic: potential memory leak - loadingTimer interval is not cleared when component unmounts if dataLoading is still true
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
suggested fix
changedFiles = [...await listChangedFiles()];
+ // Clear old entries and only keep current changed files
+ eslintCache = new Map();
changedFiles.forEach(file => {
eslintCache.set(file, null);
});
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Cache stored in module-level variables will persist between runs and could cause memory leaks. Consider implementing cache clearing mechanism.
diff block
+import pino from 'pino'
+
+import { defaultConfig } from '../config/config'
+import { LogLevel } from '../types'
+import { isProdEnv } from './env-utils'
+
+export class Logger {
+ private pino: ReturnType<typeof pino>
+ private prefix: string
+
+ constructor(name: string) {
+ this.prefix = `[${name.toUpperCase()}]`
+ const logLevel: LogLevel = defaultConfig.LOG_LEVEL
+ if (isProdEnv()) {
+ this.pino = pino({
+ // By default pino will log the level number. So we can easily unify
+ // the log structure with other parts of the app e.g. the web
+ // server, we output the level name rather than the number. This
+ // way, e.g. we can easily ingest into Loki and query across
+ // workloads for all `error` log levels.
+ formatters: {
+ level: (label) => {
+ return { level: label }
+ },
+ },
+ level: logLevel,
+ })
+ } else {
+ // If we're not in production, we ensure that:
+ //
+ // 1. we see debug logs
+ // 2. logs are pretty printed
+ //
+ // NOTE: we keep a reference to the transport such that we can call
+ // end on it, otherwise Jest will hang on open handles.
+ const transport = pino.transport({
+ target: 'pino-pretty',
+ options: {
+ sync: true,
+ level: logLevel,
+ },
+ })
+ this.pino = pino({ level: logLevel }, transport)
+ }
+ }
+
+ private _log(level: LogLevel, ...args: any[]) {
+ // Get the last arg - if it is an object then we spread it into our log values
+ const lastArg = args[args.length - 1]
+ // Check if it is an object and not an error
+ const extra = typeof lastArg === 'object' && !(lastArg instanceof Error) ? lastArg : undefined
+
+ // If there is an extra object, we spread it into our log values
+ if (extra) {
+ args.pop()
+ }
+
+ const msg = `${this.prefix} ${args.join(' ')}`
+
+ this.pino[level]({
+ ...(extra || {}),
+ msg,
+ })
+ }
+
+ debug(...args: any[]) {
+ this._log(LogLevel.Debug, ...args)
+ }
+
+ info(...args: any[]) {
+ this._log(LogLevel.Info, ...args)
+ }
+
+ warn(...args: any[]) {
+ this._log(LogLevel.Warn, ...args)
+ }
+
+ error(...args: any[]) {
+ this._log(LogLevel.Error, ...args)
+ }
+
+ close() {}
Greptile
greptile
logic: Empty close() method could cause memory leaks by not properly closing the pino transport in non-production environments
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const code = useSnippet ? snippet : sourceParameters.originalSource || '';
const transformer = transformFromProps ?? sourceParameters.transform;
+ const transformed = useMemo(
+ () => (transformer ? transformer?.(code, storyContext) : code),
+ [code, storyContext, transformer]
+ );
+
+ useEffect(() => {
+ async function getTransformedCode() {
+ setTransformedCode(await transformed);
+ }
+
+ getTransformedCode();
+ }, [transformed]);
Greptile
greptile
logic: Missing cleanup function in useEffect - could lead to memory leaks if component unmounts during async operation
diff block
+import { exec } from "child_process";
+import { promisify } from "util";
+import { showFailureToast } from "@raycast/utils";
+import { Project } from "./utils/CacheManager";
+
+// Extend the Project type to make createTime optional
+interface GCloudProject extends Omit<Project, "createTime"> {
+ createTime?: string;
+}
+
+const execPromise = promisify(exec);
+
+interface CommandCacheEntry<T> {
+ result: T;
+ timestamp: number;
+}
+
+// Global cache for command results to reduce API calls
+const commandCache = new Map<string, CommandCacheEntry<unknown>>();
+const COMMAND_CACHE_TTL = 600000; // 10 minutes cache TTL
+const PROJECTS_CACHE_TTL = 1800000; // 30 minutes cache TTL
+const pendingRequests = new Map<string, Promise<unknown>>();
+
+/**
+ * Executes a gcloud command and returns the result as JSON
+ * @param gcloudPath Path to the gcloud executable
+ * @param command The command to execute
+ * @param projectId Optional project ID to use
+ * @param options Additional options for the command
+ * @returns The parsed JSON result
+ */
+export async function executeGcloudCommand(
+ gcloudPath: string,
+ command: string,
+ projectId?: string,
+ options: {
+ skipCache?: boolean;
+ cacheTTL?: number;
+ maxRetries?: number;
+ timeout?: number;
+ } = {},
+) {
+ // Validate inputs
+ if (!gcloudPath || typeof gcloudPath !== "string") {
+ showFailureToast({
+ title: "Invalid Configuration",
+ message: "Invalid gcloud path: must be a non-empty string",
+ });
+ throw new Error("Invalid gcloud path: must be a non-empty string");
+ }
+
+ if (!command || typeof command !== "string") {
+ showFailureToast({
+ title: "Invalid Command",
+ message: "Command must be a non-empty string",
+ });
+ throw new Error("Invalid command: must be a non-empty string");
+ }
+
+ try {
+ const { skipCache = false, cacheTTL = COMMAND_CACHE_TTL, maxRetries = 1, timeout = 25000 } = options;
+
+ // Only add project flag if projectId is provided and not empty
+ const projectFlag =
+ projectId && typeof projectId === "string" && projectId.trim() !== "" ? ` --project=${projectId}` : "";
+ const fullCommand = `${gcloudPath} ${command}${projectFlag} --format=json`;
+
+ // Generate a cache key from the command
+ const cacheKey = fullCommand;
+
+ // Check for pending requests for the same command to avoid duplicate API calls
+ const pendingRequest = pendingRequests.get(cacheKey);
+ if (pendingRequest) {
+ return pendingRequest;
+ }
+
+ // Check cache unless explicitly told to skip it
+ if (!skipCache) {
+ const cachedResult = commandCache.get(cacheKey);
+ const now = Date.now();
+
+ if (cachedResult && now - cachedResult.timestamp < cacheTTL) {
+ // console.log(`Using cached result for: ${fullCommand}`);
+ return cachedResult.result;
+ }
+ }
+
+ // Create a promise for this request with timeout
+ const requestPromise = Promise.race([
+ executeCommand(fullCommand, cacheKey, maxRetries),
+ new Promise((_, reject) => {
+ setTimeout(() => reject(new Error(`Command timed out after ${timeout}ms: ${fullCommand}`)), timeout);
+ }),
+ ]);
Greptile
greptile
logic: The timeout Promise should be cleared when the command completes to prevent memory leaks ```suggestion + const timeoutId = setTimeout(() => reject(new Error(`Command timed out after ${timeout}ms: ${fullCommand}`)), timeout); const requestPromise = Promise.race([ + executeCommand(fullCommand, cacheKey, maxRetries).finally(() => clearTimeout(timeoutId)), new Promise((_, reject) => { + timeoutId; }), ]); ```
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely as new files are checked. Consider implementing cache cleanup for removed files.
diff block
+import { useEffect, useState } from 'react'
+import { ResizeHandle } from '../../ui/src'
+import { Block, BlockNoteEditor, defaultProps } from '@/lib/blocknote'
+import { createReactBlockSpec } from '@/lib/blocknote'
+import { MediaContainer } from '../media-container'
+import { DisplayComponentProps, MediaRender, MediaType } from '../media-render'
+import { HMBlockSchema } from '../../schema'
+import { isValidUrl } from '../utils'
+
+export const ImageBlock = createReactBlockSpec({
+ type: 'image',
+ propSchema: {
+ ...defaultProps,
+ url: {
+ default: '',
+ },
+ alt: {
+ default: '',
+ },
+ name: {
+ default: '',
+ },
+ width: {
+ default: '',
+ },
+ defaultOpen: {
+ values: ['false', 'true'],
+ default: 'false',
+ },
+ },
+ containsInlineContent: true,
+
+ render: ({ block, editor }: { block: Block<HMBlockSchema>; editor: BlockNoteEditor<HMBlockSchema> }) =>
+ Render(block, editor),
+
+ parseHTML: [
+ {
+ tag: 'img[src]',
+ getAttrs: (element: any) => {
+ const name = element.getAttribute('title')
+ const width = element.getAttribute('width') || element.style.width
+ const alt = element.getAttribute('alt')
+ return {
+ url: element.getAttribute('src'),
+ name,
+ width,
+ alt,
+ }
+ },
+ node: 'image',
+ },
+ ],
+})
+
+const Render = (block: Block<HMBlockSchema>, editor: BlockNoteEditor<HMBlockSchema>) => {
+ const submitImage = async (
+ assignMedia: (props: MediaType) => void,
+ queryType: string,
+ url?: string,
+ setErrorRaised?: any,
+ ) => {
+ if (queryType === 'upload') {
+ const filePaths = await window.fileSystem.openImageFileDialog()
+
+ if (filePaths && filePaths.length > 0) {
+ const filePath: string = filePaths[0]
+ const fileData = await window.fileSystem.readFile(filePath, 'base64')
+ const imageData = `data:image/png;base64,${fileData}`
+
+ const storedImageUrl = await window.fileSystem.storeImage(imageData, filePath, block.id)
+
+ assignMedia({
+ id: block.id,
+ props: {
+ url: storedImageUrl,
+ name: filePath,
+ },
+ children: [],
+ content: [],
+ type: 'image',
+ })
+ }
+ }
+
+ if (url && isValidUrl(url)) {
+ try {
+ const response = await fetch(url)
+ if (!response.ok) {
+ setErrorRaised('Failed to fetch image')
+ }
+ const blob = await response.blob()
+ const reader = new FileReader()
+ reader.onloadend = async () => {
+ const imageData = reader.result as string
+
+ const sanitizedURL = url.split('?')[0]
+
+ const storedImageUrl = await window.fileSystem.storeImage(imageData, sanitizedURL, block.id)
+
+ assignMedia({
+ id: block.id,
+ props: {
+ url: storedImageUrl,
+ name: url,
+ },
+ children: [],
+ content: [],
+ type: 'image',
+ })
+ }
+ reader.readAsDataURL(blob)
+ } catch (error) {
+ setErrorRaised('Failed to fetch image')
+ }
+ } else {
+ setErrorRaised('Invalid URL')
+ }
+ }
+
+ return (
+ <MediaRender
+ block={block}
+ hideForm={!!block.props.url}
+ editor={editor}
+ mediaType="image"
+ submit={submitImage}
+ DisplayComponent={display}
+ />
+ )
+}
+
+const display = ({ editor, block, selected, setSelected, assign }: DisplayComponentProps) => {
+ const [imageUrl, setImageUrl] = useState(block.props.url)
+ const [isLoading, setIsLoading] = useState(true)
+
+ useEffect(() => {
+ const loadImage = async () => {
+ setIsLoading(true)
+ try {
+ if (block.props.url?.startsWith('local://')) {
+ const localImage = await window.fileSystem.getImage(block.props.url)
+ if (localImage) {
+ setImageUrl(localImage)
+ }
+ } else {
+ setImageUrl(block.props.url)
+ }
+ } catch (error) {
+ console.error('Error loading video:', error)
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ loadImage()
+ }, [block.props.url])
+
+ // Min image width in px.
+ const minWidth = 64
+ let width: number = parseFloat(block.props.width) || editor.domElement.firstElementChild!.clientWidth
+ const [currentWidth, setCurrentWidth] = useState(width)
+ const [showHandle, setShowHandle] = useState(false)
+ let resizeParams:
+ | {
+ handleUsed: 'left' | 'right'
+ initialWidth: number
+ initialClientX: number
+ }
+ | undefined
+
+ useEffect(() => {
+ if (block.props.width) {
+ width = parseFloat(block.props.width)
+ setCurrentWidth(parseFloat(block.props.width))
+ }
+ }, [block.props.width])
+
+ const windowMouseMoveHandler = (event: MouseEvent) => {
+ if (!resizeParams) {
+ return
+ }
+
+ let newWidth: number
+ if (resizeParams.handleUsed === 'left') {
+ newWidth = resizeParams.initialWidth + (resizeParams.initialClientX - event.clientX) * 2
+ } else {
+ newWidth = resizeParams.initialWidth + (event.clientX - resizeParams.initialClientX) * 2
+ }
+
+ // Ensures the image is not wider than the editor and not smaller than a
+ // predetermined minimum width.
+ if (newWidth < minWidth) {
+ width = minWidth
+ setCurrentWidth(minWidth)
+ } else if (newWidth > editor.domElement.firstElementChild!.clientWidth) {
+ width = editor.domElement.firstElementChild!.clientWidth
+ setCurrentWidth(editor.domElement.firstElementChild!.clientWidth)
+ } else {
+ width = newWidth
+ setCurrentWidth(newWidth)
+ }
+ }
+
+ // Stops mouse movements from resizing the image and updates the block's
+ // `width` prop to the new value.
+ const windowMouseUpHandler = (event: MouseEvent) => {
+ setShowHandle(false)
+
+ if (!resizeParams) {
+ return
+ }
+ resizeParams = undefined
+
+ assign({
+ props: {
+ width: width.toString(),
+ },
+ })
+
+ // @ts-expect-error
+ editor.updateBlock(block.id, {
+ ...block,
+ props: {
+ width: width.toString(),
+ },
+ })
+ }
+ window.addEventListener('mousemove', windowMouseMoveHandler)
+ window.addEventListener('mouseup', windowMouseUpHandler)
Greptile
greptile
logic: Event listeners are added but never removed, which could cause memory leaks
suggested fix
useEffect(() => {
window.addEventListener('mousemove', windowMouseMoveHandler)
window.addEventListener('mouseup', windowMouseUpHandler)
+ return () => {
+ window.removeEventListener('mousemove', windowMouseMoveHandler)
+ window.removeEventListener('mouseup', windowMouseUpHandler)
}
+ }, [])
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
style: Global variables could cause memory leaks across multiple runs. Consider clearing eslintCache when changedFiles is reset.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
+import React from 'react';
+import Button from '..';
+import { fireEvent, render, sleep, assertsExist } from '../../../tests/utils';
+
+// Mock Wave ref
+let waveInstanceMock: InstanceType<typeof import('../../_util/wave').default> | null;
+jest.mock('../../_util/wave', () => {
+ const Wave: typeof import('../../_util/wave') = jest.requireActual('../../_util/wave');
+ const WaveComponent = Wave.default;
+
+ return {
+ ...Wave,
+ __esModule: true,
+ default: (props: import('../../_util/wave').WaveProps) => (
+ <WaveComponent
+ ref={node => {
+ waveInstanceMock = node;
+ }}
+ {...props}
+ />
+ ),
+ };
+});
+
+describe('click wave effect', () => {
+ async function clickButton(wrapper: any) {
+ const element = wrapper.container.firstChild;
+ fireEvent.click(element);
+ fireEvent(element, new Event('transitionstart'));
+ await sleep(20);
+ fireEvent(element, new Event('animationend'));
+ await sleep(20);
+ }
+
+ it('should have click wave effect for primary button', async () => {
+ const wrapper = render(<Button type="primary">button</Button>);
+ await clickButton(wrapper);
+ expect(wrapper.container.querySelector('.ant-btn')).toHaveAttribute(
+ 'ant-click-animating-without-extra-node',
+ );
+ });
+
+ it('should have click wave effect for default button', async () => {
+ const wrapper = render(<Button>button</Button>);
+ await clickButton(wrapper);
+ expect(wrapper.container.querySelector('.ant-btn')).toHaveAttribute(
+ 'ant-click-animating-without-extra-node',
+ );
+ });
+
+ it('should not have click wave effect for link type button', async () => {
+ const wrapper = render(<Button type="link">button</Button>);
+ await clickButton(wrapper);
+ expect(wrapper.container.querySelector('.ant-btn')).not.toHaveAttribute(
+ 'ant-click-animating-without-extra-node',
+ );
+ });
+
+ it('should not have click wave effect for text type button', async () => {
+ const wrapper = render(<Button type="text">button</Button>);
+ await clickButton(wrapper);
+ expect(wrapper.container.querySelector('.ant-btn')).not.toHaveAttribute(
+ 'ant-click-animating-without-extra-node',
+ );
+ });
+
+ it('should handle transitionstart', async () => {
+ const wrapper = render(<Button type="primary">button</Button>);
+ await clickButton(wrapper);
+ const buttonNode = wrapper.container.querySelector('.ant-btn')!;
+ fireEvent(buttonNode, new Event('transitionstart'));
+ expect(wrapper.container.querySelector('.ant-btn')).toHaveAttribute(
+ 'ant-click-animating-without-extra-node',
+ );
+ wrapper.unmount();
+ fireEvent(buttonNode, new Event('transitionstart'));
+ });
Greptile
greptile
logic: firing transitionstart event after unmount could cause memory leaks
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is not cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is created but never cleared or persisted between runs. This could lead to memory leaks in long-running processes.
diff block
+---
+order: 4
+title:
+ zh-CN: 加载中状态
+ en-US: Loading
+---
+
+## zh-CN
+
+添加 `loading` 属性即可让按钮处于加载状态,最后两个按钮演示点击后进入加载状态。
+
+## en-US
+
+A loading indicator can be added to a button by setting the `loading` property on the `Button`.
+
+```tsx
+import { PoweroffOutlined } from '@ant-design/icons';
+import { Button, Space } from 'antd';
+import React, { useState } from 'react';
+
+const App: React.FC = () => {
+ const [loadings, setLoadings] = useState<boolean[]>([]);
+
+ const enterLoading = (index: number) => {
+ setLoadings(prevLoadings => {
+ const newLoadings = [...prevLoadings];
+ newLoadings[index] = true;
+ return newLoadings;
+ });
+
+ setTimeout(() => {
+ setLoadings(prevLoadings => {
+ const newLoadings = [...prevLoadings];
+ newLoadings[index] = false;
+ return newLoadings;
+ });
+ }, 6000);
+ };
Greptile
greptile
style: setTimeout without cleanup could cause memory leaks if component unmounts during loading. Consider using useEffect with cleanup
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Cache is stored in module-level variables which persist between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared at module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: The eslintCache is stored in module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, which could lead to memory leaks in long-running processes
diff block
return (await response.json()) as string[];
}
+
+ public async connectToWebSocket(): Promise<void> {
+ const wsUrl = `${import.meta.env.VITE_SUPABASE_API_URL?.replace('https://', 'wss://')}${FUNCTIONS_ROUTE}${BASE_API_ROUTE}${ApiRoutes.AI_WS}`;
+ if (!wsUrl) {
+ throw new Error('WebSocket URL not found');
+ }
+
+ const ws = new WebSocket(wsUrl);
+
+ ws.onopen = () => {
+ console.log('WebSocket connection opened');
+ };
+
+ ws.onmessage = (event) => {
+ console.log('WebSocket message received', event.data);
+ };
+
+ ws.onclose = () => {
+ console.log('WebSocket connection closed');
+ };
+ }
Greptile
greptile
logic: connectToWebSocket method creates a WebSocket instance but never stores or cleans it up, leading to potential memory leaks
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is not cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
Greptile
greptile
style: Memory leak potential - changedFiles array is spread twice unnecessarily. Use direct assignment instead.
suggested fix
+ changedFiles = await listChangedFiles();
changedFiles.forEach(file => {
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared at module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
}, 500)
).current;
+ const isGoUpButtonVisible = (results: any[], scrollTop: number) => {
+ const withinLimit = results.length > 0 && results.length <= TOTAL_ITEMS_TO_SHOW_GO_UP_BUTTOM;
+ return withinLimit && scrollTop >= LIMIT_SCROLL_TO_DISAPEAR_GO_UP_BUTTOM;
+ };
+
+ useEffect(() => {
+ const withinLimit = results.length > 0 && results.length <= TOTAL_ITEMS_TO_SHOW_GO_UP_BUTTOM;
+ setWantGoUpButtonIsVisible(withinLimit);
+ }, [results])
+
+ useEffect(() => {
Greptile
greptile
logic: Missing cleanup of debounced handleScroll function which could cause memory leaks
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
Greptile
greptile
style: Memory leak potential - changedFiles array is spread twice unnecessarily. Consider removing the spread operator here.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Cache is stored in module-level variables which persist between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
+import { useEffect, useState } from "react";
+import { Action, ActionPanel, Detail, List, Icon } from "@raycast/api";
+import { formatDistance } from "date-fns";
+import { loadRecentReleases } from "../utils.js";
+import { Release } from "../types.js";
+
+export default function Releases() {
+ const [releases, setReleases] = useState<Release[]>([]);
+ const [error, setError] = useState("");
+
+ const fetchReleases = async () => {
+ try {
+ const releases = await loadRecentReleases();
+ setReleases(releases);
+ } catch (error) {
+ setError(error instanceof Error ? error.message : "An error occurred while loading releases");
+ }
+ };
Greptile
greptile
logic: fetchReleases should be wrapped in an AbortController to handle component unmounting and prevent memory leaks
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
style: Global mutable state (changedFiles and eslintCache) could cause memory leaks in long-running processes. Consider moving to function scope or implementing cache clearing.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: The eslintCache is initialized but never cleared between runs, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
style: Global mutable state could cause memory leaks in long-running processes since the cache is never cleared
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
style: Global variables could cause memory leaks across multiple runs. Consider clearing eslintCache when changedFiles is reset.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
const finalFilePatterns = onlyChanged
? intersect(changedFiles, filePatterns)
: filePatterns;
const report = cli.executeOnFiles(finalFilePatterns);
- if (options != null && options.fix === true) {
+ if (defaultOptions.fix === true) {
CLIEngine.outputFixes(report);
}
- // When using `ignorePattern`, eslint will show `File ignored...` warnings for any ignores.
- // We don't care because we *expect* some passed files will be ignores if `ignorePattern` is used.
const messages = report.results.filter(item => {
- if (!onlyChanged) {
- // Don't suppress the message on a full run.
- // We only expect it to happen for "only changed" runs.
- return true;
- }
- const ignoreMessage =
- 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
- return !(item.messages[0] && item.messages[0].message === ignoreMessage);
+ if (!onlyChanged) return true;
+
+ const ignoreMessage = 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
+ const isIgnored = item.messages[0]?.message === ignoreMessage;
+
+ eslintCache.set(item.filePath, isIgnored ? null : item);
Greptile
greptile
style: Cache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is stored in module scope but never cleared between runs, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
style: Cache is stored in module-level variables which persist between runs. This could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely as new files are checked. Consider adding cache invalidation strategy.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
const finalFilePatterns = onlyChanged
? intersect(changedFiles, filePatterns)
: filePatterns;
const report = cli.executeOnFiles(finalFilePatterns);
- if (options != null && options.fix === true) {
+ if (defaultOptions.fix === true) {
CLIEngine.outputFixes(report);
}
- // When using `ignorePattern`, eslint will show `File ignored...` warnings for any ignores.
- // We don't care because we *expect* some passed files will be ignores if `ignorePattern` is used.
const messages = report.results.filter(item => {
- if (!onlyChanged) {
- // Don't suppress the message on a full run.
- // We only expect it to happen for "only changed" runs.
- return true;
- }
- const ignoreMessage =
- 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
- return !(item.messages[0] && item.messages[0].message === ignoreMessage);
+ if (!onlyChanged) return true;
+
+ const ignoreMessage = 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
+ const isIgnored = item.messages[0]?.message === ignoreMessage;
+
+ eslintCache.set(item.filePath, isIgnored ? null : item);
Greptile
greptile
logic: Cache entries are never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is stored in module scope but never cleared between runs, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
+"use client";
+
+import "@assistant-ui/react-markdown/styles/dot.css";
+
+import {
+ CodeHeaderProps,
+ MarkdownTextPrimitive,
+ unstable_memoizeMarkdownComponents as memoizeMarkdownComponents,
+ useIsMarkdownCodeBlock,
+} from "@assistant-ui/react-markdown";
+import remarkGfm from "remark-gfm";
+import { FC, memo, useState } from "react";
+import { CheckIcon, CopyIcon } from "lucide-react";
+
+import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
+import { cn } from "@/lib/utils";
+
+const MarkdownTextImpl = () => {
+ return (
+ <MarkdownTextPrimitive
+ remarkPlugins={[remarkGfm]}
+ className="aui-md"
+ components={defaultComponents}
+ />
+ );
+};
+
+export const MarkdownText = memo(MarkdownTextImpl);
+
+const CodeHeader: FC<CodeHeaderProps> = ({ language, code }) => {
+ const { isCopied, copyToClipboard } = useCopyToClipboard();
+ const onCopy = () => {
+ if (!code || isCopied) return;
+ copyToClipboard(code);
+ };
+
+ return (
+ <div className="flex items-center justify-between gap-4 rounded-t-lg bg-zinc-900 px-4 py-2 text-sm font-semibold text-white">
+ <span className="lowercase [&>span]:text-xs">{language}</span>
+ <TooltipIconButton tooltip="Copy" onClick={onCopy}>
+ {!isCopied && <CopyIcon />}
+ {isCopied && <CheckIcon />}
+ </TooltipIconButton>
+ </div>
+ );
+};
+
+const useCopyToClipboard = ({
+ copiedDuration = 3000,
+}: {
+ copiedDuration?: number;
+} = {}) => {
+ const [isCopied, setIsCopied] = useState<boolean>(false);
+
+ const copyToClipboard = (value: string) => {
+ if (!value) return;
+
+ navigator.clipboard.writeText(value).then(() => {
+ setIsCopied(true);
+ setTimeout(() => setIsCopied(false), copiedDuration);
+ });
Greptile
greptile
logic: Consider cleaning up the setTimeout (e.g., using a ref and clearing it on unmount) to avoid potential memory leaks.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
const finalFilePatterns = onlyChanged
? intersect(changedFiles, filePatterns)
: filePatterns;
const report = cli.executeOnFiles(finalFilePatterns);
- if (options != null && options.fix === true) {
+ if (defaultOptions.fix === true) {
CLIEngine.outputFixes(report);
}
- // When using `ignorePattern`, eslint will show `File ignored...` warnings for any ignores.
- // We don't care because we *expect* some passed files will be ignores if `ignorePattern` is used.
const messages = report.results.filter(item => {
- if (!onlyChanged) {
- // Don't suppress the message on a full run.
- // We only expect it to happen for "only changed" runs.
- return true;
- }
- const ignoreMessage =
- 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
- return !(item.messages[0] && item.messages[0].message === ignoreMessage);
+ if (!onlyChanged) return true;
+
+ const ignoreMessage = 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
+ const isIgnored = item.messages[0]?.message === ignoreMessage;
+
+ eslintCache.set(item.filePath, isIgnored ? null : item);
Greptile
greptile
style: Cache entries are never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
+import React, { useContext, useEffect, useState } from 'react';
+
+import { Box, Text } from 'ink';
+
+import type { State } from '../steps';
+import { AppContext } from '../utils/context';
+
+export function Telemetry({ state }: { state: State }) {
+ const { telemetry } = useContext(AppContext);
+
+ useEffect(() => {
+ const { intents, framework, features, version, install, directory } = state;
+ telemetry?.('init', { intents, framework, features, version, install, directory });
+ }, []);
Greptile
greptile
logic: missing cleanup function in useEffect and missing telemetry in dependency array - could cause memory leaks or stale closures
diff block
+import { createInterface } from 'node:readline';
+
+// eslint-disable-next-line depend/ban-dependencies
+import { execaCommand } from 'execa';
+
+/**
+ * Execute a command in the local terminal and count the lines in the result
+ *
+ * @param command The command to execute.
+ * @param options Execa options
+ * @returns The number of lines the command returned
+ */
+export async function execCommandCountLines(
+ command: string,
+ options?: Parameters<typeof execaCommand>[1]
+) {
+ const process = execaCommand(command, { shell: true, buffer: false, ...options });
+ if (!process.stdout) {
+ // Return undefined rather than throwing an error
+ return undefined;
+ }
+
+ let lineCount = 0;
+ const rl = createInterface(process.stdout);
+ rl.on('line', () => {
+ lineCount += 1;
+ });
Greptile
greptile
logic: readline interface is never closed with rl.close(). This could cause memory leaks.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential: changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is stored in module scope but never cleared between runs, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
suggested fix
changedFiles = [...await listChangedFiles()];
+ // Clear old entries before adding new ones
+ eslintCache.clear();
changedFiles.forEach(file => {
eslintCache.set(file, null);
});
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is using module-level state which could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
style: Global mutable state (changedFiles and eslintCache) could cause memory leaks in long-running processes. Consider moving cache into the function scope or implementing cache clearing.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Consider clearing it when appropriate to prevent memory leaks in long-running processes.
diff block
};
};
+ /**
+ * Wait for a specific event to be sent _once_.
+ *
+ * This is useful if you only want to wait for an event to be sent once, and not continuously.
+ * Optionally supply a second event, that will reject the promise if that is sent first.
+ *
+ * @example
+ *
+ * ```typescript
+ * try {
+ * const { event, eventInfo } = await store.untilEvent('TASK_COMPLETED', 'TASK_FAILED');
+ * console.log('Task completed', event, eventInfo);
+ * } catch ({ event, eventInfo }) {
+ * console.error('Task failed', event, eventInfo);
+ * }
+ * ```
+ */
+ public untilEvent<TEvent extends Event<State, CustomEvent>>(
+ resolveEventType: TEvent['type'],
+ rejectEventType?: TEvent['type']
+ ): Promise<{ event: TEvent; eventInfo: EventInfo }> {
+ return new Promise<{ event: TEvent; eventInfo: EventInfo }>((resolve, reject) => {
+ const unsubscribeResolve = this.subscribe(resolveEventType as any, (event, eventInfo) => {
+ unsubscribeResolve();
+ resolve({ event, eventInfo } as any);
+ });
+ if (rejectEventType) {
+ const unsubscribeReject = this.subscribe(rejectEventType as any, (event, eventInfo) => {
+ unsubscribeReject();
+ reject({ event, eventInfo } as any);
+ });
+ }
+ });
Greptile
greptile
logic: The unsubscribeReject function is created but not called if the rejectEventType event occurs and the promise is rejected. This could lead to a memory leak as the event listener would remain active.
suggested fix
public untilEvent<TEvent extends Event<State, CustomEvent>>(
resolveEventType: TEvent['type'],
rejectEventType?: TEvent['type']
): Promise<{ event: TEvent; eventInfo: EventInfo }> {
return new Promise<{ event: TEvent; eventInfo: EventInfo }>((resolve, reject) => {
const unsubscribeResolve = this.subscribe(resolveEventType as any, (event, eventInfo) => {
unsubscribeResolve();
+ if (unsubscribeReject) unsubscribeReject();
resolve({ event, eventInfo } as any);
});
+ let unsubscribeReject: (() => void) | undefined;
if (rejectEventType) {
+ unsubscribeReject = this.subscribe(rejectEventType as any, (event, eventInfo) => {
+ unsubscribeReject?.();
unsubscribeResolve();
reject({ event, eventInfo } as any);
});
}
});
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
+import { Readable, Transform } from "node:stream";
+import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
+
+async function streamS3File(
+ s3Client: S3Client,
+ bucket: string,
+ key: string,
+): Promise<string> {
+ try {
+ // Get object from S3
+ const response = await s3Client.send(
+ new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }),
+ );
+
+ // Convert S3 stream to Node readable stream
+ const s3Stream = Readable.from(response.Body as any);
+
+ // Create transform stream for uppercase conversion
+ const chunks: Buffer[] = [];
+ const transform = new Transform({
+ transform(chunk, encoding, callback) {
+ chunks.push(Buffer.from(chunk.toString().toUpperCase()));
+ callback();
+ },
+ });
+
+ // Pipe the stream and collect the data
+ return new Promise((resolve, reject) => {
+ s3Stream
+ .pipe(transform)
+ .on("data", (chunk) => chunks.push(chunk))
+ .on("end", () => resolve(Buffer.concat(chunks).toString()))
+ .on("error", reject);
+ });
Greptile
greptile
logic: memory leak potential - no cleanup of stream resources if promise rejects
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Cache is stored in module-level variables which persist between runs. This could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: The eslintCache is stored in module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache and changedFiles are module-level variables that persist between runs, which could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - the eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism or size limit.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: The eslintCache is stored in module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely without cleanup mechanism
suggested fix
changedFiles = [...await listChangedFiles()];
+ // Clear old entries before adding new ones
+ eslintCache.clear();
changedFiles.forEach(file => {
eslintCache.set(file, null);
});
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared at module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared - could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
+import React, { useEffect, useState } from 'react';
+import { createPortal } from 'react-dom';
+
+import { expect, fn, mocked, userEvent, within } from '@storybook/test';
+
+import { action } from '@storybook/addon-actions';
+
+import { definePreview } from '../preview';
+import { Button } from './Button';
+
+const preview = definePreview({});
+
+const meta = preview.meta({
+ id: 'button-component',
+ title: 'Example/CSF4/Button',
+ component: Button,
+ argTypes: {
+ backgroundColor: { control: 'color' },
+ },
+ args: {
+ children: 'Children coming from meta args',
+ },
+});
+
+export const CSF2Secondary = meta.story({
+ render: (args) => {
+ return <Button {...args} />;
+ },
+ args: {
+ children: 'Children coming from story args!',
+ primary: false,
+ },
+});
+
+const getCaptionForLocale = (locale: string) => {
+ switch (locale) {
+ case 'es':
+ return 'Hola!';
+ case 'fr':
+ return 'Bonjour!';
+ case 'kr':
+ return '안녕하세요!';
+ case 'pt':
+ return 'Olá!';
+ case 'en':
+ return 'Hello!';
+ default:
+ return undefined;
+ }
+};
+
+export const CSF2StoryWithLocale = meta.story({
+ render: (args, { globals: { locale } }) => {
+ const caption = getCaptionForLocale(locale);
+ return (
+ <>
+ <p>locale: {locale}</p>
+ <Button>{caption}</Button>
+ </>
+ );
+ },
+ name: 'WithLocale',
+});
+
+export const CSF2StoryWithParamsAndDecorator = meta.story({
+ render: (args) => {
+ return <Button {...args} />;
+ },
+ args: {
+ children: 'foo',
+ },
+ parameters: {
+ layout: 'centered',
+ },
+ decorators: (StoryFn) => <StoryFn />,
+});
+
+export const CSF3Primary = meta.story({
+ args: {
+ children: 'foo',
+ size: 'large',
+ primary: true,
+ },
+});
+
+export const CSF3Button = meta.story({
+ args: { children: 'foo' },
+});
+
+export const CSF3ButtonWithRender = meta.story({
+ ...CSF3Button.input,
+ render: (args) => (
+ <div>
+ <p data-testid="custom-render">I am a custom render function</p>
+ <Button {...args} />
+ </div>
+ ),
+});
+
+export const HooksStory = meta.story({
+ render: function Component() {
+ const [isClicked, setClicked] = useState(false);
+ return (
+ <>
+ <input data-testid="input" />
+ <br />
+ <button onClick={() => setClicked(!isClicked)}>
+ I am {isClicked ? 'clicked' : 'not clicked'}
+ </button>
+ </>
+ );
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+ await step('Step label', async () => {
+ const inputEl = canvas.getByTestId('input');
+ const buttonEl = canvas.getByRole('button');
+ await userEvent.click(buttonEl);
+ await userEvent.type(inputEl, 'Hello world!');
+
+ await expect(inputEl).toHaveValue('Hello world!');
+ await expect(buttonEl).toHaveTextContent('I am clicked');
+ });
+ },
+});
+
+export const CSF3InputFieldFilled = meta.story({
+ render: () => {
+ return <input data-testid="input" />;
+ },
+ play: async ({ canvasElement, step }) => {
+ const canvas = within(canvasElement);
+ await step('Step label', async () => {
+ const inputEl = canvas.getByTestId('input');
+ await userEvent.type(inputEl, 'Hello world!');
+ await expect(inputEl).toHaveValue('Hello world!');
+ });
+ },
+});
+
+const mockFn = fn();
+export const LoaderStory = meta.story({
+ args: {
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ mockFn,
+ },
+ loaders: [
+ async () => {
+ mockFn.mockReturnValueOnce('mockFn return value');
+ return {
+ value: 'loaded data',
+ };
+ },
+ ],
+ render: (args: any & { mockFn: (val: string) => string }, { loaded }) => {
+ const data = args.mockFn('render');
+ return (
+ <div>
+ <div data-testid="loaded-data">{loaded.value}</div>
+ <div data-testid="spy-data">{String(data)}</div>
+ </div>
+ );
+ },
+ play: async () => {
+ expect(mockFn).toHaveBeenCalledWith('render');
+ },
+});
+
+export const MountInPlayFunction = meta.story({
+ args: {
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ mockFn: fn(),
+ },
+ play: async ({ args, mount, context }) => {
+ // equivalent of loaders
+ const loadedData = await Promise.resolve('loaded data');
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ mocked(args.mockFn).mockReturnValueOnce('mockFn return value');
+ // equivalent of render
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ const data = args.mockFn('render');
+ // TODO refactor this in the mount args PR
+ context.originalStoryFn = () => (
+ <div>
+ <div data-testid="loaded-data">{loadedData}</div>
+ <div data-testid="spy-data">{String(data)}</div>
+ </div>
+ );
+ await mount();
+
+ // equivalent of play
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ expect(args.mockFn).toHaveBeenCalledWith('render');
+ },
+});
+
+export const MountInPlayFunctionThrow = meta.story({
+ play: async () => {
+ throw new Error('Error thrown in play');
+ },
+});
+
+export const WithActionArg = meta.story({
+ args: {
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ someActionArg: action('some-action-arg'),
+ },
+ render: (args) => {
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ args.someActionArg('in render');
+ return (
+ <button
+ onClick={() => {
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ args.someActionArg('on click');
+ }}
+ />
+ );
+ },
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ const buttonEl = await canvas.getByRole('button');
+ await buttonEl.click();
+ },
+});
+
+export const WithActionArgType = meta.story({
+ argTypes: {
+ // @ts-expect-error TODO: add a way to provide custom args/argTypes
+ someActionArg: {
+ action: true,
+ },
+ },
+ render: () => {
+ return <div>nothing</div>;
+ },
+});
+
+export const Modal = meta.story({
+ render: function Component() {
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [modalContainer] = useState(() => {
+ const div = document.createElement('div');
+ div.id = 'modal-root';
+ return div;
+ });
+
+ useEffect(() => {
+ document.body.appendChild(modalContainer);
+ return () => {
+ document.body.removeChild(modalContainer);
+ };
+ }, [modalContainer]);
Greptile
greptile
logic: Modal container creation and cleanup could cause memory leaks if story is rendered multiple times. Consider moving modalContainer to a shared context or ref.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: The eslintCache is stored in a module-level variable but never cleared between runs, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - the eslintCache grows indefinitely without cleanup. Consider implementing a cache clearing mechanism or size limit.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
+import { clearSearchBar, getPreferenceValues, showToast, Toast } from "@raycast/api";
+import { useCallback, useMemo, useRef, useState } from "react";
+import say from "say";
+import { v4 as uuidv4 } from "uuid";
+import { Chat, ChatHook, Model } from "../type";
+import { buildUserMessage, chatTransformer } from "../utils";
+import { useAutoTTS } from "./useAutoTTS";
+import { useGemini } from "./useGemini";
+import { useHistory } from "./useHistory";
+import { useProxy } from "./useProxy";
+import { ChatCompletion, ChatCompletionChunk } from "openai/resources/chat/completions";
+import { Stream } from "openai/streaming";
+
+export function useChat<T extends Chat>(props: T[]): ChatHook {
+ const [data, setData] = useState<Chat[]>(props);
+ const [errorMsg, setErrorMsg] = useState<string | null>(null);
+ const [selectedChatId, setSelectedChatId] = useState<string | null>(null);
+ const [isLoading, setLoading] = useState<boolean>(false);
+ const [isAborted, setIsAborted] = useState<boolean>(false);
+ const [useStream] = useState<boolean>(() => {
+ return getPreferenceValues<{
+ useStream: boolean;
+ }>().useStream;
+ });
+ const [streamData, setStreamData] = useState<Chat | undefined>();
+ const abortControllerRef = useRef<AbortController | null>(null);
+
+ const [isHistoryPaused] = useState<boolean>(() => {
+ return getPreferenceValues<{
+ isHistoryPaused: boolean;
+ }>().isHistoryPaused;
+ });
+
+ const history = useHistory();
+ const isAutoTTS = useAutoTTS();
+ const proxy = useProxy();
+ const gemini = useGemini();
+
+ async function ask(question: string, files: string[], model: Model) {
+ clearSearchBar();
+
+ setLoading(true);
+ const toast = await showToast({
+ title: "Getting your answer...",
+ style: Toast.Style.Animated,
+ });
+ let chat: Chat = {
+ id: uuidv4(),
+ question,
+ files,
+ answer: "",
+ created_at: new Date().toISOString(),
+ };
+
+ setData((prev) => {
+ return [...prev, chat];
+ });
+
+ setTimeout(async () => {
+ setSelectedChatId(chat.id);
+ }, 50);
Greptile
greptile
style: setTimeout with async callback can cause memory leaks if component unmounts. Consider useEffect cleanup
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Cache is populated but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - cache grows indefinitely as new files are checked. Consider implementing a cache cleanup mechanism.
diff block
+/*
+ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
+ *
+ * Copyright (c) 2002 - 2019 Bruce Mayhew
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program; if
+ * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Getting Source ==============
+ *
+ * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
+ */
+
+package org.owasp.webgoat.lessons.passwordreset;
+
+import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
+import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
+
+import jakarta.servlet.http.HttpServletRequest;
+import java.util.UUID;
+import org.owasp.webgoat.container.CurrentUsername;
+import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
+import org.owasp.webgoat.container.assignments.AttackResult;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Part of the password reset assignment. Used to send the e-mail.
+ *
+ * @author nbaars
+ * @since 8/20/17.
+ */
+@RestController
+public class ResetLinkAssignmentForgotPassword implements AssignmentEndpoint {
+
+ private final RestTemplate restTemplate;
+ private final String webWolfHost;
+ private final String webWolfPort;
+ private final String webWolfURL;
+ private final String webWolfMailURL;
+
+ public ResetLinkAssignmentForgotPassword(
+ RestTemplate restTemplate,
+ @Value("${webwolf.host}") String webWolfHost,
+ @Value("${webwolf.port}") String webWolfPort,
+ @Value("${webwolf.url}") String webWolfURL,
+ @Value("${webwolf.mail.url}") String webWolfMailURL) {
+ this.restTemplate = restTemplate;
+ this.webWolfHost = webWolfHost;
+ this.webWolfPort = webWolfPort;
+ this.webWolfURL = webWolfURL;
+ this.webWolfMailURL = webWolfMailURL;
+ }
+
+ @PostMapping("/PasswordReset/ForgotPassword/create-password-reset-link")
+ @ResponseBody
+ public AttackResult sendPasswordResetLink(
+ @RequestParam String email, HttpServletRequest request, @CurrentUsername String username) {
+ String resetLink = UUID.randomUUID().toString();
+ ResetLinkAssignment.resetLinks.add(resetLink);
Greptile
greptile
logic: Using a static collection for reset links creates a memory leak. Consider using a time-based cleanup mechanism or database storage.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is using module-level state which could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - the eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Global mutable state (changedFiles and eslintCache) could cause memory leaks in long-running processes. Consider clearing the cache periodically or moving to a more scoped implementation.
diff block
if let Some(slot) = filename.split('.').next() {
if let Ok(slot) = slot.parse::<Slot>() {
if slot <= keep_after {
- self.storage.map.remove(&slot);
+ //self.storage.map.remove(&slot);
total_removed += 1;
Greptile
greptile
logic: Storage map removal is commented out - this could lead to memory leaks if old entries aren't properly cleaned up
diff block
+/*
+ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
+ *
+ * Copyright (c) 2002 - 2019 Bruce Mayhew
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program; if
+ * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Getting Source ==============
+ *
+ * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
+ */
+
+package org.owasp.webgoat.lessons.passwordreset;
+
+import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
+import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
+import static org.springframework.util.StringUtils.hasText;
+
+import com.google.common.collect.Maps;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.owasp.webgoat.container.CurrentUsername;
+import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
+import org.owasp.webgoat.container.assignments.AssignmentHints;
+import org.owasp.webgoat.container.assignments.AttackResult;
+import org.owasp.webgoat.lessons.passwordreset.resetlink.PasswordChangeForm;
+import org.springframework.ui.Model;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * @author nbaars
+ * @since 8/20/17.
+ */
+@RestController
+@AssignmentHints({
+ "password-reset-hint1",
+ "password-reset-hint2",
+ "password-reset-hint3",
+ "password-reset-hint4",
+ "password-reset-hint5",
+ "password-reset-hint6"
+})
+public class ResetLinkAssignment implements AssignmentEndpoint {
+
+ private static final String VIEW_FORMATTER = "lessons/passwordreset/templates/%s.html";
+ static final String PASSWORD_TOM_9 =
+ "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom";
+ static final String TOM_EMAIL = "tom@webgoat-cloud.org";
+ static Map<String, String> userToTomResetLink = new HashMap<>();
+ static Map<String, String> usersToTomPassword = Maps.newHashMap();
+ static List<String> resetLinks = new ArrayList<>();
Greptile
greptile
logic: Using static collections for user data creates thread safety issues and potential memory leaks since entries are never removed
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
+import { LemonButton, Popover } from '@posthog/lemon-ui'
+import { useActions, useValues } from 'kea'
+import { HedgehogBuddy } from 'lib/components/HedgehogBuddy/HedgehogBuddy'
+import { hedgehogBuddyLogic } from 'lib/components/HedgehogBuddy/hedgehogBuddyLogic'
+import { maxGlobalLogic } from 'scenes/max/maxGlobalLogic'
+
+export const AiConsentPopover = (): JSX.Element => {
+ const { acceptDataProcessing } = useActions(maxGlobalLogic)
+ const { dataProcessingAccepted } = useValues(maxGlobalLogic)
+ const { hedgehogConfig } = useValues(hedgehogBuddyLogic)
+
+ if (dataProcessingAccepted) {
+ return <></>
+ }
+
+ return (
+ <>
+ <div className="flex justify-center">
+ <Popover
+ overlay={
+ <div className="m-1.5 max-w-80">
+ <p className="font-medium text-pretty mb-1.5">
+ Hi! This feature uses OpenAI to analyze your data,helping you gain insights faster. If
+ your data includes personal information, it may be processed.
+ <br />
+ Your data won't be used for AI training.
+ </p>
+ <LemonButton type="secondary" size="small" onClick={() => acceptDataProcessing()}>
+ Got it, I accept OpenAI processing my data
+ </LemonButton>
+ </div>
+ }
+ placement="right-end"
+ showArrow
+ visible={true}
+ >
+ <HedgehogBuddy
+ static
+ hedgehogConfig={{
+ ...hedgehogConfig,
+ walking_enabled: false,
+ controls_enabled: false,
+ }}
+ onClick={(actor) => {
+ if (Math.random() < 0.01) {
+ actor.setOnFire()
+ } else {
+ actor.setRandomAnimation()
+ }
+ }}
+ onActorLoaded={(actor) =>
+ setTimeout(() => {
+ actor.setAnimation('wave')
+ // Always start out facing right so that the data processing popover is more readable
+ actor.direction = 'right'
+ }, 100)
+ }
Greptile
greptile
logic: Using setTimeout without cleanup in a React component can cause memory leaks. Consider using useEffect
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - cache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Global state variables could cause memory leaks in long-running processes since the cache is never cleared
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs - could cause memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - the eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: The eslintCache is stored in module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is stored in module scope but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Potential memory leak - cache grows indefinitely as new files are added but never cleared. Consider implementing a cache cleanup mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared at module level but never cleared. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared at module scope but never cleared. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: The eslintCache is stored in module scope but never cleared. This could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared at module scope but never cleared. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
const finalFilePatterns = onlyChanged
? intersect(changedFiles, filePatterns)
: filePatterns;
const report = cli.executeOnFiles(finalFilePatterns);
- if (options != null && options.fix === true) {
+ if (defaultOptions.fix === true) {
CLIEngine.outputFixes(report);
}
- // When using `ignorePattern`, eslint will show `File ignored...` warnings for any ignores.
- // We don't care because we *expect* some passed files will be ignores if `ignorePattern` is used.
const messages = report.results.filter(item => {
- if (!onlyChanged) {
- // Don't suppress the message on a full run.
- // We only expect it to happen for "only changed" runs.
- return true;
- }
- const ignoreMessage =
- 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
- return !(item.messages[0] && item.messages[0].message === ignoreMessage);
+ if (!onlyChanged) return true;
+
+ const ignoreMessage = 'File ignored because of a matching ignore pattern. Use "--no-ignore" to override.';
+ const isIgnored = item.messages[0]?.message === ignoreMessage;
+
+ eslintCache.set(item.filePath, isIgnored ? null : item);
Greptile
greptile
style: Memory leak risk: eslintCache grows indefinitely without cleanup. Consider implementing a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely as new files are added but never cleared.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - the eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism or size limit.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared globally but never cleared, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - eslintCache grows indefinitely without cleanup mechanism
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could lead to memory leaks in long-running processes.
diff block
+import { Injectable } from '@nestjs/common';
+import { HealthIndicator, HealthIndicatorResult } from '@nestjs/terminus';
+
+import { Queue } from 'bullmq';
+
+import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
+import { RedisClientService } from 'src/engine/core-modules/redis-client/redis-client.service';
+
+@Injectable()
+export class WorkerHealthIndicator extends HealthIndicator {
+ constructor(private readonly redisClient: RedisClientService) {
+ super();
+ }
+
+ async isHealthy(key: string): Promise<HealthIndicatorResult> {
+ try {
+ const redis = this.redisClient.getClient();
+
+ // Get all queue names from our MessageQueue enum
+ // TODO: Consider getting queue names dynamically from Redis using:
+ // const queueKeys = await redis.keys('bull:*:meta');
+ // const queueNames = queueKeys.map(key => key.split(':')[1]);
+ // This would automatically detect all queues instead of relying on MessageQueue enum
+ // altough using MessageQueue makes more sense as it's a more type-safe way to handle queue names
+ const queues = Object.values(MessageQueue);
+
+ const workerStatuses = await Promise.all(
+ queues.map(async (queueName) => {
+ const queue = new Queue(queueName, { connection: redis });
+ const workers = await queue.getWorkers();
Greptile
greptile
logic: Queue instances should be closed after use to prevent memory leaks and connection issues
suggested fix
const queue = new Queue(queueName, { connection: redis });
const workers = await queue.getWorkers();
+ await queue.close();
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - the eslintCache grows indefinitely without cleanup. Consider adding a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely. Consider clearing old entries periodically.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: Global variables could cause memory leaks across multiple runs. Consider clearing changedFiles and eslintCache when the module is reloaded.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: changedFiles and eslintCache are module-level variables that persist between runs. This could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is declared but never cleared. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and never cleared. Could lead to memory leaks in long-running processes.
diff block
+---
+description: Rules for the buster_rest API directory
+globs: src/api/buster_rest/**/*
+---
+# Buster REST API Rules
+
+- Follow RESTful design principles
+- Use camelCase for variable and function names
+- Include proper error handling for all endpoints
+
+# API Request Standards
+- All API requests MUST use the `mainApi` axios instance for client-side fetching
+- Each GET request must have two versions:
+ - Client version using `mainApi`
+ - Server version using `serverFetch` with '_server' suffix
+- Import statements needed:
+ - `import { mainApi } from '../instances'`
+ - `import { serverFetch } from '@/api/createServerInstance'`
+- Response interfaces MUST be imported from '@/api/asset_interfaces/{namespace}'
+- Request functions should be async/await
+- Include proper TypeScript types for params and response
+- Use consistent parameter handling with defaults when needed
+
+Example request:
+```typescript
+import { mainApi } from '../instances';
+import { serverFetch } from '@/api/createServerInstance';
+import { BusterDatasetListItem } from '@/api/asset_interfaces/datasets';
+
+// Client-side fetch version
+export const getDatasets = async (params?: GetDatasetsParams) => {
+ const { page = 0, page_size = 1000, ...allParams } = params || {};
+ return mainApi
+ .get<BusterDatasetListItem[]>(`/datasets`, { params: { page, page_size, ...allParams } })
+ .then((res) => res.data);
+};
+
+// Server-side fetch version
+export const getDatasets_server = async (params?: GetDatasetsParams) => {
+ const { page = 0, page_size = 1000, ...allParams } = params || {};
+ return await serverFetch<BusterDatasetListItem[]>(`/datasets`, {
+ params: { page, page_size, ...allParams }
+ });
+};
+```
+
+# Interface Standards
+- Response interfaces should be defined in '@/api/asset_interfaces/{namespace}'
+- Local request parameter interfaces should be defined in local `interfaces.ts`
+- Keep interface naming consistent with the API response structure
+
+# React Query Standards
+- Each namespace must include a `queryRequests.ts` file
+- Use `useCreateReactQuery` and `useCreateReactMutation` from '@/api/createReactQuery'
+- Query hooks should be prefixed with 'useGet', 'useUpdate', 'useDelete', etc.
+- Each GET request should have a corresponding prefetch function
+- Prefetch functions should:
+ - Be named `prefetchGet{ResourceName}`
+ - Accept the same parameters as the query hook
+ - Accept an optional QueryClient parameter
+ - Use the server version of the request function (with '_server' suffix)
+- Always provide proper TypeScript types for query results
+- Use consistent pattern for queryKey construction
+
+Example React Query hook and prefetch:
+```typescript
+import { useCreateReactQuery } from '@/api/createReactQuery';
+import { QueryClient } from '@tanstack/react-query';
+
+export const useGetDatasets = (params?: Parameters<typeof getDatasets>[0]) => {
+ const queryFn = useMemoizedFn(() => {
+ return getDatasets(params);
+ });
+
+ const res = useCreateReactQuery<BusterDatasetListItem[]>({
+ queryKey: ['datasets', params || {}],
+ queryFn
+ });
+
+ return {
+ ...res,
+ data: res.data || []
+ };
+};
+
+export const prefetchGetDatasets = async (
+ params?: Parameters<typeof getDatasets>[0],
+ queryClientProp?: QueryClient
+) => {
+ const queryClient = queryClientProp || new QueryClient();
Greptile
greptile
logic: Creating a new QueryClient here could lead to memory leaks - consider requiring the queryClient parameter
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - the eslintCache grows indefinitely without cleanup
suggested fix
+ // Clear cache for files that are no longer changed
+ eslintCache.clear();
changedFiles = [...await listChangedFiles()];
changedFiles.forEach(file => {
if (!eslintCache.has(file)) {
eslintCache.set(file, null);
}
});
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
logic: Memory leak potential - eslintCache grows indefinitely as new files are processed but entries are never removed
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is never cleared between runs, which could lead to memory leaks in long-running processes
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: potential memory leak - eslintCache grows unbounded without cleanup
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is stored in module scope but never cleared between runs, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could cause memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is initialized but never cleared between runs, which could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is module-level and persists between runs. Could lead to memory leaks in long-running processes.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
Greptile
greptile
style: Memory leak potential - eslintCache grows indefinitely as new files are processed. Consider implementing a cache clearing mechanism.
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
-function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options) {
- const cli = new CLIEngine(options);
- const formatter = cli.getFormatter();
+async function runESLintOnFilesWithOptions(filePatterns, onlyChanged, options = {}) {
+ const defaultOptions = {
+ cache: true,
+ cacheLocation: '.eslintcache',
+ fix: false,
+ maxWarnings: 100,
+ ...options
+ };
+
+ const cli = new CLIEngine(defaultOptions);
+ const formatter = cli.getFormatter('stylish');
if (onlyChanged && changedFiles === null) {
- // Calculate lazily.
- changedFiles = [...listChangedFiles()];
+ try {
+ changedFiles = [...await listChangedFiles()];
+ changedFiles.forEach(file => {
+ if (!eslintCache.has(file)) {
+ eslintCache.set(file, null);
+ }
+ });
+ } catch (error) {
+ console.error('Error getting changed files:', error);
+ throw error;
+ }
}
Greptile
greptile
logic: Memory leak potential - changedFiles and eslintCache are never cleared between runs
diff block
+// src/fastgpt-view.tsx
+import { ActionPanel, Detail, Icon, getPreferenceValues } from "@raycast/api";
+import { useState, useEffect } from "react";
+import { searchWithFastGPT } from "./utils/kagiApi";
+import open from "open";
+
+interface FastGPTViewProps {
+ query: string;
+}
+
+interface ExtensionPreferences {
+ token: string;
+ apiKey: string;
+}
+
+export default function FastGPTView(props: FastGPTViewProps) {
+ const { token, apiKey }: ExtensionPreferences = getPreferenceValues();
+ const [isLoading, setIsLoading] = useState(true);
+ const [answer, setAnswer] = useState("");
+ const [references, setReferences] = useState<{ title: string; snippet: string; url: string }[]>([]);
+ const [error, setError] = useState("");
+
+ useEffect(() => {
+ async function fetchFastGPTAnswer() {
+ try {
+ setIsLoading(true);
+ const controller = new AbortController();
+ const result = await searchWithFastGPT(props.query, apiKey, controller.signal);
+
+ if (result) {
+ setAnswer(result.content || "");
+ setReferences(result.references || []);
+ }
+ } catch (err) {
+ console.error("Error fetching FastGPT answer:", err);
+ setError(`Failed to get answer: ${err}`);
+ } finally {
+ setIsLoading(false);
+ }
+ }
+ fetchFastGPTAnswer();
+ }, [props.query, apiKey]);
Greptile
greptile
logic: Consider adding a cleanup function in the useEffect to abort the controller on unmount. This prevents potential memory leaks or unwanted fetch continuations. ```suggestion useEffect(() => { async function fetchFastGPTAnswer() { try { setIsLoading(true); const controller = new AbortController(); const result = await searchWithFastGPT(props.query, apiKey, controller.signal); if (result) { setAnswer(result.content || ""); setReferences(result.references || []); } } catch (err) { console.error("Error fetching FastGPT answer:", err); setError(`Failed to get answer: ${err}`); } finally { setIsLoading(false); } } fetchFastGPTAnswer(); + return () => controller.abort(); }, [props.query, apiKey]); ```
diff block
const CLIEngine = require('eslint').CLIEngine;
const listChangedFiles = require('../shared/listChangedFiles');
-const allPaths = ['**/*.js'];
+const allPaths = ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'];
let changedFiles = null;
+let eslintCache = new Map();
Greptile
greptile
logic: eslintCache is not cleared between runs, which could lead to memory leaks in long-running processes
diff block
},
],
})),
- listeners(({ actions }) => ({
+ listeners(({ actions, cache }) => ({
createDataWarehouseSavedQuerySuccess: () => {
actions.loadDatabase()
},
+ loadDataWarehouseSavedQueriesSuccess: () => {
+ clearTimeout(cache.jobsRefreshTimeout)
+
+ cache.jobsRefreshTimeout = setTimeout(() => {
+ actions.loadDataWarehouseSavedQueries()
+ }, REFRESH_INTERVAL)
+ },
Greptile
greptile
logic: No cleanup of polling timeout when component unmounts. Add cleanup in beforeUnmount event to prevent memory leaks.
suggested fix
loadDataWarehouseSavedQueriesSuccess: () => {
clearTimeout(cache.jobsRefreshTimeout)
cache.jobsRefreshTimeout = setTimeout(() => {
actions.loadDataWarehouseSavedQueries()
}, REFRESH_INTERVAL)
},
+ beforeUnmount: () => {
clearTimeout(cache.jobsRefreshTimeout)
},