UNPKG

@onurege3467/zerohelper

Version:

ZeroHelper is a versatile high-performance utility library and database framework for Node.js, fully written in TypeScript.

215 lines (214 loc) 8.5 kB
"use strict"; /** * TOON (Token-Oriented Object Notation) Support for ZeroHelper * Optimized for LLM token efficiency and now supports Native Storage. * API matches standard JSON object (stringify/parse). */ Object.defineProperty(exports, "__esModule", { value: true }); exports.stringify = stringify; exports.parse = parse; function stringify(data, indent = 0) { const space = ' '.repeat(indent); if (data === null) return 'null'; if (typeof data === 'boolean' || typeof data === 'number') return String(data); if (typeof data === 'string') { const hasSpecial = /[,\n: ]/.test(data); if (hasSpecial) return '"' + data.replace(/"/g, '\\"') + '"'; return data; } if (Array.isArray(data)) { if (data.length === 0) return '[]'; const first = data[0]; // ✅ FIX: Object array'leri için HER ZAMAN tabular format kullan (1+ eleman için) if (typeof first === 'object' && first !== null && !Array.isArray(first)) { const keys = Object.keys(first); const isUniform = data.every(item => item && typeof item === 'object' && Object.keys(item).length === keys.length && Object.keys(item).every(k => keys.includes(k))); if (isUniform) { const header = '[' + data.length + ']{' + keys.join(',') + '}:'; const rows = data.map(item => { const rowValues = keys.map(k => { const val = item[k]; if (val === null) return 'null'; if (Array.isArray(val)) { return '"' + JSON.stringify(val) + '"'; } const valStr = String(val); const hasSpecialRow = /[,\n: ]/.test(valStr); return (typeof val === 'string' && hasSpecialRow) ? '"' + valStr.replace(/"/g, '\\"') + '"' : valStr; }).join(','); return space + ' ' + rowValues; }); return header + '\n' + rows.join('\n'); } } // Non-object array'ler için inline format return '[' + data.length + ']: ' + data.map(v => stringify(v)).join(','); } if (typeof data === 'object') { const entries = Object.entries(data); if (entries.length === 0) return '{}'; return entries.map(([key, value]) => { const valStr = stringify(value, indent + 2); const isComplex = typeof value === 'object' && value !== null && !Array.isArray(value); const separator = isComplex ? '\n' : ' '; return space + key + ':' + separator + valStr; }).join('\n'); } return ''; } /** * Advanced TOON Parser with Indentation Support for Deep Nesting */ function parse(toonStr) { if (!toonStr || toonStr.trim() === '') return {}; const lines = toonStr.split('\n'); function parseValue(val) { const trimmed = val.trim(); // Tırnak içindeki string if (trimmed.startsWith('"') && trimmed.endsWith('"')) { const unquoted = trimmed.slice(1, -1).replace(/\\"/g, '"'); // JSON array string'i kontrol et try { if (unquoted.startsWith('[') && unquoted.endsWith(']')) { return JSON.parse(unquoted); } } catch (e) { // JSON değilse normal string döndür } return unquoted; } if (trimmed === 'true') return true; if (trimmed === 'false') return false; if (trimmed === 'null') return null; if (trimmed === '[]') return []; if (trimmed === '{}') return {}; if (!isNaN(Number(trimmed)) && trimmed !== '') return Number(trimmed); return trimmed; } function getIndent(line) { const match = line.match(/^(\s*)/); return match ? match[1].length : 0; } // CSV row parser with proper quote handling function parseCSVRow(row) { const result = []; let current = ''; let inQuotes = false; for (let i = 0; i < row.length; i++) { const char = row[i]; if (char === '"' && (i === 0 || row[i - 1] !== '\\')) { inQuotes = !inQuotes; current += char; } else if (char === ',' && !inQuotes) { result.push(current.trim()); current = ''; } else { current += char; } } if (current.trim()) { result.push(current.trim()); } return result; } function processLines(startIndex, currentIndent) { const result = {}; let i = startIndex; while (i < lines.length) { const line = lines[i]; const indent = getIndent(line); const content = line.trim(); // Boş satırları atla if (content === '') { i++; continue; } if (indent < currentIndent) break; // Standard Key-Value match const kvMatch = content.match(/^([^:]+):\s*(.*)$/); if (kvMatch) { const key = kvMatch[1].trim(); const valuePart = kvMatch[2].trim(); // ✅ FIX: Tabular array header - Format: [count]{field1,field2,...}: const tabularMatch = valuePart.match(/^\[(\d+)\]\{([^}]+)\}:$/); if (tabularMatch) { const expectedRowCount = parseInt(tabularMatch[1]); const fields = tabularMatch[2].split(',').map(f => f.trim()); const rows = []; let rowsRead = 0; i++; // Header'dan sonraki satıra geç while (i < lines.length && rowsRead < expectedRowCount) { const rowLine = lines[i]; const rowIndent = getIndent(rowLine); const rowContent = rowLine.trim(); // Boş satırları atla if (rowContent === '') { i++; continue; } // Indent kontrolü - child satır olmalı if (rowIndent <= currentIndent) { break; } // CSV parsing with quote support const values = parseCSVRow(rowContent); const row = {}; fields.forEach((f, idx) => { row[f] = idx < values.length ? parseValue(values[idx]) : null; }); rows.push(row); rowsRead++; i++; } result[key] = rows; continue; } // ✅ FIX: Inline array - [count]: value1,value2,... const inlineArrayMatch = valuePart.match(/^\[(\d+)\]:\s*(.+)$/); if (inlineArrayMatch) { const count = parseInt(inlineArrayMatch[1]); const valueStr = inlineArrayMatch[2].trim(); // Normal değer array'i (virgülle ayrılmış basit değerler) const values = parseCSVRow(valueStr); result[key] = values.map(v => parseValue(v)); i++; continue; } // Nested object check if (valuePart === '' && i + 1 < lines.length && getIndent(lines[i + 1]) > indent) { const [nestedObj, nextIndex] = processLines(i + 1, getIndent(lines[i + 1])); result[key] = nestedObj; i = nextIndex; continue; } // Simple value result[key] = parseValue(valuePart); i++; continue; } i++; } return [result, i]; } const [finalResult] = processLines(0, 0); return finalResult; }