Compare commits

...

8 Commits

Author SHA1 Message Date
James Brunton
e5212d8391
Merge branch 'V2' into V2-eslint-no-empty-pattern 2025-09-04 17:39:55 +01:00
James Brunton
94e8f603ff
Enable ESLint no-unused-expressions rule (#4363)
# Description of Changes
Enable ESLint [no-unused-expressions
rule](https://typescript-eslint.io/rules/no-unused-expressions/)
2025-09-04 15:12:38 +00:00
James Brunton
74609e54fe
Enable ESLint prefer-const rule (#4349)
# Description of Changes
Enable ESLint [prefer-const
rule](https://eslint.org/docs/latest/rules/prefer-const)
2025-09-04 15:09:29 +00:00
James Brunton
003285506f
Enable ESLint no-useless-escape rule (#4344)
# Description of Changes
Enable ESLint [no-useless-escape
rule](https://eslint.org/docs/latest/rules/no-useless-escape)
2025-09-04 15:04:49 +00:00
James Brunton
cb9eaf6024
Merge branch 'V2' into V2-eslint-no-empty-pattern 2025-09-04 16:01:04 +01:00
James Brunton
6d3b08d9b6
Enable ESLint no-empty rule (#4342)
# Description of Changes
Enable ESLint [no-empty
rule](https://eslint.org/docs/latest/rules/no-empty)
2025-09-04 15:59:31 +01:00
James Brunton
543ce71a64
Merge branch 'V2' into V2-eslint-no-empty-pattern 2025-09-04 15:12:39 +01:00
James Brunton
295e682e03
Add linting to frontend (#4341)
# Description of Changes
There's no current linter running over our TypeScript code, which means
we've got a bunch of dead code and other code smells around with nothing
notifying us. This PR adds ESLint with the typescript-eslint plugin and
enables the recommended settings as a starting point for us.

I've disabled all of the failing rules for the scope of this PR, just to
get linting running without causing a massive diff. I'll follow up with
future PRs that enable the failing rules one by one.

Also updates our version of TypeScript, which introduces a new type
error in the code (which I've had to fix)
2025-09-04 14:08:28 +01:00
8 changed files with 25 additions and 29 deletions

View File

@ -8,23 +8,19 @@ export default defineConfig(
eslint.configs.recommended, eslint.configs.recommended,
tseslint.configs.recommended, tseslint.configs.recommended,
{ {
"ignores": [ ignores: [
"dist", // Contains 3rd party code "dist", // Contains 3rd party code
"public", // Contains 3rd party code "public", // Contains 3rd party code
], ],
}, },
{ {
"rules": { rules: {
"no-empty": "off", // Temporarily disabled until codebase conformant
"no-undef": "off", // Temporarily disabled until codebase conformant "no-undef": "off", // Temporarily disabled until codebase conformant
"no-useless-escape": "off", // Temporarily disabled until codebase conformant
"no-case-declarations": "off", // Temporarily disabled until codebase conformant "no-case-declarations": "off", // Temporarily disabled until codebase conformant
"prefer-const": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/ban-ts-comment": "off", // Temporarily disabled until codebase conformant "@typescript-eslint/ban-ts-comment": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-empty-object-type": "off", // Temporarily disabled until codebase conformant "@typescript-eslint/no-empty-object-type": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-explicit-any": "off", // Temporarily disabled until codebase conformant "@typescript-eslint/no-explicit-any": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-require-imports": "off", // Temporarily disabled until codebase conformant "@typescript-eslint/no-require-imports": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-unused-expressions": "off", // Temporarily disabled until codebase conformant
"@typescript-eslint/no-unused-vars": "off", // Temporarily disabled until codebase conformant "@typescript-eslint/no-unused-vars": "off", // Temporarily disabled until codebase conformant
}, },
} }

View File

@ -224,7 +224,7 @@ function getLicenseUrl(licenseType) {
// Handle complex SPDX expressions like "(MIT AND Zlib)" or "(MIT OR CC0-1.0)" // Handle complex SPDX expressions like "(MIT AND Zlib)" or "(MIT OR CC0-1.0)"
if (licenseType.includes('AND') || licenseType.includes('OR')) { if (licenseType.includes('AND') || licenseType.includes('OR')) {
// Extract the first license from compound expressions for URL // Extract the first license from compound expressions for URL
const match = licenseType.match(/\(?\s*([A-Za-z0-9\-\.]+)/); const match = licenseType.match(/\(?\s*([A-Za-z0-9\-.]+)/);
if (match && licenseUrls[match[1]]) { if (match && licenseUrls[match[1]]) {
return licenseUrls[match[1]]; return licenseUrls[match[1]];
} }

View File

@ -82,8 +82,8 @@ export function adjustFontSizeToFit(
return () => { return () => {
cancelAnimationFrame(raf); cancelAnimationFrame(raf);
try { ro.disconnect(); } catch {} try { ro.disconnect(); } catch { /* Ignore errors */ }
try { mo.disconnect(); } catch {} try { mo.disconnect(); } catch { /* Ignore errors */ }
}; };
} }

View File

@ -126,7 +126,7 @@ const ToolSearch = ({
key={id} key={id}
variant="subtle" variant="subtle"
onClick={() => { onClick={() => {
onToolSelect && onToolSelect(id); onToolSelect?.(id);
setDropdownOpen(false); setDropdownOpen(false);
}} }}
leftSection={<div style={{ color: "var(--tools-text-and-icon-color)" }}>{tool.icon}</div>} leftSection={<div style={{ color: "var(--tools-text-and-icon-color)" }}>{tool.icon}</div>}

View File

@ -35,8 +35,11 @@ function updatePosthogConsent(){
return; return;
} }
const optIn = (window.CookieConsent as any).acceptedCategory('analytics'); const optIn = (window.CookieConsent as any).acceptedCategory('analytics');
optIn? if (optIn) {
posthog.opt_in_capturing() : posthog.opt_out_capturing(); posthog.opt_in_capturing();
} else {
posthog.opt_out_capturing();
}
console.log("Updated analytics consent: ", optIn? "opted in" : "opted out"); console.log("Updated analytics consent: ", optIn? "opted in" : "opted out");
} }

View File

@ -182,7 +182,7 @@ export class EnhancedPDFProcessingService {
): Promise<ProcessedFile> { ): Promise<ProcessedFile> {
const arrayBuffer = await file.arrayBuffer(); const arrayBuffer = await file.arrayBuffer();
const pdf = await pdfWorkerManager.createDocument(arrayBuffer); const pdf = await pdfWorkerManager.createDocument(arrayBuffer);
try { try {
const totalPages = pdf.numPages; const totalPages = pdf.numPages;
@ -519,10 +519,7 @@ export class EnhancedPDFProcessingService {
this.notifyListeners(); this.notifyListeners();
// Force memory cleanup hint // Force memory cleanup hint
if (typeof window !== 'undefined' && window.gc) { setTimeout(() => window.gc?.(), 100);
let gc = window.gc;
setTimeout(() => gc(), 100);
}
} }
/** /**

View File

@ -73,7 +73,7 @@ class IndexedDBManager {
request.onsuccess = () => { request.onsuccess = () => {
const db = request.result; const db = request.result;
console.log(`Successfully opened ${config.name}`); console.log(`Successfully opened ${config.name}`);
// Set up close handler to clean up our references // Set up close handler to clean up our references
db.onclose = () => { db.onclose = () => {
console.log(`Database ${config.name} closed`); console.log(`Database ${config.name} closed`);
@ -87,13 +87,11 @@ class IndexedDBManager {
request.onupgradeneeded = (event) => { request.onupgradeneeded = (event) => {
const db = request.result; const db = request.result;
const oldVersion = event.oldVersion; const oldVersion = event.oldVersion;
console.log(`Upgrading ${config.name} from v${oldVersion} to v${config.version}`); console.log(`Upgrading ${config.name} from v${oldVersion} to v${config.version}`);
// Create or update object stores // Create or update object stores
config.stores.forEach(storeConfig => { config.stores.forEach(storeConfig => {
let store: IDBObjectStore;
if (db.objectStoreNames.contains(storeConfig.name)) { if (db.objectStoreNames.contains(storeConfig.name)) {
// Store exists - for now, just continue (could add migration logic here) // Store exists - for now, just continue (could add migration logic here)
console.log(`Object store '${storeConfig.name}' already exists`); console.log(`Object store '${storeConfig.name}' already exists`);
@ -109,7 +107,7 @@ class IndexedDBManager {
options.autoIncrement = storeConfig.autoIncrement; options.autoIncrement = storeConfig.autoIncrement;
} }
store = db.createObjectStore(storeConfig.name, options); const store = db.createObjectStore(storeConfig.name, options);
console.log(`Created object store '${storeConfig.name}'`); console.log(`Created object store '${storeConfig.name}'`);
// Create indexes // Create indexes
@ -168,7 +166,7 @@ class IndexedDBManager {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const deleteRequest = indexedDB.deleteDatabase(name); const deleteRequest = indexedDB.deleteDatabase(name);
deleteRequest.onerror = () => reject(deleteRequest.error); deleteRequest.onerror = () => reject(deleteRequest.error);
deleteRequest.onsuccess = () => { deleteRequest.onsuccess = () => {
console.log(`Deleted database: ${name}`); console.log(`Deleted database: ${name}`);
@ -224,4 +222,4 @@ export const DATABASE_CONFIGS = {
} as DatabaseConfig } as DatabaseConfig
} as const; } as const;
export const indexedDBManager = IndexedDBManager.getInstance(); export const indexedDBManager = IndexedDBManager.getInstance();

View File

@ -1,6 +1,6 @@
/** /**
* PDF.js Worker Manager - Centralized worker lifecycle management * PDF.js Worker Manager - Centralized worker lifecycle management
* *
* Prevents infinite worker creation by managing PDF.js workers globally * Prevents infinite worker creation by managing PDF.js workers globally
* and ensuring proper cleanup when operations complete. * and ensuring proper cleanup when operations complete.
*/ */
@ -86,7 +86,7 @@ class PDFWorkerManager {
const pdf = await loadingTask.promise; const pdf = await loadingTask.promise;
this.activeDocuments.add(pdf); this.activeDocuments.add(pdf);
this.workerCount++; this.workerCount++;
return pdf; return pdf;
} catch (error) { } catch (error) {
// If document creation fails, make sure to clean up the loading task // If document creation fails, make sure to clean up the loading task
@ -94,6 +94,7 @@ class PDFWorkerManager {
try { try {
loadingTask.destroy(); loadingTask.destroy();
} catch (destroyError) { } catch (destroyError) {
// Ignore errors
} }
} }
throw error; throw error;
@ -125,7 +126,7 @@ class PDFWorkerManager {
documentsToDestroy.forEach(pdf => { documentsToDestroy.forEach(pdf => {
this.destroyDocument(pdf); this.destroyDocument(pdf);
}); });
this.activeDocuments.clear(); this.activeDocuments.clear();
this.workerCount = 0; this.workerCount = 0;
} }
@ -166,9 +167,10 @@ class PDFWorkerManager {
try { try {
pdf.destroy(); pdf.destroy();
} catch (error) { } catch (error) {
// Ignore errors
} }
}); });
this.activeDocuments.clear(); this.activeDocuments.clear();
this.workerCount = 0; this.workerCount = 0;
} }
@ -182,4 +184,4 @@ class PDFWorkerManager {
} }
// Export singleton instance // Export singleton instance
export const pdfWorkerManager = PDFWorkerManager.getInstance(); export const pdfWorkerManager = PDFWorkerManager.getInstance();