fetch-text-by-line.ts 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import type { BunFile } from 'bun';
  2. import { fetchWithRetry, defaultRequestInit } from './fetch-retry';
  3. import { TextLineStream } from './text-line-transform-stream';
  4. import { PolyfillTextDecoderStream } from './text-decoder-stream';
  5. import { processLine } from './process-line';
  6. // function createTextLineStreamFromStreamSource(stream: ReadableStream<Uint8Array>) {
  7. // return stream
  8. // .pipeThrough(new PolyfillTextDecoderStream())
  9. // .pipeThrough(new TextLineStream());
  10. // }
  11. const decoder = new TextDecoder('utf-8');
  12. async function *createTextLineAsyncGeneratorFromStreamSource(stream: ReadableStream<Uint8Array>): AsyncGenerator<string> {
  13. let buf = '';
  14. for await (const chunk of stream) {
  15. const chunkStr = decoder.decode(chunk).replaceAll('\r\n', '\n');
  16. for (let i = 0, len = chunkStr.length; i < len; i++) {
  17. const char = chunkStr[i];
  18. if (char === '\n') {
  19. yield buf;
  20. buf = '';
  21. } else {
  22. buf += char;
  23. }
  24. }
  25. }
  26. if (buf) {
  27. yield buf;
  28. }
  29. }
  30. export function readFileByLine(file: string | URL | BunFile) {
  31. if (typeof file === 'string') {
  32. file = Bun.file(file);
  33. } else if (!('writer' in file)) {
  34. file = Bun.file(file);
  35. }
  36. return createTextLineAsyncGeneratorFromStreamSource(file.stream());
  37. }
  38. export function createReadlineInterfaceFromResponse(this: void, resp: Response) {
  39. if (!resp.body) {
  40. throw new Error('Failed to fetch remote text');
  41. }
  42. if (resp.bodyUsed) {
  43. throw new Error('Body has already been consumed.');
  44. }
  45. return createTextLineAsyncGeneratorFromStreamSource(resp.body);
  46. }
  47. export function fetchRemoteTextByLine(url: string | URL) {
  48. return fetchWithRetry(url, defaultRequestInit).then(createReadlineInterfaceFromResponse);
  49. }
  50. export async function readFileIntoProcessedArray(file: string | URL | BunFile) {
  51. if (typeof file === 'string') {
  52. file = Bun.file(file);
  53. } else if (!('writer' in file)) {
  54. file = Bun.file(file);
  55. }
  56. const content = await file.text();
  57. return content.split('\n').filter(processLine);
  58. }