An extremely simple, pluggable static site generator for NodeJS
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
File reading and writing operations for handling individual files and file collections. These methods provide direct access to Metalsmith's file I/O system for custom processing workflows.
Read all files from a directory, parsing front-matter and creating file objects.
/**
* Read files from directory (Promise version)
* @param directory - Directory to read (defaults to source directory)
* @returns Promise resolving to Files object
*/
read(directory?: string): Promise<Files>;
/**
* Read files from directory (callback version)
* @param directory - Directory to read (defaults to source directory)
* @param callback - Callback receiving error and files
*/
read(directory: string, callback: FileCallback): void;
type FileCallback = (error: Error | null, files: Files) => void;Usage Examples:
import Metalsmith from "metalsmith";
const metalsmith = Metalsmith(__dirname);
// Read from default source directory
const files = await metalsmith.read();
console.log(`Read ${Object.keys(files).length} files`);
// Read from specific directory
const templateFiles = await metalsmith.read('./templates');
// Callback version
metalsmith.read((error, files) => {
if (error) throw error;
Object.keys(files).forEach(filepath => {
console.log(`File: ${filepath}`);
console.log(`Size: ${files[filepath].contents.length} bytes`);
});
});Read a single file by path, parsing front-matter if enabled.
/**
* Read single file by path (Promise version)
* @param filepath - File path (relative to source directory or absolute)
* @returns Promise resolving to File object
*/
readFile(filepath: string): Promise<File>;
/**
* Read single file by path (callback version)
* @param filepath - File path (relative to source directory or absolute)
* @param callback - Callback receiving error and file
*/
readFile(filepath: string, callback: SingleFileCallback): void;
type SingleFileCallback = (error: Error | null, file?: File) => void;Usage Examples:
// Read specific file
const indexFile = await metalsmith.readFile('index.md');
console.log('Title:', indexFile.title);
console.log('Content:', indexFile.contents.toString());
// Read with absolute path
const configFile = await metalsmith.readFile('/path/to/config.json');
// Callback version
metalsmith.readFile('about.md', (error, file) => {
if (error) {
console.error('Failed to read file:', error.message);
return;
}
console.log('File metadata:', {
title: file.title,
date: file.date,
size: file.contents.length
});
});Write a collection of files to the destination directory.
/**
* Write files to destination directory (Promise version)
* @param files - Files object to write
* @param directory - Target directory (defaults to destination directory)
* @returns Promise that resolves when writing is complete
*/
write(files: Files, directory?: string): Promise<void>;
/**
* Write files to directory (callback version)
* @param files - Files object to write
* @param directory - Target directory (defaults to destination directory)
* @param callback - Callback for completion
*/
write(files: Files, directory: string, callback: BuildCallback): void;
/**
* Write files with callback only
* @param files - Files object to write
* @param callback - Callback for completion
*/
write(files: Files, callback: BuildCallback): void;Usage Examples:
// Write processed files to default destination
const files = await metalsmith.read();
// ... process files with plugins
await metalsmith.write(files);
// Write to specific directory
await metalsmith.write(files, './output');
// Callback version
metalsmith.write(files, (error) => {
if (error) {
console.error('Write failed:', error.message);
return;
}
console.log('Files written successfully');
});Write a single file to the destination directory.
/**
* Write single file (Promise version)
* @param filepath - Target file path (relative to destination or absolute)
* @param data - File object to write
* @returns Promise that resolves when writing is complete
*/
writeFile(filepath: string, data: File): Promise<void>;
/**
* Write single file (callback version)
* @param filepath - Target file path (relative to destination or absolute)
* @param data - File object to write
* @param callback - Callback for completion
*/
writeFile(filepath: string, data: File, callback: ErrorCallback): void;
type ErrorCallback = (error: Error | null) => void;Usage Examples:
// Create and write a new file
const newFile = {
contents: Buffer.from('# New Page\n\nThis is content.'),
title: 'New Page',
date: new Date()
};
await metalsmith.writeFile('new-page.html', newFile);
// Write to specific location
await metalsmith.writeFile('/absolute/path/file.txt', {
contents: Buffer.from('File content')
});
// Callback version
metalsmith.writeFile('output.json', {
contents: Buffer.from(JSON.stringify(data, null, 2))
}, (error) => {
if (error) throw error;
console.log('JSON file written');
});Understanding the File object structure for reading and writing operations.
interface File {
/** File contents as Buffer (always present) */
contents: Buffer;
/** Node.js fs.Stats object with file system metadata */
stats?: import('fs').Stats;
/** Octal file permission mode (e.g., "0644") */
mode?: string;
/** Front-matter properties and custom metadata */
[key: string]: any;
}
interface Files {
/** File path mapped to File object */
[filepath: string]: File;
}File Manipulation Examples:
// Reading and modifying file contents
const files = await metalsmith.read();
Object.keys(files).forEach(filepath => {
const file = files[filepath];
// Access file contents
const content = file.contents.toString();
// Access front-matter data
console.log('Title:', file.title);
console.log('Date:', file.date);
console.log('Tags:', file.tags);
// Modify contents
file.contents = Buffer.from(content.toUpperCase());
// Add custom metadata
file.processedAt = new Date();
file.wordCount = content.split(/\s+/).length;
// Preserve file stats and mode
console.log('File size:', file.stats?.size);
console.log('File mode:', file.mode);
});
await metalsmith.write(files);Examples of custom workflows using file operations directly.
// Custom build pipeline
async function customBuild() {
const metalsmith = Metalsmith(__dirname);
// Read source files
const sourceFiles = await metalsmith.read();
console.log(`Read ${Object.keys(sourceFiles).length} source files`);
// Read template files separately
const templates = await metalsmith.read('./templates');
console.log(`Read ${Object.keys(templates).length} templates`);
// Process files through plugins
const processedFiles = await metalsmith.run(sourceFiles);
// Write to multiple locations
await metalsmith.write(processedFiles, './public');
await metalsmith.write(processedFiles, './backup');
console.log('Custom build complete');
}
// Selective file processing
async function processSpecificFiles() {
const metalsmith = Metalsmith(__dirname);
// Read only markdown files
const allFiles = await metalsmith.read();
const markdownFiles = {};
Object.keys(allFiles)
.filter(filepath => filepath.endsWith('.md'))
.forEach(filepath => {
markdownFiles[filepath] = allFiles[filepath];
});
// Process only markdown files
const processed = await metalsmith.run(markdownFiles);
// Write processed files
await metalsmith.write(processed);
}Common error scenarios and handling patterns.
try {
const files = await metalsmith.read();
} catch (error) {
if (error.code === 'ENOENT') {
console.error('Source directory not found');
} else if (error.code === 'EACCES') {
console.error('Permission denied reading files');
} else if (error.code === 'invalid_frontmatter') {
console.error('Invalid front-matter in file:', error.message);
} else {
console.error('Read error:', error.message);
}
}
// Write error handling
try {
await metalsmith.write(files);
} catch (error) {
if (error.code === 'failed_write') {
console.error('Failed to write file:', error.message);
} else if (error.code === 'EACCES') {
console.error('Permission denied writing files');
} else {
console.error('Write error:', error.message);
}
}