CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nanomatch

Fast, minimal glob matcher for node.js with complete Bash 4.3 wildcard support

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

matcher-creation.mddocs/

Matcher Creation and Capture

Factory functions for creating reusable matchers and extracting pattern captures. These functions provide advanced pattern matching capabilities for performance optimization and pattern extraction.

Capabilities

Matcher Function Creation

Create reusable matcher functions from glob patterns for repeated matching operations.

/**
 * Create a reusable matcher function from a glob pattern
 * @param {String} pattern - Glob pattern to create matcher function for
 * @param {Object} options - Optional configuration for pattern compilation
 * @returns {Function} Matcher function that takes string and returns boolean
 */
nanomatch.matcher(pattern, options);

/**
 * Matcher function signature returned by nanomatch.matcher()
 * @param {String} str - String to test against the compiled pattern
 * @returns {Boolean} True if string matches the pattern, false otherwise
 */
type MatcherFunction = (str: string) => boolean;

Usage Examples:

const nanomatch = require('nanomatch');

// Create reusable matchers for performance
const isJavaScript = nanomatch.matcher('*.js');
const isComponent = nanomatch.matcher('*.component.*');
const isInSrc = nanomatch.matcher('src/**');

// Use matchers repeatedly
console.log(isJavaScript('app.js'));          //=> true
console.log(isJavaScript('styles.css'));      //=> false
console.log(isComponent('user.component.ts')); //=> true
console.log(isInSrc('src/app/main.ts'));      //=> true

// Matcher with options
const isCaseInsensitiveJS = nanomatch.matcher('*.js', { nocase: true });
console.log(isCaseInsensitiveJS('App.JS'));   //=> true

// Complex patterns
const isTestFile = nanomatch.matcher('**/*.{test,spec}.{js,ts}');
console.log(isTestFile('src/utils.test.js'));    //=> true
console.log(isTestFile('lib/component.spec.ts')); //=> true

// Negation patterns in matchers
const isNotNodeModules = nanomatch.matcher('!**/node_modules/**');
console.log(isNotNodeModules('src/app.js'));              //=> true
console.log(isNotNodeModules('node_modules/lib/dep.js')); //=> false

// Using matchers with arrays
const files = ['app.js', 'styles.css', 'component.ts', 'test.spec.js'];
const jsFiles = files.filter(isJavaScript);
console.log(jsFiles); //=> ['app.js']

// Benchmark performance benefit
const pattern = '**/*.{js,ts,jsx,tsx}';
const filesToTest = [/* thousands of file paths */];

// Slow: recompiling pattern each time
filesToTest.forEach(file => {
  if (nanomatch.isMatch(file, pattern)) {
    // process file
  }
});

// Fast: compile once, use many times
const isSourceFile = nanomatch.matcher(pattern);
filesToTest.forEach(file => {
  if (isSourceFile(file)) {
    // process file
  }
});

Pattern Capture Extraction

Extract captured groups from glob pattern matches for parsing and information extraction.

/**
 * Extract captures from a pattern match
 * @param {String} pattern - Glob pattern with capture groups (parentheses)
 * @param {String} string - String to match and extract captures from
 * @param {Object} options - Optional configuration for pattern matching
 * @returns {Array|null} Array of captured groups or null if no match
 */
nanomatch.capture(pattern, string, options);

Usage Examples:

const nanomatch = require('nanomatch');

// Basic capture with wildcards
console.log(nanomatch.capture('*.js', 'app.js'));
//=> ['app'] (captures the * part)

console.log(nanomatch.capture('*.js', 'styles.css'));
//=> null (no match)

// Multiple captures
console.log(nanomatch.capture('src/*/*.js', 'src/components/button.js'));
//=> ['components', 'button'] (captures both * parts)

// Directory and filename parsing
const pathPattern = '**/(*).(*).js';
console.log(nanomatch.capture(pathPattern, 'src/components/user.component.js'));
//=> ['user', 'component'] (captures name and type)

// Version string parsing
const versionPattern = 'v(*).(*).(*)-*';
console.log(nanomatch.capture(versionPattern, 'v1.2.3-beta'));
//=> ['1', '2', '3'] (captures major, minor, patch)

// URL-like pattern parsing
const routePattern = '/api/(*)/(*)/';
console.log(nanomatch.capture(routePattern, '/api/users/123/'));
//=> ['users', '123'] (captures resource and id)

// No captures in pattern
console.log(nanomatch.capture('*.js', 'app.js'));
//=> [] (pattern has no explicit capture groups)

// Empty captures
console.log(nanomatch.capture('prefix-*-suffix', 'prefix--suffix'));
//=> [''] (captures empty string between dashes)

// Nested directory capture
const nestedPattern = 'src/(**)/(*).(*)';
console.log(nanomatch.capture(nestedPattern, 'src/components/ui/button.component.tsx'));
//=> ['components/ui', 'button', 'component'] (captures path, name, type)

Advanced Usage Patterns

Performance Optimization with Matchers

const nanomatch = require('nanomatch');

