⚡ Zero-dependency plcbundle library exclusively for Bun

prepare & finalize

Changed files
+59 -5
examples
src
+23
examples/service-types.ts
···
··· 1 + const counts: Record<string, number>= {} 2 + 3 + export function process({ op }: { op: any }) { 4 + 5 + if (!op.operation?.services) { 6 + return 7 + } 8 + for (const key of Object.keys(op.operation.services)) { 9 + if (!counts[key]) { 10 + counts[key] = 1 11 + } else { 12 + counts[key] += 1 13 + } 14 + } 15 + } 16 + 17 + export function prepare() { 18 + return { counts } 19 + } 20 + 21 + export function finalize(results: any, { aggregate }: any) { 22 + console.log(Object.fromEntries(Object.entries(aggregate(results.map((r: any) => r.data.counts))).sort((a, b) => a[1] < b[1] ? 1 : -1))) 23 + }
+26 -5
src/plcbundle.ts
··· 309 310 // Determine mode based on what function is exported 311 let mode: 'detect' | 'process' = 'detect'; 312 if (module) { 313 try { 314 - const mod = await import(module); 315 // If module has 'process' function, use process mode 316 if (mod.process) { 317 mode = 'process'; ··· 337 onMatch 338 ); 339 } 340 - 341 // Load module if provided but single-threaded 342 - if (module && !callback) { 343 - const resolvedPath = module; 344 - const mod = await import(resolvedPath); 345 const userFn = mode === 'detect' ? (mod.detect || mod.default) : (mod.process || mod.default); 346 347 callback = (op, position, bundleNum, line) => { ··· 446 447 // Cleanup 448 workers.forEach(w => w.terminate()); 449 450 // Aggregate results 451 let totalOps = 0; ··· 475 matches: flush || mode === 'process' ? undefined : allMatches, 476 }; 477 } 478 479 /** 480 * Fast single-threaded processing (optimized)
··· 309 310 // Determine mode based on what function is exported 311 let mode: 'detect' | 'process' = 'detect'; 312 + let mod: any; 313 if (module) { 314 try { 315 + mod = await import(module); 316 // If module has 'process' function, use process mode 317 if (mod.process) { 318 mode = 'process'; ··· 338 onMatch 339 ); 340 } 341 + 342 // Load module if provided but single-threaded 343 + if (mod && !callback) { 344 const userFn = mode === 'detect' ? (mod.detect || mod.default) : (mod.process || mod.default); 345 346 callback = (op, position, bundleNum, line) => { ··· 445 446 // Cleanup 447 workers.forEach(w => w.terminate()); 448 + 449 + if (modulePath) { 450 + const mod = await import(modulePath); 451 + if (mod.finalize) { 452 + await mod.finalize(results, { aggregate: this.aggregate }); 453 + } 454 + } 455 456 // Aggregate results 457 let totalOps = 0; ··· 481 matches: flush || mode === 'process' ? undefined : allMatches, 482 }; 483 } 484 + 485 + private aggregate(objects: Array<{ [key: string]: number }>): { [key: string]: number } { 486 + const aggregatedDict: { [key: string]: number } = {}; 487 + 488 + for (const currentObj of objects) { 489 + for (const key in currentObj) { 490 + if (Object.prototype.hasOwnProperty.call(currentObj, key)) { 491 + aggregatedDict[key] = (aggregatedDict[key] || 0) + currentObj[key]; 492 + } 493 + } 494 + } 495 + 496 + return aggregatedDict; 497 + } 498 + 499 500 /** 501 * Fast single-threaded processing (optimized)
+10
src/worker.ts
··· 123 // Continue on error 124 } 125 } 126 127 // Send final result 128 self.postMessage({ ··· 130 totalOps, 131 totalBytes, 132 matches: flush ? [] : matches, 133 } as WorkerResult); 134 };
··· 123 // Continue on error 124 } 125 } 126 + 127 + let prepareResult: any; 128 + if (typeof mod.prepare === 'function') { 129 + try { 130 + prepareResult = await mod.prepare(); 131 + } catch (error) { 132 + // Silently ignore finalize errors 133 + } 134 + } 135 136 // Send final result 137 self.postMessage({ ··· 139 totalOps, 140 totalBytes, 141 matches: flush ? [] : matches, 142 + data: prepareResult || null 143 } as WorkerResult); 144 };