0
# Utilities and Helpers
1
2
Utility methods for path resolution, file matching, environment variables, ignore patterns, and file watching. These helpers provide essential functionality for configuring and extending Metalsmith behavior.
3
4
## Capabilities
5
6
### Path Resolution
7
8
Resolve paths relative to the Metalsmith working directory.
9
10
```javascript { .api }
11
/**
12
* Resolve paths relative to the metalsmith working directory
13
* @param paths - Path segments to resolve
14
* @returns Absolute path resolved from working directory
15
*/
16
path(...paths: string[]): string;
17
```
18
19
**Usage Examples:**
20
21
```javascript
22
import Metalsmith from "metalsmith";
23
24
const metalsmith = Metalsmith(__dirname);
25
26
// Resolve paths relative to working directory
27
const srcPath = metalsmith.path('src', 'content');
28
const buildPath = metalsmith.path('build');
29
const configPath = metalsmith.path('config', 'site.json');
30
31
console.log(srcPath); // "/absolute/path/to/project/src/content"
32
console.log(buildPath); // "/absolute/path/to/project/build"
33
console.log(configPath); // "/absolute/path/to/project/config/site.json"
34
35
// Use in plugins
36
function customPlugin(files, metalsmith, done) {
37
const dataPath = metalsmith.path('data', 'api.json');
38
const templatePath = metalsmith.path('templates');
39
40
// Use resolved paths for file operations
41
done();
42
}
43
```
44
45
### File Pattern Matching
46
47
Match file paths against glob patterns using micromatch.
48
49
```javascript { .api }
50
/**
51
* Match filepaths against glob patterns
52
* @param patterns - Glob pattern(s) to match against
53
* @param input - Array of file paths to test (defaults to current files)
54
* @param options - Micromatch options (excluding 'format')
55
* @returns Array of matching file paths
56
*/
57
match(
58
patterns: string | string[],
59
input?: string[],
60
options?: MatchOptions
61
): string[];
62
63
interface MatchOptions {
64
/** Include dotfiles in matches */
65
dot?: boolean;
66
/** Case-sensitive matching */
67
nocase?: boolean;
68
/** Additional micromatch options */
69
[key: string]: any;
70
}
71
```
72
73
**Usage Examples:**
74
75
```javascript
76
const files = await metalsmith.read();
77
const filePaths = Object.keys(files);
78
79
// Match all markdown files
80
const markdownFiles = metalsmith.match('**/*.md', filePaths);
81
82
// Match multiple patterns
83
const contentFiles = metalsmith.match([
84
'**/*.md',
85
'**/*.html',
86
'**/*.txt'
87
], filePaths);
88
89
// Match with options
90
const draftFiles = metalsmith.match('**/*draft*', filePaths, {
91
nocase: true // Case-insensitive
92
});
93
94
// Use in plugins
95
function selectivePlugin(files, metalsmith, done) {
96
const targetFiles = metalsmith.match('posts/*.md');
97
98
targetFiles.forEach(filepath => {
99
// Process only matching files
100
const file = files[filepath];
101
file.processed = true;
102
});
103
104
done();
105
}
106
107
// Default input uses current files
108
metalsmith.use((files, metalsmith, done) => {
109
// Automatically matches against Object.keys(files)
110
const jsFiles = metalsmith.match('**/*.js');
111
done();
112
});
113
```
114
115
### Environment Variables
116
117
Get and set Metalsmith environment variables (case-insensitive).
118
119
```javascript { .api }
120
/**
121
* Get single environment variable
122
* @param name - Variable name (case-insensitive)
123
* @returns Variable value or undefined
124
*/
125
env(name: string): string | number | boolean | null;
126
127
/**
128
* Get all environment variables
129
* @returns Object with all environment variables
130
*/
131
env(): { [key: string]: string | number | boolean | null };
132
133
/**
134
* Set single environment variable
135
* @param name - Variable name (case-insensitive)
136
* @param value - Variable value (primitives only)
137
* @returns Metalsmith instance for chaining
138
*/
139
env(name: string, value: string | number | boolean | null): Metalsmith;
140
141
/**
142
* Set multiple environment variables
143
* @param env - Object with variable names and values
144
* @returns Metalsmith instance for chaining
145
*/
146
env(env: { [key: string]: string | number | boolean | null }): Metalsmith;
147
```
148
149
**Usage Examples:**
150
151
```javascript
152
// Set environment variables
153
metalsmith
154
.env('NODE_ENV', 'production')
155
.env('DEBUG', '@metalsmith/*')
156
.env('SITE_URL', 'https://example.com');
157
158
// Set multiple at once
159
metalsmith.env({
160
NODE_ENV: process.env.NODE_ENV,
161
DEBUG: false,
162
BUILD_TIME: Date.now()
163
});
164
165
// Get environment variables
166
const nodeEnv = metalsmith.env('NODE_ENV');
167
const isDebug = metalsmith.env('DEBUG');
168
const allEnv = metalsmith.env();
169
170
console.log('Environment:', nodeEnv);
171
console.log('Debug mode:', isDebug);
172
console.log('All vars:', allEnv);
173
174
// Use in plugins
175
function environmentAwarePlugin(files, metalsmith, done) {
176
const isDev = metalsmith.env('NODE_ENV') === 'development';
177
const debugEnabled = metalsmith.env('DEBUG');
178
179
if (isDev) {
180
// Development-specific processing
181
}
182
183
if (debugEnabled) {
184
console.log('Processing files in debug mode');
185
}
186
187
done();
188
}
189
190
// Environment variables are case-insensitive
191
metalsmith.env('debug', true);
192
console.log(metalsmith.env('DEBUG')); // true
193
```
194
195
### Ignore Patterns
196
197
Configure which files and directories to ignore during processing.
198
199
```javascript { .api }
200
/**
201
* Add files/paths to ignore list
202
* @param files - File patterns, paths, or filter functions to ignore
203
* @returns Metalsmith instance for chaining
204
*/
205
ignore(files: string | string[] | IgnoreFunction | IgnoreFunction[]): Metalsmith;
206
207
/**
208
* Get current ignore list
209
* @returns Array of ignore patterns and functions
210
*/
211
ignore(): (string | IgnoreFunction)[];
212
213
type IgnoreFunction = (filepath: string, stats: import('fs').Stats) => boolean;
214
```
215
216
**Usage Examples:**
217
218
```javascript
219
import { Stats } from 'fs';
220
221
// Ignore specific files
222
metalsmith.ignore('README.md');
223
224
// Ignore patterns
225
metalsmith.ignore([
226
'**/.DS_Store',
227
'**/Thumbs.db',
228
'**/*.tmp',
229
'drafts/**'
230
]);
231
232
// Ignore using functions
233
metalsmith.ignore((filepath, stats) => {
234
// Ignore hidden files
235
return filepath.startsWith('.');
236
});
237
238
metalsmith.ignore((filepath, stats) => {
239
// Ignore large files (>1MB)
240
return stats.size > 1024 * 1024;
241
});
242
243
// Multiple ignore rules
244
metalsmith
245
.ignore('node_modules/**')
246
.ignore('*.log')
247
.ignore((filepath, stats) => {
248
// Ignore directories named 'temp'
249
return stats.isDirectory() && filepath.endsWith('/temp');
250
});
251
252
// Get current ignore list
253
const ignoreList = metalsmith.ignore();
254
console.log('Ignoring:', ignoreList);
255
```
256
257
### File Watching
258
259
Configure file watching for automatic rebuilds (experimental feature).
260
261
```javascript { .api }
262
/**
263
* Get current watch configuration
264
* @returns Current watch settings or false if disabled
265
*/
266
watch(): false | WatchOptions;
267
268
/**
269
* Enable/disable file watching
270
* @param enabled - True to watch source directory, false to disable
271
* @returns Metalsmith instance for chaining
272
*/
273
watch(enabled: boolean): Metalsmith;
274
275
/**
276
* Watch specific paths
277
* @param paths - Directory paths or glob patterns to watch
278
* @returns Metalsmith instance for chaining
279
*/
280
watch(paths: string | string[]): Metalsmith;
281
282
/**
283
* Configure watch options
284
* @param options - Chokidar watch options
285
* @returns Metalsmith instance for chaining
286
*/
287
watch(options: WatchOptions): Metalsmith;
288
289
interface WatchOptions {
290
/** Paths to watch (default: source directory) */
291
paths?: string[];
292
/** Wait for write operations to complete before triggering */
293
awaitWriteFinish?: boolean;
294
/** Ignore initial add events */
295
ignoreInitial?: boolean;
296
/** Use polling instead of native events */
297
usePolling?: boolean;
298
/** Polling interval in milliseconds */
299
interval?: number;
300
/** Additional chokidar options */
301
[key: string]: any;
302
}
303
```
304
305
**Usage Examples:**
306
307
```javascript
308
// Enable watching (experimental)
309
metalsmith
310
.clean(false) // Use partial rebuilds for better performance
311
.watch(true) // Watch source directory
312
.build((error, files) => {
313
if (error) {
314
console.error('Build error:', error);
315
metalsmith.watch(false); // Stop watching on error
316
return;
317
}
318
console.log(`Rebuilt ${Object.keys(files).length} files`);
319
});
320
321
// Watch specific directories
322
metalsmith.watch(['src', 'templates', 'data']);
323
324
// Advanced watch configuration
325
metalsmith.watch({
326
paths: ['src/**/*.md', 'templates/**/*.hbs'],
327
awaitWriteFinish: {
328
stabilityThreshold: 2000,
329
pollInterval: 100
330
},
331
ignoreInitial: true
332
});
333
334
// Get watch status
335
const watchConfig = metalsmith.watch();
336
if (watchConfig) {
337
console.log('Watching:', watchConfig.paths);
338
} else {
339
console.log('Watch mode disabled');
340
}
341
342
// Stop watching
343
metalsmith.watch(false);
344
```
345
346
### Utility Usage Patterns
347
348
Common patterns for using utilities in plugins and workflows.
349
350
```javascript
351
// Plugin using multiple utilities
352
function utilityPlugin(options = {}) {
353
return function plugin(files, metalsmith, done) {
354
const debug = metalsmith.env('DEBUG');
355
const pattern = options.pattern || '**/*.md';
356
357
// Use path utility for file operations
358
const dataPath = metalsmith.path('data', 'config.json');
359
360
// Match files using pattern
361
const targetFiles = metalsmith.match(pattern);
362
363
if (debug) {
364
console.log(`Processing ${targetFiles.length} files matching ${pattern}`);
365
}
366
367
targetFiles.forEach(filepath => {
368
const file = files[filepath];
369
// Process file...
370
});
371
372
done();
373
};
374
}
375
376
// Environment-based configuration
377
const isProduction = metalsmith.env('NODE_ENV') === 'production';
378
const debugEnabled = metalsmith.env('DEBUG');
379
380
metalsmith
381
.clean(isProduction) // Only clean in production
382
.concurrency(isProduction ? 50 : 10) // Higher concurrency in production
383
.ignore(isProduction ? [] : ['drafts/**']) // Include drafts in development
384
.env('MINIFY', isProduction); // Set flags for plugins
385
386
// Dynamic ignore patterns
387
metalsmith.ignore((filepath, stats) => {
388
const isDraft = files[filepath]?.draft === true;
389
const isProduction = metalsmith.env('NODE_ENV') === 'production';
390
391
// Ignore drafts in production
392
return isProduction && isDraft;
393
});
394
```