From f756475f55dc229c032db3ef4e6eff9e7ad1cffb Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 11 Jan 2026 17:02:03 +0100 Subject: [PATCH 1/7] feat: Add CLI option --- test-avanza.csv | 3 +++ test-output.csv | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 test-avanza.csv create mode 100644 test-output.csv diff --git a/test-avanza.csv b/test-avanza.csv new file mode 100644 index 0000000..c902bf2 --- /dev/null +++ b/test-avanza.csv @@ -0,0 +1,3 @@ +Datum,Konto,Typ av transaktion,Värdepapper/beskrivning,Antal,Kurs,Avgift,Belopp,Valuta,ISIN +2024-01-01,ISK,Köp,AAPL,10,150,1,1501,USD,US0378331005 +2024-01-02,ISK,Sälj,AAPL,5,160,1,799,USD,US0378331005 diff --git a/test-output.csv b/test-output.csv new file mode 100644 index 0000000..103bb05 --- /dev/null +++ b/test-output.csv @@ -0,0 +1,3 @@ +Symbol,Trade Date,Purchase Price,Quantity,Commission,Comment +AAPL,20240101,150.0000,10,0.0000,Imported from Avanza +AAPL,20240102,160.0000,-5,0.0000,Imported from Avanza \ No newline at end of file From 2f07f5792440c8ba94b7703b7615758ce754711a Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 11 Jan 2026 17:08:56 +0100 Subject: [PATCH 2/7] test: add tests --- test-avanza.csv | 3 --- test-output.csv | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 test-avanza.csv delete mode 100644 test-output.csv diff --git a/test-avanza.csv b/test-avanza.csv deleted file mode 100644 index c902bf2..0000000 --- a/test-avanza.csv +++ /dev/null @@ -1,3 +0,0 @@ -Datum,Konto,Typ av transaktion,Värdepapper/beskrivning,Antal,Kurs,Avgift,Belopp,Valuta,ISIN -2024-01-01,ISK,Köp,AAPL,10,150,1,1501,USD,US0378331005 -2024-01-02,ISK,Sälj,AAPL,5,160,1,799,USD,US0378331005 diff --git a/test-output.csv b/test-output.csv deleted file mode 100644 index 103bb05..0000000 --- a/test-output.csv +++ /dev/null @@ -1,3 +0,0 @@ -Symbol,Trade Date,Purchase Price,Quantity,Commission,Comment -AAPL,20240101,150.0000,10,0.0000,Imported from Avanza -AAPL,20240102,160.0000,-5,0.0000,Imported from Avanza \ No newline at end of file From a8a1398cd389ffac321dfa0453c8f20b4105cabb Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 11 Jan 2026 17:22:54 +0100 Subject: [PATCH 3/7] feat: Add ticker resolver --- eslint.config copy.mjs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 eslint.config copy.mjs diff --git a/eslint.config copy.mjs b/eslint.config copy.mjs new file mode 100644 index 0000000..99e9e99 --- /dev/null +++ b/eslint.config copy.mjs @@ -0,0 +1,32 @@ +import { defineConfig, globalIgnores } from 'eslint/config'; +import nextVitals from 'eslint-config-next/core-web-vitals'; +import nextTs from 'eslint-config-next/typescript'; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + '.next/**', + 'out/**', + 'build/**', + 'next-env.d.ts', + 'node_modules/**', + ]), + { + rules: { + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + }, + ], + quotes: ['error', 'single', { avoidEscape: true }], + }, + }, +]); + +export default eslintConfig; From e230c9009e3fe6ea5e4f483d2e9d118fbee61ba7 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 11 Jan 2026 18:04:36 +0100 Subject: [PATCH 4/7] fix: Remove unnecessary file --- eslint.config copy.mjs | 32 -------------------------------- 1 file changed, 32 deletions(-) delete mode 100644 eslint.config copy.mjs diff --git a/eslint.config copy.mjs b/eslint.config copy.mjs deleted file mode 100644 index 99e9e99..0000000 --- a/eslint.config copy.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import { defineConfig, globalIgnores } from 'eslint/config'; -import nextVitals from 'eslint-config-next/core-web-vitals'; -import nextTs from 'eslint-config-next/typescript'; - -const eslintConfig = defineConfig([ - ...nextVitals, - ...nextTs, - // Override default ignores of eslint-config-next. - globalIgnores([ - // Default ignores of eslint-config-next: - '.next/**', - 'out/**', - 'build/**', - 'next-env.d.ts', - 'node_modules/**', - ]), - { - rules: { - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/no-unused-vars': [ - 'warn', - { - argsIgnorePattern: '^_', - varsIgnorePattern: '^_', - }, - ], - quotes: ['error', 'single', { avoidEscape: true }], - }, - }, -]); - -export default eslintConfig; From 0c16b7a90add409e0116033512a8f46a59d91574 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 11 Jan 2026 18:28:02 +0100 Subject: [PATCH 5/7] fix: Fix CLI version --- src/cache.ts | 8 ++++---- src/cli.ts | 40 ++++++++++++++++++++-------------------- src/resolvers/file.ts | 30 +++++++++++++++--------------- tests/cache.test.ts | 32 ++++++++++++++++---------------- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/cache.ts b/src/cache.ts index 8ab10e2..86aa95c 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -2,13 +2,13 @@ import fs from 'fs'; import { TickerCache, TickerResolution } from './enricher'; export class LocalFileTickerCache implements TickerCache { - private cache: Record = {}; + private cache: Record={}; private filePath: string; private dirty = false; private saveTimer: NodeJS.Timeout | null = null; constructor(filePath: string) { - this.filePath = filePath; + this.filePath=filePath; this.load(); // Ensure cache is saved on process exit @@ -20,7 +20,7 @@ export class LocalFileTickerCache implements TickerCache { private load() { if (fs.existsSync(this.filePath)) { try { - this.cache = JSON.parse(fs.readFileSync(this.filePath, 'utf8')); + this.cache=JSON.parse(fs.readFileSync(this.filePath, 'utf8')); } catch (e) { console.warn(`Failed to load ticker cache from ${this.filePath}`); } @@ -55,7 +55,7 @@ export class LocalFileTickerCache implements TickerCache { } } - async get(key: string): Promise { + async get(key: string): Promise { return this.cache[key]; } diff --git a/src/cli.ts b/src/cli.ts index 56b2881..14225f3 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -57,39 +57,39 @@ program .option('--no-yahoo', 'Disable automatic Yahoo Finance resolution') .option('--no-cache', 'Disable caching') .action(async (file, options) => { - const filePath = path.resolve(file); + const filePath=path.resolve(file); if (!fs.existsSync(filePath)) { console.error(`Error: File not found at ${filePath}`); process.exit(1); } - const csvData = fs.readFileSync(filePath, 'utf8'); - const parsedCsv = Papa.parse(csvData, { + const csvData=fs.readFileSync(filePath, 'utf8'); + const parsedCsv=Papa.parse(csvData, { header: true, skipEmptyLines: true, }); - if (parsedCsv.errors.length > 0) { + if (parsedCsv.errors.length>0) { console.warn('Warning: Some errors occurred during CSV parsing:'); console.warn(parsedCsv.errors); } - const data = parsedCsv.data as Record[]; - const transactions = data + const data=parsedCsv.data as Record[]; + const transactions=data .map((row) => parseTransaction(row, options.format as BrokerFormat)) - .filter((t): t is ParsedTransaction => t !== null); + .filter((t): t is ParsedTransaction => t!==null); - if (transactions.length === 0) { + if (transactions.length===0) { console.error('Error: No transactions could be parsed from the file.'); process.exit(1); } console.log(`Successfully parsed ${transactions.length} transactions.`); - let processedTransactions = transactions; + let processedTransactions=transactions; // resolver stacking - const resolvers = []; + const resolvers=[]; // 1. File Resolver (Highest priority if provided) if (options.tickerFile) { @@ -97,31 +97,31 @@ program } // 2. Yahoo ISIN Resolver (High accuracy) - if (options.yahoo !== false || options.yahooIsin) { + if (options.yahoo!==false||options.yahooIsin) { resolvers.push(new YahooISINResolver()); } // 3. Yahoo Name Resolver (Fallback) - if (options.yahoo !== false || options.yahooName) { + if (options.yahoo!==false||options.yahooName) { resolvers.push(new YahooNameResolver()); } - if (resolvers.length > 0) { + if (resolvers.length>0) { console.log( `Resolving tickers using: ${resolvers.map((r) => r.name).join(', ')}...` ); let cache; - if (options.cache !== false) { - cache = new LocalFileTickerCache(path.resolve(options.cache)); + if (options.cache!==false) { + cache=new LocalFileTickerCache(path.resolve(options.cache)); } - processedTransactions = await enrichTransactions(transactions, { + processedTransactions=await enrichTransactions(transactions, { resolvers, cache, }); - const resolvedCount = processedTransactions.filter( + const resolvedCount=processedTransactions.filter( (t) => t.ticker ).length; console.log( @@ -130,14 +130,14 @@ program } let result; - if (options.exporter === 'yahoo') { - result = YahooFinanceExporter.export(processedTransactions); + if (options.exporter==='yahoo') { + result=YahooFinanceExporter.export(processedTransactions); } else { console.error(`Error: Unknown exporter "${options.exporter}"`); process.exit(1); } - const outputPath = options.output || path.resolve(result.filename); + const outputPath=options.output||path.resolve(result.filename); fs.writeFileSync(outputPath, result.content); console.log(`Success! Exported to ${outputPath}`); }); diff --git a/src/resolvers/file.ts b/src/resolvers/file.ts index 1e0fe2f..8412ddb 100644 --- a/src/resolvers/file.ts +++ b/src/resolvers/file.ts @@ -4,8 +4,8 @@ import Papa from 'papaparse'; import { TickerResolver, TickerResolution } from '../enricher'; export class FileTickerResolver implements TickerResolver { - name = 'File Resolver'; - private mappings: Map = new Map(); + name='File Resolver'; + private mappings: Map=new Map(); constructor(filePath: string) { this.load(filePath); @@ -17,35 +17,35 @@ export class FileTickerResolver implements TickerResolver { return; } - const ext = path.extname(filePath).toLowerCase(); - const content = fs.readFileSync(filePath, 'utf8'); + const ext=path.extname(filePath).toLowerCase(); + const content=fs.readFileSync(filePath, 'utf8'); - if (ext === '.json') { + if (ext==='.json') { try { - const data = JSON.parse(content); + const data=JSON.parse(content); if (Array.isArray(data)) { data.forEach((item: any) => { - const key = item.isin || item.name; - if (key && item.ticker) this.mappings.set(key, item.ticker); + const key=item.isin||item.name; + if (key&&item.ticker) this.mappings.set(key, item.ticker); }); } else { Object.entries(data).forEach(([key, value]) => { - if (typeof value === 'string') this.mappings.set(key, value); + if (typeof value==='string') this.mappings.set(key, value); }); } } catch (e) { console.error(`Error parsing JSON ticker file: ${e}`); } - } else if (ext === '.csv') { + } else if (ext==='.csv') { try { - const results = Papa.parse(content, { + const results=Papa.parse(content, { header: true, skipEmptyLines: true, }); (results.data as any[]).forEach((row) => { - const key = row.isin || row.name || row.ISIN; - const ticker = row.ticker || row.Ticker; - if (key && ticker) this.mappings.set(key, ticker); + const key=row.isin||row.name||row.ISIN; + const ticker=row.ticker||row.Ticker; + if (key&&ticker) this.mappings.set(key, ticker); }); } catch (e) { console.error(`Error parsing CSV ticker file: ${e}`); @@ -54,7 +54,7 @@ export class FileTickerResolver implements TickerResolver { } async resolve(isin: string, name: string): Promise { - const ticker = this.mappings.get(isin) || this.mappings.get(name) || null; + const ticker=this.mappings.get(isin)||this.mappings.get(name)||null; return { ticker }; } } diff --git a/tests/cache.test.ts b/tests/cache.test.ts index 660f92f..c9c2b23 100644 --- a/tests/cache.test.ts +++ b/tests/cache.test.ts @@ -4,7 +4,7 @@ import fs from 'fs'; import path from 'path'; describe('LocalFileTickerCache', () => { - const tempCachePath = path.join(__dirname, 'temp_cache.json'); + const tempCachePath=path.join(__dirname, 'temp_cache.json'); afterEach(() => { if (fs.existsSync(tempCachePath)) { @@ -13,7 +13,7 @@ describe('LocalFileTickerCache', () => { }); it('should create cache file if it does not exist', async () => { - const cache = new LocalFileTickerCache(tempCachePath); + const cache=new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); cache.flush(); // Ensure file is written @@ -21,34 +21,34 @@ describe('LocalFileTickerCache', () => { }); it('should store and retrieve ticker resolutions', async () => { - const cache = new LocalFileTickerCache(tempCachePath); + const cache=new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); - const result = await cache.get('US0378331005'); + const result=await cache.get('US0378331005'); expect(result).toEqual({ ticker: 'AAPL', currency: 'USD' }); }); it('should return undefined for non-existent keys', async () => { - const cache = new LocalFileTickerCache(tempCachePath); - const result = await cache.get('NONEXISTENT'); + const cache=new LocalFileTickerCache(tempCachePath); + const result=await cache.get('NONEXISTENT'); expect(result).toBeUndefined(); }); it('should persist data across instances', async () => { - const cache1 = new LocalFileTickerCache(tempCachePath); + const cache1=new LocalFileTickerCache(tempCachePath); await cache1.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); cache1.flush(); // Ensure data is written to disk - const cache2 = new LocalFileTickerCache(tempCachePath); - const result = await cache2.get('US0378331005'); + const cache2=new LocalFileTickerCache(tempCachePath); + const result=await cache2.get('US0378331005'); expect(result).toEqual({ ticker: 'AAPL', currency: 'USD' }); }); it('should handle multiple entries', async () => { - const cache = new LocalFileTickerCache(tempCachePath); + const cache=new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); await cache.set('US30303M1027', { ticker: 'META', currency: 'USD' }); @@ -69,29 +69,29 @@ describe('LocalFileTickerCache', () => { }); it('should overwrite existing entries', async () => { - const cache = new LocalFileTickerCache(tempCachePath); + const cache=new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'EUR' }); - const result = await cache.get('US0378331005'); + const result=await cache.get('US0378331005'); expect(result?.currency).toBe('EUR'); }); it('should handle empty cache file gracefully', async () => { fs.writeFileSync(tempCachePath, '{}'); - const cache = new LocalFileTickerCache(tempCachePath); + const cache=new LocalFileTickerCache(tempCachePath); - const result = await cache.get('US0378331005'); + const result=await cache.get('US0378331005'); expect(result).toBeUndefined(); }); it('should handle corrupted cache file gracefully', async () => { fs.writeFileSync(tempCachePath, 'invalid json'); - const cache = new LocalFileTickerCache(tempCachePath); + const cache=new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); - const result = await cache.get('US0378331005'); + const result=await cache.get('US0378331005'); expect(result).toEqual({ ticker: 'AAPL', currency: 'USD' }); }); From 3267769ad00868f2e2c9a453b20521d91180df98 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 11 Jan 2026 18:33:28 +0100 Subject: [PATCH 6/7] chore: FIx format --- src/cache.ts | 8 ++++---- src/cli.ts | 40 ++++++++++++++++++++-------------------- src/resolvers/file.ts | 30 +++++++++++++++--------------- tests/cache.test.ts | 32 ++++++++++++++++---------------- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/cache.ts b/src/cache.ts index 86aa95c..8ab10e2 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -2,13 +2,13 @@ import fs from 'fs'; import { TickerCache, TickerResolution } from './enricher'; export class LocalFileTickerCache implements TickerCache { - private cache: Record={}; + private cache: Record = {}; private filePath: string; private dirty = false; private saveTimer: NodeJS.Timeout | null = null; constructor(filePath: string) { - this.filePath=filePath; + this.filePath = filePath; this.load(); // Ensure cache is saved on process exit @@ -20,7 +20,7 @@ export class LocalFileTickerCache implements TickerCache { private load() { if (fs.existsSync(this.filePath)) { try { - this.cache=JSON.parse(fs.readFileSync(this.filePath, 'utf8')); + this.cache = JSON.parse(fs.readFileSync(this.filePath, 'utf8')); } catch (e) { console.warn(`Failed to load ticker cache from ${this.filePath}`); } @@ -55,7 +55,7 @@ export class LocalFileTickerCache implements TickerCache { } } - async get(key: string): Promise { + async get(key: string): Promise { return this.cache[key]; } diff --git a/src/cli.ts b/src/cli.ts index 14225f3..56b2881 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -57,39 +57,39 @@ program .option('--no-yahoo', 'Disable automatic Yahoo Finance resolution') .option('--no-cache', 'Disable caching') .action(async (file, options) => { - const filePath=path.resolve(file); + const filePath = path.resolve(file); if (!fs.existsSync(filePath)) { console.error(`Error: File not found at ${filePath}`); process.exit(1); } - const csvData=fs.readFileSync(filePath, 'utf8'); - const parsedCsv=Papa.parse(csvData, { + const csvData = fs.readFileSync(filePath, 'utf8'); + const parsedCsv = Papa.parse(csvData, { header: true, skipEmptyLines: true, }); - if (parsedCsv.errors.length>0) { + if (parsedCsv.errors.length > 0) { console.warn('Warning: Some errors occurred during CSV parsing:'); console.warn(parsedCsv.errors); } - const data=parsedCsv.data as Record[]; - const transactions=data + const data = parsedCsv.data as Record[]; + const transactions = data .map((row) => parseTransaction(row, options.format as BrokerFormat)) - .filter((t): t is ParsedTransaction => t!==null); + .filter((t): t is ParsedTransaction => t !== null); - if (transactions.length===0) { + if (transactions.length === 0) { console.error('Error: No transactions could be parsed from the file.'); process.exit(1); } console.log(`Successfully parsed ${transactions.length} transactions.`); - let processedTransactions=transactions; + let processedTransactions = transactions; // resolver stacking - const resolvers=[]; + const resolvers = []; // 1. File Resolver (Highest priority if provided) if (options.tickerFile) { @@ -97,31 +97,31 @@ program } // 2. Yahoo ISIN Resolver (High accuracy) - if (options.yahoo!==false||options.yahooIsin) { + if (options.yahoo !== false || options.yahooIsin) { resolvers.push(new YahooISINResolver()); } // 3. Yahoo Name Resolver (Fallback) - if (options.yahoo!==false||options.yahooName) { + if (options.yahoo !== false || options.yahooName) { resolvers.push(new YahooNameResolver()); } - if (resolvers.length>0) { + if (resolvers.length > 0) { console.log( `Resolving tickers using: ${resolvers.map((r) => r.name).join(', ')}...` ); let cache; - if (options.cache!==false) { - cache=new LocalFileTickerCache(path.resolve(options.cache)); + if (options.cache !== false) { + cache = new LocalFileTickerCache(path.resolve(options.cache)); } - processedTransactions=await enrichTransactions(transactions, { + processedTransactions = await enrichTransactions(transactions, { resolvers, cache, }); - const resolvedCount=processedTransactions.filter( + const resolvedCount = processedTransactions.filter( (t) => t.ticker ).length; console.log( @@ -130,14 +130,14 @@ program } let result; - if (options.exporter==='yahoo') { - result=YahooFinanceExporter.export(processedTransactions); + if (options.exporter === 'yahoo') { + result = YahooFinanceExporter.export(processedTransactions); } else { console.error(`Error: Unknown exporter "${options.exporter}"`); process.exit(1); } - const outputPath=options.output||path.resolve(result.filename); + const outputPath = options.output || path.resolve(result.filename); fs.writeFileSync(outputPath, result.content); console.log(`Success! Exported to ${outputPath}`); }); diff --git a/src/resolvers/file.ts b/src/resolvers/file.ts index 8412ddb..1e0fe2f 100644 --- a/src/resolvers/file.ts +++ b/src/resolvers/file.ts @@ -4,8 +4,8 @@ import Papa from 'papaparse'; import { TickerResolver, TickerResolution } from '../enricher'; export class FileTickerResolver implements TickerResolver { - name='File Resolver'; - private mappings: Map=new Map(); + name = 'File Resolver'; + private mappings: Map = new Map(); constructor(filePath: string) { this.load(filePath); @@ -17,35 +17,35 @@ export class FileTickerResolver implements TickerResolver { return; } - const ext=path.extname(filePath).toLowerCase(); - const content=fs.readFileSync(filePath, 'utf8'); + const ext = path.extname(filePath).toLowerCase(); + const content = fs.readFileSync(filePath, 'utf8'); - if (ext==='.json') { + if (ext === '.json') { try { - const data=JSON.parse(content); + const data = JSON.parse(content); if (Array.isArray(data)) { data.forEach((item: any) => { - const key=item.isin||item.name; - if (key&&item.ticker) this.mappings.set(key, item.ticker); + const key = item.isin || item.name; + if (key && item.ticker) this.mappings.set(key, item.ticker); }); } else { Object.entries(data).forEach(([key, value]) => { - if (typeof value==='string') this.mappings.set(key, value); + if (typeof value === 'string') this.mappings.set(key, value); }); } } catch (e) { console.error(`Error parsing JSON ticker file: ${e}`); } - } else if (ext==='.csv') { + } else if (ext === '.csv') { try { - const results=Papa.parse(content, { + const results = Papa.parse(content, { header: true, skipEmptyLines: true, }); (results.data as any[]).forEach((row) => { - const key=row.isin||row.name||row.ISIN; - const ticker=row.ticker||row.Ticker; - if (key&&ticker) this.mappings.set(key, ticker); + const key = row.isin || row.name || row.ISIN; + const ticker = row.ticker || row.Ticker; + if (key && ticker) this.mappings.set(key, ticker); }); } catch (e) { console.error(`Error parsing CSV ticker file: ${e}`); @@ -54,7 +54,7 @@ export class FileTickerResolver implements TickerResolver { } async resolve(isin: string, name: string): Promise { - const ticker=this.mappings.get(isin)||this.mappings.get(name)||null; + const ticker = this.mappings.get(isin) || this.mappings.get(name) || null; return { ticker }; } } diff --git a/tests/cache.test.ts b/tests/cache.test.ts index c9c2b23..660f92f 100644 --- a/tests/cache.test.ts +++ b/tests/cache.test.ts @@ -4,7 +4,7 @@ import fs from 'fs'; import path from 'path'; describe('LocalFileTickerCache', () => { - const tempCachePath=path.join(__dirname, 'temp_cache.json'); + const tempCachePath = path.join(__dirname, 'temp_cache.json'); afterEach(() => { if (fs.existsSync(tempCachePath)) { @@ -13,7 +13,7 @@ describe('LocalFileTickerCache', () => { }); it('should create cache file if it does not exist', async () => { - const cache=new LocalFileTickerCache(tempCachePath); + const cache = new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); cache.flush(); // Ensure file is written @@ -21,34 +21,34 @@ describe('LocalFileTickerCache', () => { }); it('should store and retrieve ticker resolutions', async () => { - const cache=new LocalFileTickerCache(tempCachePath); + const cache = new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); - const result=await cache.get('US0378331005'); + const result = await cache.get('US0378331005'); expect(result).toEqual({ ticker: 'AAPL', currency: 'USD' }); }); it('should return undefined for non-existent keys', async () => { - const cache=new LocalFileTickerCache(tempCachePath); - const result=await cache.get('NONEXISTENT'); + const cache = new LocalFileTickerCache(tempCachePath); + const result = await cache.get('NONEXISTENT'); expect(result).toBeUndefined(); }); it('should persist data across instances', async () => { - const cache1=new LocalFileTickerCache(tempCachePath); + const cache1 = new LocalFileTickerCache(tempCachePath); await cache1.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); cache1.flush(); // Ensure data is written to disk - const cache2=new LocalFileTickerCache(tempCachePath); - const result=await cache2.get('US0378331005'); + const cache2 = new LocalFileTickerCache(tempCachePath); + const result = await cache2.get('US0378331005'); expect(result).toEqual({ ticker: 'AAPL', currency: 'USD' }); }); it('should handle multiple entries', async () => { - const cache=new LocalFileTickerCache(tempCachePath); + const cache = new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); await cache.set('US30303M1027', { ticker: 'META', currency: 'USD' }); @@ -69,29 +69,29 @@ describe('LocalFileTickerCache', () => { }); it('should overwrite existing entries', async () => { - const cache=new LocalFileTickerCache(tempCachePath); + const cache = new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'EUR' }); - const result=await cache.get('US0378331005'); + const result = await cache.get('US0378331005'); expect(result?.currency).toBe('EUR'); }); it('should handle empty cache file gracefully', async () => { fs.writeFileSync(tempCachePath, '{}'); - const cache=new LocalFileTickerCache(tempCachePath); + const cache = new LocalFileTickerCache(tempCachePath); - const result=await cache.get('US0378331005'); + const result = await cache.get('US0378331005'); expect(result).toBeUndefined(); }); it('should handle corrupted cache file gracefully', async () => { fs.writeFileSync(tempCachePath, 'invalid json'); - const cache=new LocalFileTickerCache(tempCachePath); + const cache = new LocalFileTickerCache(tempCachePath); await cache.set('US0378331005', { ticker: 'AAPL', currency: 'USD' }); - const result=await cache.get('US0378331005'); + const result = await cache.get('US0378331005'); expect(result).toEqual({ ticker: 'AAPL', currency: 'USD' }); }); From 9a414a313ad706a18772d95eac18d3b781c46998 Mon Sep 17 00:00:00 2001 From: Abhishek Jain Date: Sun, 11 Jan 2026 19:44:51 +0100 Subject: [PATCH 7/7] build: add prepare script for git installs --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 93a4039..9131a37 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "scripts": { "build": "tsc", + "prepare": "npm run build", "watch": "tsc -w", "type-check": "tsc --noEmit", "test": "vitest",