{"version":3,"file":"index.umd.production.min.cjs","sources":["../src/util.ts","../src/index.ts"],"sourcesContent":["import { INewLineCharacter } from './types';\nimport { EnumNewLineCharacter } from './index';\n\n/**\n * 處理換行字元選項，將各種輸入格式轉換為位元組陣列\n * Process new line character option, converting various input formats to byte array\n *\n * @param {INewLineCharacter} [newLineCharacter] - 換行字元設定 / New line character configuration\n * @returns {number[]} 換行字元的位元組陣列 / Byte array of new line characters\n */\nexport function handleOptionNewLineCharacter(newLineCharacter?: INewLineCharacter): number[]\n{\n\t// 若未提供換行字元，預設使用 LF (\\n) / If no new line character provided, default to LF\n\tif (!newLineCharacter)\n\t{\n\t\treturn [EnumNewLineCharacter.LF];\n\t}\n\t// 處理字串、陣列或 Buffer 類型 / Handle string, array, or Buffer types\n\telse if (typeof newLineCharacter !== 'number')\n\t{\n\t\tconst ls = [] as number[];\n\n\t\tfor (let i = 0; i < newLineCharacter.length; i++)\n\t\t{\n\t\t\tconst c = newLineCharacter[i];\n\n\t\t\t// 將字元轉換為其字元碼 / Convert character to its char code\n\t\t\tif (typeof c !== 'number')\n\t\t\t{\n\t\t\t\tls.push(c.charCodeAt(0))\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tls.push(c)\n\t\t\t}\n\t\t}\n\n\t\treturn ls\n\t}\n\n\t// 數字類型直接包裝為陣列 / Number type wrapped directly as array\n\treturn [newLineCharacter]\n}\n\n","/**\n * 逐行讀取檔案模組\n * Line by line file reading module\n *\n * 提供同步方式逐行讀取檔案，無需將整個檔案載入記憶體\n * Provides synchronous line-by-line file reading without loading the entire file into memory\n *\n * Created by user on 2020/5/29.\n */\n\nexport * from './types';\nexport * from './util';\nimport { IPathLike, IOptions } from './types';\nimport { readSync, closeSync, openSync } from 'fs';\nimport {\n\thandleOptionNewLineCharacter,\n} from './util';\nimport {\n\tbufferEndWithByBuffer,\n\tbufferStripEndWithByBuffer,\n\tsplitBufferByBuffer,\n} from '@lazy-node/util-buffer';\n\n/**\n * 換行字元列舉\n * New line character enumeration\n */\nexport const enum EnumNewLineCharacter\n{\n\t/** 換行 (Line Feed) - \\n */\n\tLF = 0x0a,\n\t/** 回車 (Carriage Return) - \\r */\n\tCR = 0x0d,\n}\n\n/**\n * 逐行讀取器類別\n * Line by line reader class\n *\n * 使用同步方式逐行讀取檔案內容，適合處理大型檔案\n * Reads file content line by line synchronously, suitable for large files\n */\nexport class LineByLine\n{\n\t/** 檔案路徑或檔案描述符 / File path or file descriptor */\n\t#file: IPathLike;\n\t/** 檔案描述符 / File descriptor */\n\t#fd: number;\n\t/** 讀取選項 / Read options */\n\t#options: IOptions;\n\t/** 換行字元 Buffer / New line character buffer */\n\treadonly #newLineCharacter: Buffer;\n\t/** 是否已到達檔案結尾 / Whether end of file is reached */\n\t#eofReached: boolean;\n\t/** 行快取陣列 / Line cache array */\n\t#linesCache: Buffer[];\n\t/** 當前檔案讀取位置 / Current file read position */\n\t#fdPosition: number;\n\t/** 每次讀取的區塊大小 / Chunk size for each read operation */\n\t#readChunk: number;\n\t/** 當前行號（從 0 開始）/ Current line number (0-based) */\n\t#lineNumber: number = -1;\n\n\t/**\n\t * 建立逐行讀取器實例\n\t * Create a line by line reader instance\n\t *\n\t * @param {IPathLike} file - 檔案路徑或檔案描述符 / File path or file descriptor\n\t * @param {IOptions} [options] - 讀取選項 / Read options\n\t */\n\tconstructor(file: IPathLike, options?: IOptions)\n\t{\n\t\tlet { readChunk, newLineCharacter } = (options = options || {});\n\n\t\t// 預設區塊大小為 1024 位元組 / Default chunk size is 1024 bytes\n\t\tif (!readChunk) readChunk = 1024;\n\n\t\tthis.#file = file;\n\t\tthis.#options = options;\n\n\t\t// 處理換行字元選項 / Process new line character option\n\t\tthis.#newLineCharacter = Buffer.from(handleOptionNewLineCharacter(newLineCharacter));\n\t\tthis.#readChunk = readChunk;\n\n\t\t// 驗證換行字元長度 / Validate new line character length\n\t\tif (this.#newLineCharacter.length <= 0)\n\t\t{\n\t\t\tthrow new TypeError(`newLineCharacter should have length > 0`)\n\t\t}\n\n\t\tthis._open();\n\t\tthis.reset();\n\t}\n\n\t/**\n\t * 開啟檔案並取得檔案描述符\n\t * Open file and obtain file descriptor\n\t * @protected\n\t */\n\tprotected _open()\n\t{\n\t\t// 若傳入的是數字，視為已開啟的檔案描述符 / If number is passed, treat as already opened file descriptor\n\t\tif (typeof this.#file === 'number')\n\t\t{\n\t\t\tthis.#fd = this.#file;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// 以唯讀模式開啟檔案 / Open file in read-only mode\n\t\t\tthis.#fd = openSync(this.#file, 'r');\n\t\t}\n\t}\n\n\t/**\n\t * 取得檔案路徑或描述符\n\t * Get file path or descriptor\n\t */\n\tget file()\n\t{\n\t\treturn this.#file\n\t}\n\n\t/**\n\t * 取得檔案描述符\n\t * Get file descriptor\n\t */\n\tget fd()\n\t{\n\t\treturn this.#fd\n\t}\n\n\t/**\n\t * 取得讀取選項\n\t * Get read options\n\t */\n\tget options()\n\t{\n\t\treturn this.#options\n\t}\n\n\t/**\n\t * 取得當前檔案讀取位置\n\t * Get current file read position\n\t */\n\tget fdPosition()\n\t{\n\t\treturn this.#fdPosition\n\t}\n\n\t/**\n\t * 取得換行字元 Buffer\n\t * Get new line character buffer\n\t */\n\tget newLineCharacter()\n\t{\n\t\treturn this.#newLineCharacter\n\t}\n\n\t/**\n\t * 檢查是否已到達檔案結尾\n\t * Check if end of file is reached\n\t */\n\tget eofReached()\n\t{\n\t\treturn this.#eofReached\n\t}\n\n\t/**\n\t * 取得當前行號（從 0 開始）\n\t * Get current line number (0-based)\n\t */\n\tget lineNumber()\n\t{\n\t\treturn this.#lineNumber\n\t}\n\n\t/**\n\t * 重置讀取器狀態，從頭開始讀取\n\t * Reset reader state to start from the beginning\n\t */\n\treset()\n\t{\n\t\tthis.#eofReached = false;\n\t\tthis.#linesCache = [];\n\t\tthis.#fdPosition = 0;\n\t\tthis.#lineNumber = -1;\n\t}\n\n\t/**\n\t * 關閉檔案描述符\n\t * Close file descriptor\n\t */\n\tclose()\n\t{\n\t\tthis.#fd && closeSync(this.#fd);\n\t\tthis.#fd = null;\n\t}\n\n\t/**\n\t * 從 Buffer 中提取行資料\n\t * Extract line data from buffer\n\t *\n\t * @param {Buffer} buffer - 原始 Buffer 資料 / Raw buffer data\n\t * @returns {Buffer[]} 分割後的行資料陣列 / Array of line data buffers\n\t * @protected\n\t */\n\tprotected _extractLines(buffer: Buffer)\n\t{\n\t\treturn splitBufferByBuffer(buffer, this.#newLineCharacter as any)\n\t};\n\n\t/**\n\t * 讀取一個區塊的資料並解析出行資料\n\t * Read a chunk of data and parse line data\n\t *\n\t * @param {Buffer} [lineLeftovers] - 上一區塊剩餘的未完整行資料 / Incomplete line data from previous chunk\n\t * @returns {number} 實際讀取的位元組數 / Number of bytes actually read\n\t * @protected\n\t */\n\tprotected _readChunk(lineLeftovers?: Buffer)\n\t{\n\t\tlet totalBytesRead = 0;\n\n\t\tlet bytesRead: number;\n\t\tconst buffers: Buffer[] = [];\n\n\t\t// 持續讀取直到找到換行字元或到達檔案結尾\n\t\t// Keep reading until new line character is found or end of file is reached\n\t\tdo\n\t\t{\n\t\t\tconst readBuffer = Buffer.alloc(this.#readChunk);\n\n\t\t\tbytesRead = readSync(this.#fd, readBuffer as any, 0, this.#readChunk, this.#fdPosition);\n\t\t\ttotalBytesRead = totalBytesRead + bytesRead;\n\n\t\t\tthis.#fdPosition = this.#fdPosition + bytesRead;\n\n\t\t\tbuffers.push(readBuffer);\n\t\t}\n\t\twhile (bytesRead && buffers[buffers.length - 1].indexOf(this.#newLineCharacter as any) === -1);\n\n\t\t// 合併所有讀取的區塊 / Concatenate all read chunks\n\t\tlet bufferData = Buffer.concat(buffers as any);\n\n\t\t// 若讀取的位元組數小於區塊大小，表示已到達檔案結尾\n\t\t// If bytes read is less than chunk size, it means end of file is reached\n\t\tif (bytesRead < this.#readChunk)\n\t\t{\n\t\t\tthis.#eofReached = true;\n\t\t\tbufferData = bufferData.slice(0, totalBytesRead);\n\t\t}\n\n\t\t// 將資料分割成行並加入快取 / Split data into lines and add to cache\n\t\tif (totalBytesRead)\n\t\t{\n\t\t\tthis.#linesCache = this._extractLines(bufferData);\n\n\t\t\t// 若有上一區塊的剩餘資料，與第一行合併\n\t\t\t// If there is leftover data from previous chunk, concatenate with first line\n\t\t\tif (lineLeftovers)\n\t\t\t{\n\t\t\t\tthis.#linesCache[0] = Buffer.concat([lineLeftovers as any, this.#linesCache[0] as any]);\n\t\t\t}\n\t\t}\n\n\t\treturn totalBytesRead;\n\t}\n\n\t/**\n\t * 讀取下一行資料\n\t * Read next line data\n\t *\n\t * @returns {Buffer | undefined} 行資料 Buffer，若已到結尾則回傳 undefined / Line data buffer, returns undefined if end is reached\n\t */\n\tnext()\n\t{\n\t\t// 檢查檔案是否已關閉或已到結尾 / Check if file is closed or end is reached\n\t\tif (!this.#fd || this.#eofReached && this.#linesCache.length === 0)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tlet line: Buffer;\n\t\tlet bytesRead: number;\n\n\t\t// 若快取為空，先讀取一個區塊 / If cache is empty, read a chunk first\n\t\tif (!this.#linesCache.length)\n\t\t{\n\t\t\tbytesRead = this._readChunk();\n\t\t}\n\n\t\t// 從快取中取出下一行 / Get next line from cache\n\t\tif (this.#linesCache.length)\n\t\t{\n\t\t\tline = this.#linesCache.shift();\n\n\t\t\t// 若行結尾沒有換行字元，表示這行跨區塊，需要繼續讀取\n\t\t\t// If line doesn't end with new line character, it spans across chunks, need to continue reading\n\t\t\tif (!bufferEndWithByBuffer(line, this.#newLineCharacter))\n\t\t\t{\n\t\t\t\tbytesRead = this._readChunk(line);\n\n\t\t\t\tif (bytesRead)\n\t\t\t\t{\n\t\t\t\t\tline = this.#linesCache.shift();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 若已到結尾且快取已空，關閉檔案 / If end is reached and cache is empty, close file\n\t\tif (this.#eofReached && this.#linesCache.length === 0)\n\t\t{\n\t\t\tthis.close();\n\t\t}\n\n\t\t// 移除行結尾的換行字元 / Remove trailing new line character from line\n\t\tif (line)\n\t\t{\n\t\t\tline = bufferStripEndWithByBuffer(line, this.#newLineCharacter, 0 - this.#newLineCharacter.length)\n\t\t}\n\n\t\tthis.#lineNumber++;\n\n\t\treturn line;\n\t}\n\n\t/**\n\t * 產生器函式，迭代讀取所有行\n\t * Generator function to iterate through all lines\n\t *\n\t * @returns {Generator<Buffer>} 行資料產生器 / Line data generator\n\t */\n\t* generator()\n\t{\n\t\tlet line: Buffer;\n\t\twhile (line = this.next())\n\t\t{\n\t\t\tyield line\n\t\t}\n\t}\n\n\t/**\n\t * 靜態產生器函式，建立實例並迭代讀取所有行\n\t * Static generator function to create instance and iterate through all lines\n\t *\n\t * @param {IPathLike} file - 檔案路徑或檔案描述符 / File path or file descriptor\n\t * @param {IOptions} [options] - 讀取選項 / Read options\n\t * @returns {Generator<Buffer>} 行資料產生器 / Line data generator\n\t */\n\tstatic* generator(file: IPathLike, options?: IOptions)\n\t{\n\t\tconst liner = new this(file, options)\n\t\tyield* liner.generator()\n\t}\n}\n\n// @ts-ignore\n// 為 CommonJS 相容性添加屬性 / Add properties for CommonJS compatibility\nif (process.env.TSDX_FORMAT !== 'esm')\n{\n\tObject.defineProperty(LineByLine, \"__esModule\", { value: true });\n\n\tObject.defineProperty(LineByLine, 'LineByLine', { value: LineByLine });\n\tObject.defineProperty(LineByLine, 'default', { value: LineByLine });\n\n\tObject.defineProperty(LineByLine, \"handleOptionNewLineCharacter\", { value: handleOptionNewLineCharacter });\n\n\t// @ts-ignore\n\tObject.defineProperty(LineByLine, \"EnumNewLineCharacter\", { value: EnumNewLineCharacter });\n}\n\nexport default LineByLine\n"],"names":["handleOptionNewLineCharacter","newLineCharacter","ls","i","length","c","push","charCodeAt","EnumNewLineCharacter","exports","LineByLine","file","fd","options","eofReached","linesCache","fdPosition","readChunk","lineNumber","constructor","this","Buffer","from","TypeError","_open","reset","openSync","close","closeSync","_extractLines","buffer","splitBufferByBuffer","_readChunk","lineLeftovers","bytesRead","totalBytesRead","buffers","readBuffer","alloc","readSync","indexOf","bufferData","concat","slice","next","line","shift","bufferEndWithByBuffer","bufferStripEndWithByBuffer","generator","liner","Object","defineProperty","value"],"mappings":"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"}