or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

archive-creation.mdarchive-manipulation.mdarchive-reading.mdcomments-metadata.mdfile-extraction.mdindex.md
tile.json

comments-metadata.mddocs/

Comments and Metadata

Comprehensive functionality for managing ZIP archive comments, individual entry metadata, and archive-level information for documentation and organization purposes.

Capabilities

Archive Comments

Manage comments at the archive level for documentation and identification purposes.

/**
 * Add comment to the entire ZIP archive
 * @param {string} comment - Archive comment text
 */
addZipComment(comment);

/**
 * Get the current archive comment
 * @returns {string} Archive comment text (empty string if no comment)
 */
getZipComment();

Usage Examples:

const AdmZip = require("adm-zip");

// Create archive with comment
const zip = new AdmZip();
zip.addFile("readme.txt", Buffer.from("Hello World", "utf8"));
zip.addZipComment("Application backup created on " + new Date().toISOString());
zip.writeZip("./backup.zip");

// Read existing archive comment
const existingZip = new AdmZip("./backup.zip");
const comment = existingZip.getZipComment();
console.log("Archive comment:", comment);

// Update archive comment
existingZip.addZipComment("Updated backup - version 2.0");
existingZip.writeZip("./backup.zip");

// Add multi-line comment with metadata
const metadata = [
    "Project: MyApp v1.2.3",
    "Created: " + new Date().toISOString(),
    "Author: Development Team",
    "Purpose: Production deployment package",
    "Contact: dev-team@company.com"
].join("\n");

zip.addZipComment(metadata);

// Conditional comment based on contents
const entries = zip.getEntries();
const fileCount = entries.filter(e => !e.isDirectory).length;
const dirCount = entries.filter(e => e.isDirectory).length;
const totalSize = entries.reduce((sum, e) => sum + (e.header.size || 0), 0);

const statsComment = `Archive Statistics:
Files: ${fileCount}
Directories: ${dirCount}
Total Size: ${Math.round(totalSize / 1024)} KB
Generated: ${new Date().toLocaleString()}`;

zip.addZipComment(statsComment);

Entry Comments

Manage comments for individual files and directories within the archive.

/**
 * Add comment to specific ZIP entry
 * @param {ZipEntry} entry - Target entry object
 * @param {string} comment - Entry comment text (max 65535 characters)
 */
addZipEntryComment(entry, comment);

/**
 * Get comment for specific ZIP entry
 * @param {ZipEntry} entry - Target entry object
 * @returns {string} Entry comment text (empty string if no comment)
 */
getZipEntryComment(entry);

Usage Examples:

const zip = new AdmZip();

// Add files with comments
zip.addFile("config.json", Buffer.from('{"debug": true}', "utf8"));
const configEntry = zip.getEntry("config.json");
zip.addZipEntryComment(configEntry, "Main application configuration file");

zip.addFile("data/users.csv", Buffer.from("name,email\nJohn,john@example.com", "utf8"));
const csvEntry = zip.getEntry("data/users.csv");
zip.addZipEntryComment(csvEntry, "User database export - contains sensitive data");

// Read entry comments
const entries = zip.getEntries();
entries.forEach(entry => {
    const comment = zip.getZipEntryComment(entry);
    if (comment) {
        console.log(`${entry.entryName}: ${comment}`);
    }
});

// Add descriptive comments to directories
zip.addFile("assets/", null); // Create directory
const assetsDir = zip.getEntry("assets/");
zip.addZipEntryComment(assetsDir, "Static assets: images, stylesheets, fonts");

zip.addFile("docs/", null);
const docsDir = zip.getEntry("docs/");
zip.addZipEntryComment(docsDir, "Project documentation and API references");

// Batch comment addition
const commentMap = {
    "package.json": "Node.js package manifest",
    "README.md": "Project overview and setup instructions",
    "LICENSE": "MIT license terms",
    "src/app.js": "Main application entry point",
    "src/config/": "Configuration files and environment settings",
    "test/": "Unit tests and integration tests"
};

Object.keys(commentMap).forEach(entryName => {
    const entry = zip.getEntry(entryName);
    if (entry) {
        zip.addZipEntryComment(entry, commentMap[entryName]);
    }
});

Metadata Analysis

Analyze and extract various metadata from archive entries for reporting and organization.

Usage Examples:

const zip = new AdmZip("./project.zip");

// Generate comprehensive metadata report
function generateMetadataReport() {
    const entries = zip.getEntries();
    const archiveComment = zip.getZipComment();
    const report = {
        archive: {
            comment: archiveComment,
            totalEntries: entries.length,
            createdDate: new Date().toISOString()
        },
        entries: []
    };
    
    entries.forEach(entry => {
        const entryComment = zip.getZipEntryComment(entry);
        const entryInfo = {
            name: entry.entryName,
            type: entry.isDirectory ? 'directory' : 'file',
            size: entry.header.size,
            compressedSize: entry.header.compressedSize,
            compressionRatio: entry.header.size > 0 ? 
                Math.round((1 - entry.header.compressedSize / entry.header.size) * 100) : 0,
            lastModified: entry.header.time,
            comment: entryComment,
            hasComment: entryComment.length > 0,
            crc32: entry.header.crc
        };
        
        report.entries.push(entryInfo);
    });
    
    return report;
}

const report = generateMetadataReport();
console.log("Archive Report:", JSON.stringify(report, null, 2));

// Find entries with comments
function findCommentedEntries() {
    const entries = zip.getEntries();
    const commentedEntries = [];
    
    entries.forEach(entry => {
        const comment = zip.getZipEntryComment(entry);
        if (comment) {
            commentedEntries.push({
                name: entry.entryName,
                comment: comment,
                commentLength: comment.length
            });
        }
    });
    
    return commentedEntries;
}

