Skip to content

TypeError & Working Version #11

@rebelancap

Description

@rebelancap

Stopped working for me today, with TypeError: undefined is not an object (evaluating 'o.classList [0].split')
Claude suggested the following instead, which now works for me.

// Fixed version of the Claude export script with better error handling
(function() {
    // Helper function to safely get language from classList
    function getLanguageFromClassList(element) {
        if (!element || !element.classList || element.classList.length === 0) {
            return 'text'; // default fallback
        }
        
        // Look for language- classes
        for (let className of element.classList) {
            if (className.startsWith('language-')) {
                return className.split('-')[1] || 'text';
            }
        }
        
        // Fallback: try the first class if it contains a dash
        const firstClass = element.classList[0];
        if (firstClass && firstClass.includes('-')) {
            return firstClass.split('-')[1] || 'text';
        }
        
        return 'text'; // ultimate fallback
    }

    // Save function
    function saveToFile(content, format, filename = '') {
        const mimeType = format === 'json' ? 'application/json' : 'text/plain';
        const extension = format === 'json' ? '.json' : '.md';
        
        let finalFilename = filename ? 
            filename.trim().toLowerCase().replace(/^[^\w\d]+|[^\w\d]+$/g, "").replace(/[\s\W-]+/g, "-") : 
            "claude";
        finalFilename += extension;
        
        if (format === 'json' && typeof content === 'object') {
            content = JSON.stringify(content, null, 2);
        }
        
        const blob = new Blob([content], { type: mimeType });
        const url = window.URL.createObjectURL(blob);
        
        const a = document.createElement('a');
        a.download = finalFilename;
        a.href = url;
        a.click();
        
        window.URL.revokeObjectURL(url);
    }

    // Get current timestamp
    function getCurrentTimestamp() {
        return new Date().toISOString().slice(0, 19).replace("T", " ");
    }

    // Extract conversation data
    function extractConversation() {
        const container = document.querySelector("div.flex-1.flex.flex-col.gap-3.px-4");
        const titleButton = document.querySelector("button[data-testid='chat-menu-trigger']");
        const title = titleButton ? titleButton.textContent : "";
        
        if (!container) {
            console.error("Could not find conversation container");
            return null;
        }
        
        const messageElements = container.querySelectorAll("div.font-claude-message, div.font-user-message");
        
        const conversation = {
            meta: {
                exported_at: getCurrentTimestamp(),
                title: title
            },
            chats: []
        };
        
        for (let i = 0; i < messageElements.length; i++) {
            const element = messageElements[i];
            const message = {
                index: i,
                type: element.classList.contains("font-claude-message") ? "response" : "prompt",
                message: []
            };
            
            const firstChild = element.firstChild;
            if (!firstChild) continue;
            
            let contentNodes = [];
            
            if (firstChild.nodeType === Node.ELEMENT_NODE) {
                if (message.type === "response") {
                    const innerChild = firstChild.firstChild || firstChild;
                    contentNodes = Array.from(innerChild.childNodes);
                } else {
                    contentNodes = Array.from(element.childNodes);
                }
                
                for (const node of contentNodes) {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        const tagName = node.tagName;
                        const textContent = node.textContent;
                        
                        if (tagName === 'P') {
                            message.message.push({ type: 'p', data: textContent });
                        } else if (tagName === 'OL' || tagName === 'UL') {
                            const items = Array.from(node.querySelectorAll('li')).map(li => ({
                                type: 'li',
                                data: li.textContent
                            }));
                            message.message.push({ 
                                type: tagName.toLowerCase(), 
                                data: items 
                            });
                        } else if (tagName === 'PRE') {
                            const codeElement = node.querySelector('code');
                            if (codeElement) {
                                const code = codeElement.textContent;
                                const language = getLanguageFromClassList(codeElement);
                                message.message.push({
                                    type: 'pre',
                                    language: language,
                                    data: code
                                });
                            }
                        } else if (tagName === 'TABLE') {
                            const tableData = [];
                            const sections = node.querySelectorAll('thead, tbody');
                            
                            sections.forEach(section => {
                                const rows = [];
                                const rowElements = section.querySelectorAll('tr');
                                
                                rowElements.forEach(row => {
                                    const cells = [];
                                    const cellElements = row.querySelectorAll('td, th');
                                    
                                    cellElements.forEach(cell => {
                                        cells.push({
                                            type: cell.tagName.toLowerCase(),
                                            data: cell.textContent
                                        });
                                    });
                                    
                                    rows.push({ type: 'tr', data: cells });
                                });
                                
                                tableData.push({
                                    type: section.tagName.toLowerCase(),
                                    data: rows
                                });
                            });
                            
                            message.message.push({ type: 'table', data: tableData });
                        }
                    }
                }
            } else if (firstChild.nodeType === Node.TEXT_NODE) {
                message.message.push({ type: 'text', data: firstChild.textContent });
            }
            
            conversation.chats.push(message);
        }
        
        return conversation;
    }
    
    // Main execution
    try {
        const conversation = extractConversation();
        if (conversation) {
            console.log("Conversation extracted successfully:", conversation);
            saveToFile(conversation, 'json', conversation.meta.title);
            console.log("✅ Export completed successfully!");
        } else {
            console.error("❌ Failed to extract conversation");
        }
    } catch (error) {
        console.error("❌ Export failed:", error);
    }
})();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions