"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Types: () => Types_exports, dataToLines: () => dataToLines, fieldFormatter: () => field_formatter_default, getAsyncFlatFileCreator: () => getAsyncFlatFileCreator, getAsyncFlatFileReader: () => getAsyncFlatFileReader, linesToData: () => linesToData, parseLine: () => parseLine, rowFormatter: () => row_formatter_default }); module.exports = __toCommonJS(src_exports); // src/Types.ts var Types_exports = {}; __export(Types_exports, { assertFieldSpec: () => assertFieldSpec }); var import_lodash = __toESM(require("lodash"), 1); // src/utils.ts function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n); } var checkValidPaddingPosition = (paddingPosition) => { if (!["start", "end"].includes(paddingPosition)) { throw new Error(`padding position "${paddingPosition}" not allowed`); } return paddingPosition; }; var getPaddingPositionOrDef = (paddingPosition, def) => checkValidPaddingPosition(paddingPosition ? paddingPosition : def); var checkValidSymbol = (sym) => { if (sym.length > 1) { throw new Error("paddingSymbol cannot have length > 1"); } return sym; }; var getPaddingSymbol = (sym) => checkValidSymbol(sym || " "); var getFillStringOfSymbol = (sym) => (length) => { return length > 0 ? sym.repeat(length) : ""; }; var getPadder = (position) => (str, fill) => { return position === "start" ? fill + str : str + fill; }; // src/Types.ts function assertFieldSpec(spec, type) { if (!spec) { throw new Error("map is null or undefined"); } if (typeof spec !== "object") { throw new Error("map is not an object"); } if (import_lodash.default.isEmpty(spec)) { throw new Error("map object is empty"); } if (typeof spec.name === "undefined") { throw new Error("map field name is required"); } if (typeof spec.size === "undefined") { throw new Error("map size is required"); } if (spec.size <= 0) { throw new Error("map size must be greater than 0"); } if (isNumeric(spec.type)) { throw new Error(`map field [${spec.name}] type not could be numeric`); } if (type) { if (type !== spec.type) { throw new Error( `map field [${spec.name}] is for ${spec.type}, not the required ${type}` ); } if (type === "float" && typeof spec.precision === "undefined") { throw new Error("float precision must be specified"); } } } // src/date-formatter.ts var import_lodash2 = __toESM(require("lodash"), 1); var import_moment = __toESM(require("moment"), 1); var paddingDefault = "end"; var defaultFormat = { utc: false }; var getFormattedDateString = (date, opts) => { const base = (0, import_moment.default)(date); if (!base.isValid()) { throw new Error(`Invalid date ${date}`); } const convention = opts.utc ? base.utc() : base; if (!opts.dateFormat) { return convention.toISOString(); } return convention.format(opts.dateFormat); }; function assertDateFieldValue(d, fieldName) { if (d !== null && typeof d !== "undefined" && typeof d !== "string" && typeof d.toISOString === "undefined" && typeof d.year === "undefined") { throw new Error( `Value for date field ${fieldName} must be a date or a string representation of a date` ); } } var dateFormatter = (map, data) => { assertFieldSpec(map); data = data === void 0 || data === null ? map.default : data; let resDate; if (data === void 0) { throw new Error("No value supplied and no default set"); } else if (data === null) { resDate = ""; } else { assertDateFieldValue(data, map.name); const format = { ...defaultFormat, ...map.format }; resDate = data ? getFormattedDateString(data, format) : ""; if (import_lodash2.default.size(resDate) > map.size) { throw new Error(`Date ${resDate} exceed size ${map.size}`); } } return getPadder( getPaddingPositionOrDef(map.paddingPosition, paddingDefault) )( resDate, getFillStringOfSymbol(getPaddingSymbol(map.paddingSymbol))( map.size - import_lodash2.default.size(resDate) ) ); }; var date_formatter_default = dateFormatter; // src/float-formatter.ts var import_lodash3 = __toESM(require("lodash"), 1); var paddingDefault2 = "start"; var floatFormatter = (map, data = null) => { assertFieldSpec(map, "float"); data = data === void 0 || data === null ? map.default : data; let str; if (data === void 0) { throw new Error("No value supplied and no default set"); } else if (data === null) { str = ""; } else { if (!isNumeric(data)) { throw new Error(`field [${map.name}] has not compatible type`); } const num = Number(data); const precision = !map.precision ? 0 : map.precision; if (map.dotNotation) { str = num.toFixed(precision).toString(); } else { str = Math.trunc(num * Math.pow(10, precision)).toString(); } if (import_lodash3.default.size(str) > map.size) { throw new Error(`Value ${str} exceed size ${map.size}`); } } return getPadder( getPaddingPositionOrDef(map.paddingPosition, paddingDefault2) )( str, getFillStringOfSymbol(getPaddingSymbol(map.paddingSymbol))( map.size - import_lodash3.default.size(str) ) ); }; var float_formatter_default = floatFormatter; // src/integer-formatter.ts var import_lodash4 = __toESM(require("lodash"), 1); var paddingDefault3 = "start"; var integerFormatter = (map, data = null) => { assertFieldSpec(map, "integer"); data = data === void 0 || data === null ? map.default : data; let num; if (data === void 0) { throw new Error("No value supplied and no default set"); } else if (data === null) { num = ""; } else { if (!isNumeric(data)) { throw new Error("field has not compatible type"); } num = Math.round(data).toString(); if (import_lodash4.default.size(num) > map.size) { throw new Error(`Value ${num} exceed size ${map.size}`); } } return getPadder( getPaddingPositionOrDef(map.paddingPosition, paddingDefault3) )( num, getFillStringOfSymbol(getPaddingSymbol(map.paddingSymbol))( map.size - import_lodash4.default.size(num) ) ); }; var integer_formatter_default = integerFormatter; // src/string-formatter.ts var import_lodash5 = __toESM(require("lodash"), 1); // src/Errors.ts var FlatFileError = class extends Error { code; constructor(msg, code) { super(msg); this.code = "ER_FLAT_FILE" + (code ? `_${code}` : ""); } }; var FlatFileReadLineError = class extends FlatFileError { constructor(msg, lineData) { super(msg, "READ_LINE"); this.lineData = lineData; } }; var FlatFileReadFieldTypeError = class extends FlatFileError { constructor(msg, fieldName) { super(msg, "READ_FIELD_TYPE"); this.fieldName = fieldName; } }; var FlatFileEnumError = class extends FlatFileError { constructor(msg, fieldName) { super(msg, "BAD_ENUM"); this.fieldName = fieldName; } }; // src/string-formatter.ts var paddingDefault4 = "end"; var stringFormatter = (map, data) => { assertFieldSpec(map, "string"); if (map.straight && isNumeric(data)) { throw new Error("field has not compatible type"); } data = data === void 0 || data === null ? map.default : data; let str; if (data === void 0) { throw new Error("No value supplied and no default set"); } else if (data === null) { str = ""; } else { str = data; if (!map.preserveEmptySpace) { str = str.trim(); } if (map.enum !== void 0) { let i = Object.values(map.enum).indexOf(str); if (i > -1) { str = Object.keys(map.enum)[i]; } else { i = Object.keys(map.enum).indexOf(str); if (i === -1) { throw new FlatFileEnumError( `Value for field '${map.name}' should have been one of the accepted values ["${Object.values( map.enum ).join('", "')}"]${typeof map.default !== "undefined" && map.default === null ? " or null" : ""}, but you passed '${str}'`, map.name ); } } } if (str.length > map.size) { throw new Error(`Value ${str} exceed size ${map.size}`); } } return getPadder( getPaddingPositionOrDef(map.paddingPosition, paddingDefault4) )( str.substring(0, map.size), getFillStringOfSymbol(getPaddingSymbol(map.paddingSymbol))( map.size - import_lodash5.default.size(str) ) ); }; var string_formatter_default = stringFormatter; // src/field-formatter.ts var fieldFormatter = (map, data) => { try { assertFieldSpec(map); const fieldName = map.name; switch (map.type) { case "string": return string_formatter_default(map, data[fieldName]); case "integer": return integer_formatter_default(map, data[fieldName]); case "float": return float_formatter_default(map, data[fieldName]); case "date": return date_formatter_default(map, data[fieldName]); case void 0: return string_formatter_default( { ...map, type: "string" }, data[fieldName] ); default: throw new Error("required field type is not present"); } } catch (e) { if (map) { e.message = `Field ${map.name}: ${e.message} (data: ${data ? `'${data[map.name]}'` : "unknown"})`; } throw e; } }; var field_formatter_default = fieldFormatter; // src/flat-file-reader.ts var import_moment2 = __toESM(require("moment"), 1); var import_node_fs = __toESM(require("fs"), 1); var getAsyncFlatFileReader = (fields, options = {}) => { return (path) => { return new Promise((res, rej) => { import_node_fs.default.readFile( path, options, (err, contents) => { if (err) { rej(err); } try { const data = typeof contents === "string" ? contents : contents.toString(options.encoding || "utf8"); res(linesToData(data, fields, options)); } catch (e) { rej(e); } } ); }); }; }; var linesToData = (contents, fields, options = {}) => { const lineLength = fields.reduce((n, f) => n + f.size, 0); const results = []; const lines = Array.isArray(contents) ? contents : contents.split(/[\n\r]+/); for (let i = 0; i < lines.length; i++) { if (lines[i] !== "") { results.push( parseLine( lines[i], fields, options.throwErrors !== false ? lineLength : void 0 ) ); } } return results; }; var parseLine = (line, fields, expectedLineLength) => { if (typeof expectedLineLength === "number" && line.length !== expectedLineLength) { throw new FlatFileReadLineError( `FlatFileReader: The given line must be ${expectedLineLength} characters long according to the data specification. The current line is ${line.length} characters long.`, line ); } const result = {}; let cursor = 0; for (let fieldNum = 0; fieldNum < fields.length; fieldNum++) { const fieldSpec = fields[fieldNum]; const fieldVal = line.slice(cursor, cursor + fieldSpec.size); cursor += fieldSpec.size; result[fieldSpec.name] = trim(fieldVal, fieldSpec); } return interpret(result, fields); }; var trim = (val, fieldSpec) => { const paddingChar = fieldSpec.paddingSymbol || " "; const pattern = fieldSpec.paddingPosition === "start" || typeof fieldSpec.paddingPosition === "undefined" && (fieldSpec.type === "integer" || fieldSpec.type === "float") ? new RegExp(`^${paddingChar}+`) : new RegExp(`${paddingChar}+$`); val = val.replace(pattern, ""); if (fieldSpec.type === "integer" || fieldSpec.type === "float") { val = val.trim(); } return val; }; var interpret = (result, fields) => { for (let i = 0; i < fields.length; i++) { const field = fields[i]; if (result[field.name] === "") { if (typeof field.default !== "undefined") { result[field.name] = field.default; continue; } else { throw new FlatFileReadFieldTypeError( `Field '${field.name}' is required, but not defined`, field.name ); } } const getInt = (val, fieldName) => { if (val.match(/^-?[0-9]+$/) || val.match(/^-?[0-9]+e[0-9]+$/)) { return Number(val); } else { throw new FlatFileReadFieldTypeError( `Field '${fieldName}' is supposed to be an integer but is not. Actual value: ${val}`, fieldName ); } }; switch (field.type) { case "integer": { result[field.name] = getInt(result[field.name], field.name); break; } case "float": { let val = null; if (field.dotNotation) { if (result[field.name].match(/^-?[0-9]*\.?[0-9]+$/)) { val = parseFloat(result[field.name]); } else if (result[field.name].match(/^-?[0-9]+(\.[0-9]+)?e[0-9]+$/)) { val = JSON.parse(result[field.name]); } } else { val = getInt(result[field.name], field.name) / Math.pow(10, field.precision || 0); } if (val === null) { throw new FlatFileReadFieldTypeError( `Field '${field.name}' is supposed to be a float but is not. Actual value: ` + result[field.name], field.name ); } result[field.name] = val; break; } case "date": { result[field.name] = (0, import_moment2.default)( result[field.name], field.format && field.format.dateFormat ? field.format.dateFormat : void 0 ); break; } case "string": case void 0: { if (field.enum !== void 0) { if (field.enum[result[field.name]] !== void 0) { result[field.name] = field.enum[result[field.name]]; } else { throw new FlatFileEnumError( `Incoming value for field '${field.name}' should have been one of the accepted enum keys ["${Object.keys(field.enum).join('", "')}"]${typeof field.default !== "undefined" && field.default === null ? " or null" : ""}, but found '${result[field.name]}'`, field.name ); } } } } } return result; }; // src/file-append-promise.ts var import_promises = __toESM(require("fs/promises"), 1); var defaultOptions = { encoding: "utf8", mode: 438, flag: "a" }; var prepareOptions = (opts) => { let options = { ...defaultOptions }; options = opts.encoding ? { ...options, encoding: opts.encoding } : options; options = opts.mode ? { ...options, mode: opts.mode } : options; options = opts.flag ? { ...options, flag: opts.flag } : options; return { ...options }; }; var fileAppendPromise = async (path, data, options) => { if (options && options.encoding) { import_promises.default.appendFile(path, data, prepareOptions(options)); return; } import_promises.default.appendFile(path, data); }; var file_append_promise_default = fileAppendPromise; // src/row-formatter.ts var import_lodash6 = __toESM(require("lodash"), 1); var defaultOptions2 = { rowEnd: "" }; var prepareToConcatData = (data) => (acc, field, i) => { try { return acc + field_formatter_default(field, data); } catch (e) { e.message = `Row Index ${i}: ${e.message}`; throw e; } }; var rowFormatter = (maps, data, options) => { if (typeof maps !== "object") { throw new Error("mapping is not an array"); } if (import_lodash6.default.isEmpty(maps)) { throw new Error("mapping is empty"); } if (!data) { throw new Error("data is null"); } if (typeof data !== "object") { throw new Error("data is not an object"); } const opt = { ...defaultOptions2, ...options }; return maps.reduce(prepareToConcatData(data), "") + opt.rowEnd; }; var row_formatter_default = rowFormatter; // src/get-async-flat-file-creator.ts var rowWriterMapper = (maps, path, options) => { return (data) => file_append_promise_default(path, row_formatter_default(maps, data, options), options); }; var getAsyncFlatFileCreator = (maps, options) => { return (data, path) => Promise.all(data.map(rowWriterMapper(maps, path, options))); }; var dataToLines = (data, fields, options) => { return data.map((d) => row_formatter_default(fields, d, options || {})); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Types, dataToLines, fieldFormatter, getAsyncFlatFileCreator, getAsyncFlatFileReader, linesToData, parseLine, rowFormatter }); //# sourceMappingURL=index.cjs.map