const commentedFiles = findCommentedEntries();
console.log(`Found ${commentedFiles.length} entries with comments`);

// Extract file type statistics with comments
function analyzeFileTypes() {
    const entries = zip.getEntries();
    const typeStats = {};
    
    entries.forEach(entry => {
        if (!entry.isDirectory) {
            const ext = entry.entryName.split('.').pop().toLowerCase() || 'no-extension';
            if (!typeStats[ext]) {
                typeStats[ext] = {
                    count: 0,
                    totalSize: 0,
                    withComments: 0,
                    examples: []
                };
            }
            
            typeStats[ext].count++;
            typeStats[ext].totalSize += entry.header.size;
            
            const comment = zip.getZipEntryComment(entry);
            if (comment) {
                typeStats[ext].withComments++;
            }
            
            if (typeStats[ext].examples.length < 3) {
                typeStats[ext].examples.push({
                    name: entry.entryName,
                    hasComment: comment.length > 0
                });
            }
        }
    });
    
    return typeStats;
}

const typeAnalysis = analyzeFileTypes();
console.log("File Type Analysis:", typeAnalysis);

Comment Management

Advanced comment management including validation, migration, and bulk operations.

Usage Examples:

// Validate comment lengths and content
function validateComments() {
    const entries = zip.getEntries();
    const issues = [];
    
    // Check archive comment
    const archiveComment = zip.getZipComment();
    if (archiveComment.length > 65535) {
        issues.push("Archive comment exceeds maximum length (65535 characters)");
    }
    
    // Check entry comments
    entries.forEach(entry => {
        const comment = zip.getZipEntryComment(entry);
        if (comment.length > 65535) {
            issues.push(`Entry '${entry.entryName}' comment exceeds maximum length`);
        }
        
        // Check for potentially problematic characters
        if (comment.includes('\0')) {
            issues.push(`Entry '${entry.entryName}' comment contains null characters`);
        }
    });
    
    return issues;
}

const validationIssues = validateComments();
if (validationIssues.length > 0) {
    console.log("Comment validation issues:", validationIssues);
}

// Migrate comments from external metadata file
function migrateCommentsFromJSON(metadataFile) {
    const fs = require("fs");
    const metadata = JSON.parse(fs.readFileSync(metadataFile, "utf8"));
    
    // Set archive comment
    if (metadata.archiveComment) {
        zip.addZipComment(metadata.archiveComment);
    }
    
    // Set entry comments
    if (metadata.entryComments) {
        Object.keys(metadata.entryComments).forEach(entryName => {
            const entry = zip.getEntry(entryName);
            if (entry) {
                zip.addZipEntryComment(entry, metadata.entryComments[entryName]);
                console.log(`Added comment to: ${entryName}`);
            } else {
                console.log(`Entry not found: ${entryName}`);
            }
        });
    }
}

// Example metadata.json structure:
const exampleMetadata = {
    "archiveComment": "Project release v1.0.0 - Production ready",
    "entryComments": {
        "src/main.js": "Application entry point with initialization logic",
        "config/prod.json": "Production environment configuration",
        "docs/README.md": "Complete project documentation"
    }
};

// Export comments to external file
function exportCommentsToJSON(outputFile) {
    const entries = zip.getEntries();
    const exportData = {
        archiveComment: zip.getZipComment(),
        entryComments: {},
        exportDate: new Date().toISOString()
    };
    
    entries.forEach(entry => {
        const comment = zip.getZipEntryComment(entry);
        if (comment) {
            exportData.entryComments[entry.entryName] = comment;
        }
    });
    
    const fs = require("fs");
    fs.writeFileSync(outputFile, JSON.stringify(exportData, null, 2));
    console.log(`Exported comments to ${outputFile}`);
    
    return exportData;
}

const exportedComments = exportCommentsToJSON("./archive-comments.json");

// Bulk comment operations
function addCommentsByPattern(pattern, commentTemplate) {
    const entries = zip.getEntries();
    let addedCount = 0;
    
    entries.forEach(entry => {
        if (pattern.test(entry.entryName)) {
            const comment = commentTemplate.replace("{filename}", entry.entryName)
                                         .replace("{size}", entry.header.size)
                                         .replace("{date}", new Date().toLocaleDateString());
            zip.addZipEntryComment(entry, comment);
            addedCount++;
        }
    });
    
    console.log(`Added comments to ${addedCount} entries matching pattern`);
}

// Add timestamps to all JavaScript files
addCommentsByPattern(/\.js$/, "JavaScript file - {filename} ({size} bytes) - Archived on {date}");

// Remove all comments
function clearAllComments() {
    const entries = zip.getEntries();
    
    // Clear archive comment
    zip.addZipComment("");
    
    // Clear all entry comments
    entries.forEach(entry => {
        zip.addZipEntryComment(entry, "");
    });
    
    console.log("Cleared all comments from archive");
}

// Conditional comment clearing
function clearCommentsIf(condition) {
    const entries = zip.getEntries();
    let clearedCount = 0;
    
    entries.forEach(entry => {
        const comment = zip.getZipEntryComment(entry);
        if (comment && condition(entry, comment)) {
            zip.addZipEntryComment(entry, "");
            clearedCount++;
        }
    });
    
    console.log(`Cleared ${clearedCount} comments`);
}

// Clear comments from temporary files
clearCommentsIf((entry, comment) => entry.entryName.includes('.tmp'));