UNPKG

purify-objects

Version:

A powerful TypeScript library for cleaning objects by removing empty values, with support for YAML and CSV formats

204 lines (203 loc) 6.63 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const isNil = (value) => value === null || value === void 0; const isObject = (value) => typeof value === "object" && value !== null; const cloneDeep = (obj) => { if (!isObject(obj)) return obj; if (Array.isArray(obj)) { return obj.map(cloneDeep); } return Object.entries(obj).reduce((acc, [key, value]) => ({ ...acc, [key]: cloneDeep(value) }), {}); }; function parseYAML(content) { const lines = content.split("\n"); const root = {}; let currentNode = root; let stack = [[root, -1]]; for (const line of lines) { if (!line.trim() || line.trim().startsWith("#")) continue; const indent = line.search(/\S/); const [key, ...valueParts] = line.trim().split(":"); let value = valueParts.join(":").trim(); while (stack.length > 1 && stack[stack.length - 1][1] >= indent) { stack.pop(); } currentNode = stack[stack.length - 1][0]; if (value) { if (value.startsWith("[") && value.endsWith("]")) { currentNode[key] = value.slice(1, -1).split(",").map((v) => v.trim()); } else if (value.toLowerCase() === "true") { currentNode[key] = true; } else if (value.toLowerCase() === "false") { currentNode[key] = false; } else if (value === "null") { currentNode[key] = null; } else if (!isNaN(Number(value))) { currentNode[key] = Number(value); } else { currentNode[key] = value.replace(/^["']|["']$/g, ""); } } else { currentNode[key] = {}; stack.push([currentNode[key], indent]); } } return root; } function parseCSV(content, options) { const lines = content.split("\n").filter((line) => line.trim()); const delimiter = options.delimiter || ","; const result = []; const headers = options.headers ? lines[0].split(delimiter).map((header) => header.trim()) : Array.from({ length: lines[0].split(delimiter).length }, (_, i) => `column${i + 1}`); const dataLines = options.headers ? lines.slice(1) : lines; for (const line of dataLines) { const values = line.split(delimiter).map((value) => { value = value.trim(); if (value.startsWith('"') && value.endsWith('"')) { return value.slice(1, -1); } if (value === "null") { return null; } if (value === "") { return value; } if (!isNaN(Number(value))) { return Number(value); } if (value.toLowerCase() === "true") { return true; } if (value.toLowerCase() === "false") { return false; } return value; }); const row = {}; headers.forEach((header, index) => { row[header] = values[index]; }); result.push(row); } return result; } function stringifyYAML(obj, indent = 0) { let result = ""; const spaces = " ".repeat(indent); for (const [key, value] of Object.entries(obj)) { if (value === null || value === void 0) { result += `${spaces}${key}: `; } else if (value === "") { result += `${spaces}${key}: "" `; } else if (Array.isArray(value)) { result += `${spaces}${key}: [${value.join(", ")}] `; } else if (typeof value === "object") { result += `${spaces}${key}: ${stringifyYAML(value, indent + 2)}`; } else if (typeof value === "string" && value.includes("\n")) { result += `${spaces}${key}: | ${value.split("\n").map((line) => `${spaces} ${line}`).join("\n")} `; } else { result += `${spaces}${key}: ${value} `; } } return result; } function stringifyCSV(objects, options) { const delimiter = options.delimiter || ","; const headers = options.headers ? Object.keys(objects[0]) : Array.from({ length: Object.keys(objects[0]).length }, (_, i) => `column${i + 1}`); let result = options.headers ? headers.join(delimiter) + "\n" : ""; for (const obj of objects) { const values = headers.map((header) => { const value = obj[header]; if (value === null || value === void 0) { return ""; } if (typeof value === "string" && (value.includes(delimiter) || value.includes('"'))) { return `"${value.replace(/"/g, '""')}"`; } return String(value); }); result += values.join(delimiter) + "\n"; } return result; } const INITIAL_OPTIONS = { customCleaner: void 0, keepFields: [], recursive: true, safe: true }; const evaluateEmptiness = (value) => isNil(value) || value === "" || Array.isArray(value) && !value.length || isObject(value) && !Object.keys(value).length; function processNestedObject(target, customCleaner, preservedFields, config) { const workingCopy = config.safe ? cloneDeep(target) : target; for (const key in workingCopy) { const value = workingCopy[key]; if (preservedFields.includes(key)) continue; if (customCleaner == null ? void 0 : customCleaner(key, value)) { delete workingCopy[key]; continue; } if (evaluateEmptiness(value)) { delete workingCopy[key]; continue; } if (config.recursive && isObject(value) && !Array.isArray(value)) { const processed = processNestedObject( value, customCleaner, preservedFields, config ); if (!Object.keys(processed).length) { delete workingCopy[key]; } else { workingCopy[key] = processed; } } } return workingCopy; } function cleanObject(obj, customCleaner, keepFields = [], options = {}) { const config = { ...INITIAL_OPTIONS, ...options }; return processNestedObject(obj, customCleaner, keepFields, config); } function parseContent(content, format, options = {}) { switch (format) { case "yaml": return parseYAML(content); case "csv": return parseCSV(content, { delimiter: options.delimiter || ",", headers: options.headers !== false }); default: return JSON.parse(content); } } function stringifyContent(data, format, options = {}) { switch (format) { case "yaml": return stringifyYAML(data); case "csv": return stringifyCSV(Array.isArray(data) ? data : [data], { delimiter: options.delimiter || ",", headers: options.headers !== false }); default: return JSON.stringify(data, null, 2); } } exports.cleanObject = cleanObject; exports.default = cleanObject; exports.parseCSV = parseCSV; exports.parseContent = parseContent; exports.parseYAML = parseYAML; exports.stringifyCSV = stringifyCSV; exports.stringifyContent = stringifyContent; exports.stringifyYAML = stringifyYAML;