// Scenario: Processing large file lists with multiple pattern checks
const files = [
  'src/app.js', 'src/utils.js', 'lib/helper.js',
  'test/app.test.js', 'test/utils.spec.js',
  'docs/readme.md', 'config/webpack.js'
];

// Inefficient: recompiling patterns
function processFilesSlowly(files) {
  const results = { source: [], tests: [], configs: [] };
  
  files.forEach(file => {
    if (nanomatch.isMatch(file, 'src/**/*.js')) {
      results.source.push(file);
    }
    if (nanomatch.isMatch(file, '**/*.{test,spec}.js')) {
      results.tests.push(file);
    }
    if (nanomatch.isMatch(file, 'config/**')) {
      results.configs.push(file);
    }
  });
  
  return results;
}

// Efficient: pre-compiled matchers
function processFilesQuickly(files) {
  const isSource = nanomatch.matcher('src/**/*.js');
  const isTest = nanomatch.matcher('**/*.{test,spec}.js');
  const isConfig = nanomatch.matcher('config/**');
  
  const results = { source: [], tests: [], configs: [] };
  
  files.forEach(file => {
    if (isSource(file)) results.source.push(file);
    if (isTest(file)) results.tests.push(file);
    if (isConfig(file)) results.configs.push(file);
  });
  
  return results;
}

Information Extraction with Captures

const nanomatch = require('nanomatch');

// File path parsing
function parseFilePath(filePath) {
  // Extract directory, name, and extension
  const captures = nanomatch.capture('(**)/(*).(*)' , filePath);
  if (!captures) return null;
  
  const [directory, name, extension] = captures;
  return { directory, name, extension };
}

console.log(parseFilePath('src/components/button.tsx'));
//=> { directory: 'src/components', name: 'button', extension: 'tsx' }

// API route parsing
function parseApiRoute(route) {
  const captures = nanomatch.capture('/api/v(*)/(*)/(*)', route);
  if (!captures) return null;
  
  const [version, resource, id] = captures;
  return { version, resource, id: id || null };
}

console.log(parseApiRoute('/api/v1/users/123'));
//=> { version: '1', resource: 'users', id: '123' }

console.log(parseApiRoute('/api/v2/posts/'));
//=> { version: '2', resource: 'posts', id: '' }

// Configuration key parsing
function parseConfigKey(key) {
  const captures = nanomatch.capture('(*).(*).(*)', key);
  if (!captures) return null;
  
  const [service, environment, setting] = captures;
  return { service, environment, setting };
}

console.log(parseConfigKey('database.production.host'));
//=> { service: 'database', environment: 'production', setting: 'host' }

// Build artifact parsing
function parseBuildArtifact(filename) {
  const captures = nanomatch.capture('(*)-v(*)-(*)-(*).*', filename);
  if (!captures) return null;
  
  const [name, version, platform, arch] = captures;
  return { name, version, platform, arch };
}

console.log(parseBuildArtifact('myapp-v1.2.3-linux-x64.tar.gz'));
//=> { name: 'myapp', version: '1.2.3', platform: 'linux', arch: 'x64' }

Matcher Function Properties

const nanomatch = require('nanomatch');

// Matchers have additional properties for debugging
const matcher = nanomatch.matcher('src/**/*.{js,ts}');

// Access compilation result (non-enumerable property)
console.log(matcher.result);
//=> { output: '...', ast: {...}, ... } (compilation details)

// Matcher functions are memoized
const matcher1 = nanomatch.matcher('*.js');
const matcher2 = nanomatch.matcher('*.js');
console.log(matcher1 === matcher2); //=> true (same cached function)

// Different options create different matchers
const matcher3 = nanomatch.matcher('*.js', { nocase: true });
console.log(matcher1 === matcher3); //=> false (different options)

Error Handling

const nanomatch = require('nanomatch');

// Invalid pattern types
try {
  nanomatch.matcher(123);
} catch (error) {
  console.log(error.message);
  //=> 'expected pattern to be an array, string or regex'
}

try {
  nanomatch.matcher(null);
} catch (error) {
  console.log(error.message);
  //=> 'expected pattern to be an array, string or regex'
}

// Empty patterns
const emptyMatcher = nanomatch.matcher('');
console.log(emptyMatcher('anything')); //=> false

// Capture with non-matching patterns
console.log(nanomatch.capture('*.js', 'style.css')); //=> null

// Empty string inputs
console.log(nanomatch.capture('*', '')); //=> [''] (captures empty string)
console.log(nanomatch.capture('', 'test')); //=> null (empty pattern doesn't match)

Memory and Performance Considerations

  • Matcher functions are cached globally - identical patterns with identical options return the same function instance
  • Use matchers when you need to test the same pattern against many strings
  • Captures are not cached - each call recomputes the match and extractions
  • Matchers include compiled regex and metadata, so they use more memory than simple functions
  • For one-off matching, isMatch() may be more efficient than creating a matcher

docs

collection-operations.md

content-matching.md

core-matching.md

index.md

matcher-creation.md

regex-compilation.md

tile.json