UNPKG

excel-sheet-to-json

Version:

A TypeScript/JavaScript library that converts Excel files to JSON with custom header mapping. Works in both Node.js and browser environments.

172 lines (168 loc) 6.73 kB
import { read, utils } from 'xlsx'; function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _createForOfIteratorHelperLoose(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (t) return (t = t.call(r)).next.bind(t); if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var o = 0; return function () { return o >= r.length ? { done: !0 } : { done: !1, value: r[o++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function parse(fileBuffer, // Buffer | ArrayBuffer (타입 추정) options) { // 1. Buffer 읽기 및 워크북 생성 var workbook = read(fileBuffer, { type: 'buffer' }); var sheetName = workbook.SheetNames[0]; var worksheet = workbook.Sheets[sheetName]; // 2. 빈 행 생략 문제 해결: range 옵션 사용 var sheetRef = worksheet['!ref']; if (!sheetRef) { return { originHeaderNames: [], fields: [], header: {}, body: [] }; // 💡 header 초기값 변경 } var arrayData = utils.sheet_to_json(worksheet, { header: 1, range: sheetRef, raw: true }); // 3. 인덱스 계산 (1-based -> 0-based) var headerRowIndex = options.headerStartRowNumber - 1; var bodyRowIndex = options.bodyStartRowNumber - 1; // 4. 원본 헤더 추출 var rawHeaders = arrayData[headerRowIndex] || []; var originHeaderNames = rawHeaders.map(function (name) { return name ? String(name).trim() : ''; }).filter(function (name) { return name !== ''; }); // 💡 5. fields 배열 및 header 객체 생성 (수정된 로직) var fields = []; // 매핑 성공한 DB 키 목록 (순서 보존용) var header = {}; // { DB 키: 원본 헤더 이름 } originHeaderNames.forEach(function (originName) { var dbKey = options.headerNameToKey[originName]; // 매핑 테이블에 존재하는 헤더만 처리 if (dbKey) { fields.push(dbKey); header[dbKey] = originName; // 💡 DB 키를 Key로, 원본 헤더 이름을 Value로 저장 } }); // 6. 바디 데이터 (JSON 배열) 변환 var body = []; for (var i = bodyRowIndex; i < arrayData.length; i++) { var row = arrayData[i]; var jsonObject = {}; var isEmptyRow = true; // 7. 각 열을 반복하며 JSON 객체 생성 // 💡 arrayData의 모든 열을 반복하는 것이 아니라, fields 배열의 순서대로 반복해야 합니다. // 문제: 현재 fields 배열의 순서와 row[j]의 인덱스가 일치한다고 가정한 로직은 // 매핑되지 않은 헤더가 중간에 있을 경우 깨질 수 있습니다. // 💡 해결책: 매핑 성공한 DB 키(fields) 순서대로 데이터를 찾아 할당합니다. // 이 문제를 해결하기 위해, arrayData[headerRowIndex]에서 DB 키에 해당하는 // 원본 헤더의 인덱스를 찾아야 합니다. var isRowDataValid = true; var _loop = function _loop() { var dbKey = _step.value; // 현재 DB 키에 매핑된 원본 헤더 이름 var originName = header[dbKey]; // 원본 헤더 이름이 arrayData[headerRowIndex]에서 몇 번째 인덱스(열)에 있는지 찾습니다. // Array.prototype.indexOf를 사용하여 찾습니다. var colIndex = rawHeaders.findIndex(function (name) { return String(name).trim() === originName; }); if (colIndex !== -1) { var cellValue = row[colIndex] || ''; if (cellValue !== null && cellValue !== undefined && String(cellValue).trim() !== '') { isEmptyRow = false; } jsonObject[dbKey] = cellValue; } else { // 이 필드는 헤더 행에 존재했지만, 어떤 이유로 찾을 수 없다면 오류로 간주할 수 있습니다. // 여기서는 매핑을 건너뛰고 다음 필드로 넘어갑니다. isRowDataValid = false; } }; for (var _iterator = _createForOfIteratorHelperLoose(fields), _step; !(_step = _iterator()).done;) { _loop(); } // 8. 모든 값이 빈 문자열이거나 null인 행은 건너뜁니다. // 💡 fields 배열을 기반으로 루프를 돌았으므로, row.length 대신 fields.length로 제어됩니다. if (!isEmptyRow && isRowDataValid) { body.push(jsonObject); } } return { originHeaderNames: originHeaderNames, fields: fields, header: header, body: body }; } /** * 브라우저 환경에서의 File 객체를 ArrayBuffer로 변환합니다. * @param file - 브라우저 환경에서의 File 객체 * @returns ArrayBuffer로 변환된 파일 데이터 */ function fileToArrayBufferInClient(file) { // 파일이 유효한지 확인 if (!file || !(file instanceof File)) { return Promise.reject(new Error('Input must be a valid File object.')); } return new Promise(function (resolve, reject) { var reader = new FileReader(); // 1. 성공적으로 읽었을 때 처리 reader.onload = function (event) { var _event$target; // event.target.result는 readAsArrayBuffer 호출 시 ArrayBuffer 타입입니다. var arrayBuffer = (_event$target = event.target) == null ? void 0 : _event$target.result; if (arrayBuffer instanceof ArrayBuffer) { resolve(arrayBuffer); } else { reject(new Error('File reading completed, but result is not ArrayBuffer.')); } }; // 2. 파일 읽기 실패 시 처리 reader.onerror = function (error) { reject(error); }; // 3. 파일 읽기 시작 (ArrayBuffer 형태로) reader.readAsArrayBuffer(file); }); } function arrayBufferToBufferInClient(arrayBuffer) { return Buffer.from(arrayBuffer); } var ExcelSheetToJson = { parse: parse, fileToArrayBufferInClient: fileToArrayBufferInClient, arrayBufferToBufferInClient: arrayBufferToBufferInClient }; export default ExcelSheetToJson; export { arrayBufferToBufferInClient, fileToArrayBufferInClient, parse }; //# sourceMappingURL=excel-sheet-to-json.esm.js.map