Comprehensive functionality for managing ZIP archive comments, individual entry metadata, and archive-level information for documentation and organization purposes.
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);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]);
}
});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);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'));