UNPKG

meta-log-db

Version:

Native database package for Meta-Log (ProLog, DataLog, R5RS)

383 lines 14.8 kB
"use strict"; /** * Browser JSONL Parser * * Browser-specific JSONL parser using BrowserFileIO instead of Node.js fs */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BrowserJsonlParser = void 0; const io_js_1 = require("../io.js"); const storage_encryption_js_1 = require("../crypto/storage-encryption.js"); /** * Browser JSONL Parser */ class BrowserJsonlParser { constructor(config = {}) { this.facts = []; this.canvas = null; this.fileIO = config.fileIO || new io_js_1.BrowserFileIO(); this.enableEncryption = config.enableEncryption || false; this.mnemonic = config.mnemonic; this.encryptionPurpose = config.encryptionPurpose || 'local'; } /** * Initialize file I/O */ async init() { await this.fileIO.init(); } /** * Parse JSONL file from URL or IndexedDB */ async parse(filePath, url) { let content; try { // Load file content content = await this.fileIO.loadFile(filePath, url); // Decrypt if encryption is enabled if (this.enableEncryption && this.mnemonic) { try { content = await (0, storage_encryption_js_1.decryptFileContent)(content, this.mnemonic, this.encryptionPurpose); } catch (error) { // If decryption fails, assume content is not encrypted console.warn('Decryption failed, assuming unencrypted content:', error); } } } catch (error) { throw new Error(`Failed to load file ${filePath}: ${error}`); } // Parse JSONL content // Handle multiline JSON objects by accumulating lines until we have valid JSON const lines = content.split('\n'); const objects = []; let currentLine = ''; let braceDepth = 0; for (let i = 0; i < lines.length; i++) { const line = lines[i]; currentLine += (currentLine ? '\n' : '') + line; // Count braces to detect complete JSON objects for (const char of line) { if (char === '{') braceDepth++; if (char === '}') braceDepth--; } // If we have a complete JSON object (balanced braces), try to parse it if (braceDepth === 0 && currentLine.trim()) { try { const obj = JSON.parse(currentLine.trim()); objects.push(obj); currentLine = ''; } catch (error) { // If parsing fails, try to extract valid JSON from the line // This handles cases where there might be trailing content const trimmed = currentLine.trim(); const jsonMatch = trimmed.match(/^(\{.*\})/s); if (jsonMatch) { try { const obj = JSON.parse(jsonMatch[1]); objects.push(obj); } catch (e) { // If still fails, log and skip console.warn(`Failed to parse JSONL line ${i + 1}: ${trimmed.substring(0, 200)}...`, error); } } else { console.warn(`Failed to parse JSONL line ${i + 1}: ${trimmed.substring(0, 200)}...`, error); } currentLine = ''; } } } // Handle any remaining content if (currentLine.trim() && braceDepth === 0) { try { const obj = JSON.parse(currentLine.trim()); objects.push(obj); } catch (error) { console.warn(`Failed to parse final JSONL line: ${currentLine.substring(0, 200)}...`, error); } } this.canvas = this.organizeCanvas(objects); return this.canvas; } /** * Parse CanvasL file (with extensions) */ async parseCanvasL(filePath, url) { let content; try { // Load file content content = await this.fileIO.loadFile(filePath, url); // Decrypt if encryption is enabled if (this.enableEncryption && this.mnemonic) { try { content = await (0, storage_encryption_js_1.decryptFileContent)(content, this.mnemonic, this.encryptionPurpose); } catch (error) { // If decryption fails, assume content is not encrypted console.warn('Decryption failed, assuming unencrypted content:', error); } } } catch (error) { throw new Error(`Failed to load CanvasL file ${filePath}: ${error}`); } // Parse CanvasL content const lines = content.split('\n'); const objects = []; let currentDirective = null; let currentLine = ''; let braceDepth = 0; let i = 0; while (i < lines.length) { const line = lines[i]; const trimmed = line.trim(); // Handle directives if (trimmed.startsWith('@')) { // If we have accumulated content, try to parse it first if (currentLine.trim() && braceDepth === 0) { try { const obj = JSON.parse(currentLine.trim()); if (currentDirective) { obj._directive = `@${currentDirective}`; } objects.push(obj); } catch (error) { console.warn(`Failed to parse accumulated CanvasL line: ${currentLine.substring(0, 200)}...`, error); } currentLine = ''; } const match = trimmed.match(/^@(\w+)\s*(.*)$/); if (match) { currentDirective = match[1]; if (match[2]) { objects.push({ type: `@${currentDirective}`, value: match[2] }); } } i++; continue; } // Accumulate lines for JSON objects if (trimmed && trimmed.startsWith('{')) { currentLine += (currentLine ? '\n' : '') + line; // Count braces for (const char of line) { if (char === '{') braceDepth++; if (char === '}') braceDepth--; } // If we have a complete JSON object, parse it if (braceDepth === 0 && currentLine.trim()) { try { const obj = JSON.parse(currentLine.trim()); if (currentDirective) { obj._directive = `@${currentDirective}`; } objects.push(obj); currentLine = ''; } catch (error) { // Try to extract valid JSON from the line const trimmedLine = currentLine.trim(); const jsonMatch = trimmedLine.match(/^(\{.*\})/s); if (jsonMatch) { try { const obj = JSON.parse(jsonMatch[1]); if (currentDirective) { obj._directive = `@${currentDirective}`; } objects.push(obj); } catch (e) { console.warn(`Failed to parse CanvasL line ${i + 1}: ${trimmedLine.substring(0, 200)}...`, error); } } else { console.warn(`Failed to parse CanvasL line ${i + 1}: ${trimmedLine.substring(0, 200)}...`, error); } currentLine = ''; } } } else if (currentLine.trim() && braceDepth > 0) { // Continue accumulating if we're in the middle of a JSON object currentLine += '\n' + line; for (const char of line) { if (char === '{') braceDepth++; if (char === '}') braceDepth--; } // Check if we've completed the object if (braceDepth === 0 && currentLine.trim()) { try { const obj = JSON.parse(currentLine.trim()); if (currentDirective) { obj._directive = `@${currentDirective}`; } objects.push(obj); currentLine = ''; } catch (error) { console.warn(`Failed to parse accumulated CanvasL line ${i + 1}: ${currentLine.substring(0, 200)}...`, error); currentLine = ''; } } } i++; } // Handle any remaining content if (currentLine.trim() && braceDepth === 0) { try { const obj = JSON.parse(currentLine.trim()); if (currentDirective) { obj._directive = `@${currentDirective}`; } objects.push(obj); } catch (error) { console.warn(`Failed to parse final CanvasL line: ${currentLine.substring(0, 200)}...`, error); } } this.canvas = this.organizeCanvas(objects); return this.canvas; } /** * Organize parsed objects into canvas structure */ organizeCanvas(objects) { const canvas = { nodes: [], edges: [], }; for (const obj of objects) { if (obj.type === 'node' || obj.id) { canvas.nodes = canvas.nodes || []; canvas.nodes.push(obj); } else if (obj.type === 'edge' || obj.fromNode || obj.toNode) { canvas.edges = canvas.edges || []; canvas.edges.push(obj); } else { // Store other objects const key = obj.type || 'other'; if (!canvas[key]) { canvas[key] = []; } canvas[key].push(obj); } } return canvas; } /** * Extract facts from canvas */ extractFacts(canvas) { const targetCanvas = canvas || this.canvas; if (!targetCanvas) { return []; } this.facts = []; // Extract node facts if (targetCanvas.nodes) { for (const node of targetCanvas.nodes) { this.facts.push({ predicate: 'node', args: [node.id, node.type || 'unknown', node.x || 0, node.y || 0, node.text || ''] }); // Extract node properties as facts for (const [key, value] of Object.entries(node)) { if (!['id', 'type', 'x', 'y', 'text'].includes(key)) { this.facts.push({ predicate: `node_${key}`, args: [node.id, value] }); } } } } // Extract edge facts if (targetCanvas.edges) { for (const edge of targetCanvas.edges) { this.facts.push({ predicate: 'edge', args: [edge.id, edge.type || 'unknown', edge.fromNode, edge.toNode] }); // Extract vertical/horizontal relationships if (edge.type?.startsWith('v:')) { this.facts.push({ predicate: 'vertical', args: [edge.id, edge.fromNode, edge.toNode] }); } else if (edge.type?.startsWith('h:')) { this.facts.push({ predicate: 'horizontal', args: [edge.id, edge.fromNode, edge.toNode] }); } } } return this.facts; } /** * Convert facts to RDF triples */ toRdf(facts) { const targetFacts = facts || this.facts; const triples = []; for (const fact of targetFacts) { if (fact.predicate === 'node' && fact.args.length >= 2) { const [id, type] = fact.args; triples.push({ subject: `<http://example.org/node/${id}>`, predicate: '<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>', object: `<http://example.org/type/${type}>` }); } else if (fact.predicate === 'edge' && fact.args.length >= 4) { const [id, type, fromNode, toNode] = fact.args; triples.push({ subject: `<http://example.org/edge/${id}>`, predicate: '<http://example.org/predicate/fromNode>', object: `<http://example.org/node/${fromNode}>` }); triples.push({ subject: `<http://example.org/edge/${id}>`, predicate: '<http://example.org/predicate/toNode>', object: `<http://example.org/node/${toNode}>` }); triples.push({ subject: `<http://example.org/edge/${id}>`, predicate: '<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>', object: `<http://example.org/type/${type}>` }); } } return triples; } /** * Get extracted facts */ getFacts() { return [...this.facts]; } /** * Clear facts */ clear() { this.facts = []; this.canvas = null; } } exports.BrowserJsonlParser = BrowserJsonlParser; //# sourceMappingURL=browser-parser.js.map