A Haskell utility that analyzes JSON configuration files and creates an inverted index showing which config files contain which key-value pairs. This is particularly useful for tracking configuration usage across multiple files in large projects.
Given a directory of JSON configuration files, config-mapper
produces a mapping that shows for each key-value pair which files contain it. This inverted index makes it easy to:
- Find all configurations that use a specific key-value pair
- Track where certain configuration values are defined
- Audit configuration consistency across multiple files
Input files:
configs/C1.json
:
{
"name": "Crescent",
"title": "America"
}
configs/C2.json
:
{
"name": "Crescent",
"title": "Japanese"
}
Output (output.json
):
{
"name": {
"Crescent": ["C1.json", "C2.json"]
},
"title": {
"America": ["C1.json"],
"Japanese": ["C2.json"]
}
}
- GHC 9.10.1 or later
- Cabal 3.4 or later
Clone the repository and build:
git clone https://github.com/onnenon/config-mapper.git
cd config-mapper
cabal build
- Place your JSON configuration files in the
configs/
directory - Run the executable:
cabal run config-mapper
- The inverted configuration map will be written to
output.json
The project is organized into three main components:
Core functionality for reading and inverting config maps:
buildConfigMap
: Reads all JSON files from a directory and parses theminvertConfigMap
: Fold-based implementation for inverting the config mapinvertConfigMapLens
: Lens-based implementation (currently used by default)
Simple CLI that:
- Reads configs from the
configs/
directory - Inverts the configuration map
- Writes the result to
output.json
Comprehensive HSpec tests covering:
- Both inversion implementations
- Edge cases (empty maps, single files, multiple files)
- Real-world examples
type ConfigMap = Map FilePath (Map Text Text)
type InvertedConfigMap = Map Text (Map Text [FilePath])
- ConfigMap: Maps each file path to its key-value pairs
- InvertedConfigMap: Maps each key to its values, with each value mapped to the list of files containing that key-value pair
# Build the project
cabal build all
# Clean build artifacts
cabal clean
# Build and install
cabal install
# Run the executable
cabal run config-mapper
# Run tests
cabal test
# Run tests with verbose output
cabal test --test-show-details=direct
config-mapper/
├── app/
│ └── Main.hs # CLI executable
├── configs/ # Input directory for JSON configs
│ ├── C1.json
│ └── C2.json
├── src/
│ └── ConfigMapper.hs # Core library
├── test/
│ ├── Spec.hs
│ └── ConfigMapperSpec.hs # Test suite
├── config-map.cabal # Package configuration
└── output.json # Generated output
- aeson: JSON parsing and encoding
- lens: Lens-based map manipulation
- containers: Map data structures
- directory/filepath: File system operations
The library provides two implementations of the inversion logic:
invertConfigMap
: Original fold-based implementation using pure map operationsinvertConfigMapLens
: Lens-based implementation using Control.Lens for safe nested map navigation
The lens implementation uses at
, _Just
, and lens operators to safely navigate and update nested map structures. Both implementations are fully tested and produce identical results.
Config files should be valid JSON with flat key-value pairs where values are strings:
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Make your changes
- Run tests (
cabal test
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
For more detailed development information, see DEVELOPMENT.md.