0
# Matcher Creation and Capture
1
2
Factory functions for creating reusable matchers and extracting pattern captures. These functions provide advanced pattern matching capabilities for performance optimization and pattern extraction.
3
4
## Capabilities
5
6
### Matcher Function Creation
7
8
Create reusable matcher functions from glob patterns for repeated matching operations.
9
10
```javascript { .api }
11
/**
12
* Create a reusable matcher function from a glob pattern
13
* @param {String} pattern - Glob pattern to create matcher function for
14
* @param {Object} options - Optional configuration for pattern compilation
15
* @returns {Function} Matcher function that takes string and returns boolean
16
*/
17
nanomatch.matcher(pattern, options);
18
19
/**
20
* Matcher function signature returned by nanomatch.matcher()
21
* @param {String} str - String to test against the compiled pattern
22
* @returns {Boolean} True if string matches the pattern, false otherwise
23
*/
24
type MatcherFunction = (str: string) => boolean;
25
```
26
27
**Usage Examples:**
28
29
```javascript
30
const nanomatch = require('nanomatch');
31
32
// Create reusable matchers for performance
33
const isJavaScript = nanomatch.matcher('*.js');
34
const isComponent = nanomatch.matcher('*.component.*');
35
const isInSrc = nanomatch.matcher('src/**');
36
37
// Use matchers repeatedly
38
console.log(isJavaScript('app.js')); //=> true
39
console.log(isJavaScript('styles.css')); //=> false
40
console.log(isComponent('user.component.ts')); //=> true
41
console.log(isInSrc('src/app/main.ts')); //=> true
42
43
// Matcher with options
44
const isCaseInsensitiveJS = nanomatch.matcher('*.js', { nocase: true });
45
console.log(isCaseInsensitiveJS('App.JS')); //=> true
46
47
// Complex patterns
48
const isTestFile = nanomatch.matcher('**/*.{test,spec}.{js,ts}');
49
console.log(isTestFile('src/utils.test.js')); //=> true
50
console.log(isTestFile('lib/component.spec.ts')); //=> true
51
52
// Negation patterns in matchers
53
const isNotNodeModules = nanomatch.matcher('!**/node_modules/**');
54
console.log(isNotNodeModules('src/app.js')); //=> true
55
console.log(isNotNodeModules('node_modules/lib/dep.js')); //=> false
56
57
// Using matchers with arrays
58
const files = ['app.js', 'styles.css', 'component.ts', 'test.spec.js'];
59
const jsFiles = files.filter(isJavaScript);
60
console.log(jsFiles); //=> ['app.js']
61
62
// Benchmark performance benefit
63
const pattern = '**/*.{js,ts,jsx,tsx}';
64
const filesToTest = [/* thousands of file paths */];
65
66
// Slow: recompiling pattern each time
67
filesToTest.forEach(file => {
68
if (nanomatch.isMatch(file, pattern)) {
69
// process file
70
}
71
});
72
73
// Fast: compile once, use many times
74
const isSourceFile = nanomatch.matcher(pattern);
75
filesToTest.forEach(file => {
76
if (isSourceFile(file)) {
77
// process file
78
}
79
});
80
```
81
82
### Pattern Capture Extraction
83
84
Extract captured groups from glob pattern matches for parsing and information extraction.
85
86
```javascript { .api }
87
/**
88
* Extract captures from a pattern match
89
* @param {String} pattern - Glob pattern with capture groups (parentheses)
90
* @param {String} string - String to match and extract captures from
91
* @param {Object} options - Optional configuration for pattern matching
92
* @returns {Array|null} Array of captured groups or null if no match
93
*/
94
nanomatch.capture(pattern, string, options);
95
```
96
97
**Usage Examples:**
98
99
```javascript
100
const nanomatch = require('nanomatch');
101
102
// Basic capture with wildcards
103
console.log(nanomatch.capture('*.js', 'app.js'));
104
//=> ['app'] (captures the * part)
105
106
console.log(nanomatch.capture('*.js', 'styles.css'));
107
//=> null (no match)
108
109
// Multiple captures
110
console.log(nanomatch.capture('src/*/*.js', 'src/components/button.js'));
111
//=> ['components', 'button'] (captures both * parts)
112
113
// Directory and filename parsing
114
const pathPattern = '**/(*).(*).js';
115
console.log(nanomatch.capture(pathPattern, 'src/components/user.component.js'));
116
//=> ['user', 'component'] (captures name and type)
117
118
// Version string parsing
119
const versionPattern = 'v(*).(*).(*)-*';
120
console.log(nanomatch.capture(versionPattern, 'v1.2.3-beta'));
121
//=> ['1', '2', '3'] (captures major, minor, patch)
122
123
// URL-like pattern parsing
124
const routePattern = '/api/(*)/(*)/';
125
console.log(nanomatch.capture(routePattern, '/api/users/123/'));
126
//=> ['users', '123'] (captures resource and id)
127
128
// No captures in pattern
129
console.log(nanomatch.capture('*.js', 'app.js'));
130
//=> [] (pattern has no explicit capture groups)
131
132
// Empty captures
133
console.log(nanomatch.capture('prefix-*-suffix', 'prefix--suffix'));
134
//=> [''] (captures empty string between dashes)
135
136
// Nested directory capture
137
const nestedPattern = 'src/(**)/(*).(*)';
138
console.log(nanomatch.capture(nestedPattern, 'src/components/ui/button.component.tsx'));
139
//=> ['components/ui', 'button', 'component'] (captures path, name, type)
140
```
141
142
## Advanced Usage Patterns
143
144
### Performance Optimization with Matchers
145
146
```javascript
147
const nanomatch = require('nanomatch');
148
149
// Scenario: Processing large file lists with multiple pattern checks
150
const files = [
151
'src/app.js', 'src/utils.js', 'lib/helper.js',
152
'test/app.test.js', 'test/utils.spec.js',
153
'docs/readme.md', 'config/webpack.js'
154
];
155
156
// Inefficient: recompiling patterns
157
function processFilesSlowly(files) {
158
const results = { source: [], tests: [], configs: [] };
159
160
files.forEach(file => {
161
if (nanomatch.isMatch(file, 'src/**/*.js')) {
162
results.source.push(file);
163
}
164
if (nanomatch.isMatch(file, '**/*.{test,spec}.js')) {
165
results.tests.push(file);
166
}
167
if (nanomatch.isMatch(file, 'config/**')) {
168
results.configs.push(file);
169
}
170
});
171
172
return results;
173
}
174
175
// Efficient: pre-compiled matchers
176
function processFilesQuickly(files) {
177
const isSource = nanomatch.matcher('src/**/*.js');
178
const isTest = nanomatch.matcher('**/*.{test,spec}.js');
179
const isConfig = nanomatch.matcher('config/**');
180
181
const results = { source: [], tests: [], configs: [] };
182
183
files.forEach(file => {
184
if (isSource(file)) results.source.push(file);
185
if (isTest(file)) results.tests.push(file);
186
if (isConfig(file)) results.configs.push(file);
187
});
188
189
return results;
190
}
191
```
192
193
### Information Extraction with Captures
194
195
```javascript
196
const nanomatch = require('nanomatch');
197
198
// File path parsing
199
function parseFilePath(filePath) {
200
// Extract directory, name, and extension
201
const captures = nanomatch.capture('(**)/(*).(*)' , filePath);
202
if (!captures) return null;
203
204
const [directory, name, extension] = captures;
205
return { directory, name, extension };
206
}
207
208
console.log(parseFilePath('src/components/button.tsx'));
209
//=> { directory: 'src/components', name: 'button', extension: 'tsx' }
210
211
// API route parsing
212
function parseApiRoute(route) {
213
const captures = nanomatch.capture('/api/v(*)/(*)/(*)', route);
214
if (!captures) return null;
215
216
const [version, resource, id] = captures;
217
return { version, resource, id: id || null };
218
}
219
220
console.log(parseApiRoute('/api/v1/users/123'));
221
//=> { version: '1', resource: 'users', id: '123' }
222
223
console.log(parseApiRoute('/api/v2/posts/'));
224
//=> { version: '2', resource: 'posts', id: '' }
225
226
// Configuration key parsing
227
function parseConfigKey(key) {
228
const captures = nanomatch.capture('(*).(*).(*)', key);
229
if (!captures) return null;
230
231
const [service, environment, setting] = captures;
232
return { service, environment, setting };
233
}
234
235
console.log(parseConfigKey('database.production.host'));
236
//=> { service: 'database', environment: 'production', setting: 'host' }
237
238
// Build artifact parsing
239
function parseBuildArtifact(filename) {
240
const captures = nanomatch.capture('(*)-v(*)-(*)-(*).*', filename);
241
if (!captures) return null;
242
243
const [name, version, platform, arch] = captures;
244
return { name, version, platform, arch };
245
}
246
247
console.log(parseBuildArtifact('myapp-v1.2.3-linux-x64.tar.gz'));
248
//=> { name: 'myapp', version: '1.2.3', platform: 'linux', arch: 'x64' }
249
```
250
251
## Matcher Function Properties
252
253
```javascript
254
const nanomatch = require('nanomatch');
255
256
// Matchers have additional properties for debugging
257
const matcher = nanomatch.matcher('src/**/*.{js,ts}');
258
259
// Access compilation result (non-enumerable property)
260
console.log(matcher.result);
261
//=> { output: '...', ast: {...}, ... } (compilation details)
262
263
// Matcher functions are memoized
264
const matcher1 = nanomatch.matcher('*.js');
265
const matcher2 = nanomatch.matcher('*.js');
266
console.log(matcher1 === matcher2); //=> true (same cached function)
267
268
// Different options create different matchers
269
const matcher3 = nanomatch.matcher('*.js', { nocase: true });
270
console.log(matcher1 === matcher3); //=> false (different options)
271
```
272
273
## Error Handling
274
275
```javascript
276
const nanomatch = require('nanomatch');
277
278
// Invalid pattern types
279
try {
280
nanomatch.matcher(123);
281
} catch (error) {
282
console.log(error.message);
283
//=> 'expected pattern to be an array, string or regex'
284
}
285
286
try {
287
nanomatch.matcher(null);
288
} catch (error) {
289
console.log(error.message);
290
//=> 'expected pattern to be an array, string or regex'
291
}
292
293
// Empty patterns
294
const emptyMatcher = nanomatch.matcher('');
295
console.log(emptyMatcher('anything')); //=> false
296
297
// Capture with non-matching patterns
298
console.log(nanomatch.capture('*.js', 'style.css')); //=> null
299
300
// Empty string inputs
301
console.log(nanomatch.capture('*', '')); //=> [''] (captures empty string)
302
console.log(nanomatch.capture('', 'test')); //=> null (empty pattern doesn't match)
303
```
304
305
## Memory and Performance Considerations
306
307
- Matcher functions are cached globally - identical patterns with identical options return the same function instance
308
- Use matchers when you need to test the same pattern against many strings
309
- Captures are not cached - each call recomputes the match and extractions
310
- Matchers include compiled regex and metadata, so they use more memory than simple functions
311
- For one-off matching, `isMatch()` may be more efficient than creating a matcher