JSON Config Guide
April 14, 2026 · View on GitHub
The runtime parsing functions (parsePattern and parsePatterns) are designed for loading regex patterns from JSON configuration files. This is perfect for configuration-driven applications where patterns need to be updated without code changes.
Why JSON Config?
Your Workflow
You mentioned using .mjs files that get converted to JSON strings and parsed at runtime. The runtime parser functions are designed exactly for this use case:
// 1. Define patterns in JSON (human-readable with dots)
{
"pattern": "^(?<user.name>\\w+)@(?<user.domain>\\w+)$"
}
// 2. Load and parse at runtime
const config = JSON.parse(configString);
const parser = parsePattern(config.pattern);
// 3. Use immediately
const result = parser('john@example.com');
// { user: { name: 'john', domain: 'example.com' } }
Benefits
- ✅ Human-readable: Dots in group names (not underscores)
- ✅ No build step: Parse at runtime
- ✅ Dynamic updates: Change patterns without redeploying
- ✅ Shareable: Same config across projects
- ✅ Flexible: Load from files, APIs, databases, etc.
Basic Usage
Single Pattern
import { parsePattern } from 'nested-regex-groups';
// From JSON config
const config = {
pattern: "^(?<user.name>\\w+)@(?<user.domain>\\w+)$"
};
const parser = parsePattern(config.pattern);
const result = parser('john@example.com');
console.log(result.value);
// { user: { name: 'john', domain: 'example.com' } }
Multiple Patterns
import { parsePatterns } from 'nested-regex-groups';
// From JSON config file
const config = {
patterns: [
{
name: "email",
pattern: "^(?<user.name>\\w+)@(?<user.domain>\\w+)$",
description: "Email address"
},
{
name: "username",
pattern: "^(?<user.name>\\w+)$",
description: "Simple username"
}
]
};
const parser = parsePatterns(config.patterns);
const result1 = parser('john@example.com');
// { success: true, pattern: 'email', value: { user: { name: 'john', domain: 'example.com' } } }
const result2 = parser('jane');
// { success: true, pattern: 'username', value: { user: { name: 'jane' } } }
Complete Workflow Example
1. Create JSON Config File
config/patterns.json:
{
"parserName": "be-switched",
"patterns": [
{
"name": "simpleComparison",
"pattern": "^(?<trigger>on|off)\\s+when\\s+(?<lhs.id>#\\w+)\\s+(?<op>eq)\\s+(?<rhs.id>#\\w+)$",
"description": "Simple comparison"
},
{
"name": "booleanCondition",
"pattern": "^(?<trigger>on|off)\\s+when\\s+(?<lhs.id>#\\w+)$",
"description": "Boolean condition"
}
]
}
2. Load and Parse at Runtime
import { readFileSync } from 'fs';
import { parsePatterns } from 'nested-regex-groups';
// Load config
const configContent = readFileSync('./config/patterns.json', 'utf-8');
const config = JSON.parse(configContent);
// Create parser
const parser = parsePatterns(config.patterns);
// Use parser
const result = parser('on when #lhs eq #rhs');
console.log(result);
// {
// success: true,
// pattern: 'simpleComparison',
// value: {
// trigger: 'on',
// lhs: { id: '#lhs' },
// op: 'eq',
// rhs: { id: '#rhs' }
// }
// }
Your .mjs → JSON Workflow
Based on your description, here's how it would work:
Before (Manual groupMap)
// patterns.mjs
export const patterns = [
{
name: 'email',
regex: String.raw`^(?<user_name>\w+)@(?<user_domain>\w+)$`,
groupMap: { user_name: 'user.name', user_domain: 'user.domain' }
}
];
// Convert to JSON string, parse at runtime
const config = JSON.parse(JSON.stringify(patterns));
// Then manually create parser with groupMap...
After (Automatic with parsePatterns)
// patterns.mjs
export const patterns = [
{
name: 'email',
pattern: String.raw`^(?<user.name>\w+)@(?<user.domain>\w+)$`,
description: 'Email address'
}
];
// Convert to JSON string, parse at runtime
const config = JSON.parse(JSON.stringify(patterns));
const parser = parsePatterns(config);
// Done! Dots automatically converted to underscores + groupMap created
Or even simpler - just use JSON directly:
{
"patterns": [
{
"name": "email",
"pattern": "^(?<user.name>\\w+)@(?<user.domain>\\w+)$",
"description": "Email address"
}
]
}
Dynamic Configuration
Load patterns from anywhere:
From API
import { parsePatterns } from 'nested-regex-groups';
// Fetch from API
const response = await fetch('https://api.example.com/patterns');
const config = await response.json();
// Create parser
const parser = parsePatterns(config.patterns);
From Database
import { parsePatterns } from 'nested-regex-groups';
// Load from database
const config = await db.query('SELECT * FROM parser_configs WHERE name = ?', ['be-switched']);
// Create parser
const parser = parsePatterns(config.patterns);
From Environment
import { parsePatterns } from 'nested-regex-groups';
// Load from environment variable
const config = JSON.parse(process.env.PARSER_CONFIG);
// Create parser
const parser = parsePatterns(config.patterns);
Pattern String Format
Escaping in JSON
When writing patterns in JSON, remember to escape backslashes:
{
"pattern": "^(?<name>\\w+)$"
}
The \\w becomes \w after JSON.parse.
Common Patterns
{
"patterns": [
{
"name": "word",
"pattern": "^(?<value>\\w+)$"
},
{
"name": "number",
"pattern": "^(?<value>\\d+)$"
},
{
"name": "whitespace",
"pattern": "^(?<value>\\s+)$"
},
{
"name": "email",
"pattern": "^(?<user.name>\\w+)@(?<user.domain>[\\w.]+)$"
}
]
}
Error Handling
With Pattern Names
const parser = parsePattern(config.pattern, 'email-pattern');
const result = parser('invalid');
if (!result.success) {
console.log(result.error);
// "Pattern 'email-pattern' did not match"
}
Verbose Mode
const parser = parsePatterns(config.patterns, { verbose: true });
const result = parser('invalid');
if (!result.success) {
console.log(result.error);
// "No pattern matched. Tried:
// email: Pattern 'email' did not match
// username: Pattern 'username' did not match"
}
Best Practices
1. Use Descriptive Names
{
"name": "emailWithDomain",
"pattern": "...",
"description": "Matches email addresses with username and domain"
}
2. Order by Specificity
{
"patterns": [
{
"name": "specificEmail",
"pattern": "^(?<user.name>\\w+)@example\\.com$"
},
{
"name": "generalEmail",
"pattern": "^(?<user.name>\\w+)@(?<user.domain>\\w+)$"
}
]
}
3. Add Descriptions
{
"name": "comparison",
"pattern": "...",
"description": "Matches comparison expressions like 'on when #lhs eq #rhs'"
}
4. Validate Config at Startup
try {
const parser = parsePatterns(config.patterns);
console.log('✓ Parser initialized successfully');
} catch (error) {
console.error('✗ Failed to initialize parser:', error);
process.exit(1);
}
Comparison: Template Tag vs JSON Config
Template Tag (Development)
import { rx } from 'nested-regex-groups/template';
// Best for: Code-based patterns, type safety, IDE support
const parser = rx`^(?<user.name>\w+)@(?<user.domain>\w+)$`;
Use when:
- Patterns are part of your code
- You want type inference
- Patterns rarely change
- You want IDE autocomplete
JSON Config (Runtime)
import { parsePattern } from 'nested-regex-groups';
// Best for: Configuration-driven, dynamic updates, sharing
const parser = parsePattern(config.pattern);
Use when:
- Patterns come from config files
- You need dynamic updates
- Patterns are shared across projects
- Non-developers need to update patterns
Real-World Example: be-switched
See examples/json-config.json and examples/json-config-usage.ts for a complete working example of the be-switched parser loaded from JSON config.
Summary
parsePattern()- Single pattern from stringparsePatterns()- Multiple patterns from config objects- Dots in JSON - Automatically converted to underscores
- No build step - Parse at runtime
- Dynamic - Load from files, APIs, databases, etc.
- Perfect for - Configuration-driven applications
Your .mjs → JSON workflow is now much simpler with automatic dot-to-underscore conversion!