@feinarbyte/file-merge
v2.2.0
Published
File fragment merger - merge JSON, YAML, text files and more from templates, fragments, and overrides. Batteries included, dlx-ready.
Readme
@feinarbyte/file-merge
File fragment merger - batteries included, dlx-ready.
Merge files from templates, fragments, and overrides with intelligent strategies for YAML, JSON, GitLab CI, Docker Compose, TypeScript configs, text files, and more.
Installation
# Using pnpm dlx (recommended)
pnpm dlx @feinarbyte/file-merge
# Using npx
npx @feinarbyte/file-merge
# Or install globally
pnpm add -g @feinarbyte/file-mergeConfiguration
Create a config file in your project root to customize behavior:
# Create YAML config (recommended)
file-merge init
# Or create JSON config
file-merge init --jsonYAML Configuration (Recommended)
# .file-merge.config.yaml
templatesDir: config-templates
# Glob patterns with negation support
fragmentPatterns:
- "**/*.fragment.*" # Include all fragment files
- "!node_modules/**" # Exclude node_modules
- "!dist/**" # Exclude dist
# Advanced: Exclude folder but include specific patterns
# - "!folderA/folderB/**"
# - "folderA/folderB/catalog.*.fragment.*"
ignorePatterns:
- "**/node_modules/**"
- "**/dist/**"
- "**/.git/**"JSON Configuration
{
"templatesDir": "config-templates",
"fragmentPatterns": [
"**/*.fragment.*",
"!node_modules/**",
"!dist/**"
],
"ignorePatterns": [
"**/node_modules/**",
"**/dist/**",
"**/.git/**"
]
}Configuration Options
noSymlink- Copy single-source outputs instead of creating symlinks (default:false)copyPatterns- Per-file glob patterns (relative to project root) for targets that should be copied instead of symlinked when they have a single source (default:[])templatesDir- Directory containing template files with__prefix (default:"atom-framework/config-templates")fragmentPatterns- Glob patterns to discover fragment files. Supports negation with!prefix- Example:
["**/*.fragment.*", "!node_modules/**", "!folderA/**", "folderA/catalog.*.fragment.*"]
- Example:
ignorePatterns- Additional patterns to ignore (applied after fragmentPatterns)modules- Optional module activation filtering (atom-framework specific)activeDir- Directory where active modules are symlinkedsourceDir- Directory containing available modules
watchPatterns- Patterns to watch in watch mode (optional, auto-derived if not set)
Copy instead of symlink (per file)
By default, targets with a single source (typically a template) are symlinked to keep a single canonical file.
If you need a real file (for example .gitignore in some environments), configure per-target copy rules:
# .file-merge.config.yaml
copyPatterns:
- ".gitignore"Config File Formats
File-merge automatically detects and loads config files in this order:
.file-merge.config.yaml(recommended).file-merge.config.yml.file-merge.config.json
If no config file exists, file-merge uses default patterns suitable for the atom-framework structure.
Custom Config Location
You can specify a custom config file location:
# Use a different config file
file-merge apply --config configs/prod.config.json
# Use a shared config from parent directory
file-merge apply --config ../shared-config.json
# Watch with custom config
file-merge watch --config my-config.jsonUsage
Apply Merging
file-merge applyOptions:
--dry-run- Show what would be generated without writing files--verbose- Detailed output--filter <patterns...>- Only process files matching patterns--config <path>- Path to config file (default: auto-detect.yaml,.yml, or.json)
Watch Mode
file-merge watchAutomatically regenerates merged files when source files change.
Options:
--verbose- Detailed output--config <path>- Path to config file (default: auto-detect.yaml,.yml, or.json)
Migration
# Analyze existing files
file-merge migrate analyze
# Extract differences into override files
file-merge migrate extract --strategy smartValidation
file-merge validateStatus
file-merge status [file]Features
- Configurable - Customize templates directory, fragment patterns, and module locations via
.file-merge.config.json - Template-based merging - Define templates in configurable templates directory (default:
config-templates/) - Fragment merging - Merge fragments from packages/modules using configurable patterns
- Override support - Override templates with project-specific changes
- Smart merge strategies - Auto-detects merge strategy based on file type
- Template variables - Use
{{VARIABLE}}syntax in filenames and paths (resolved from environment variables) - Module filtering - Only include fragments from active modules (configurable)
- Supported formats: YAML, JSON, TOML, GitLab CI, Docker Compose, TypeScript configs, VS Code tasks, text files (.gitignore, .dockerignore), and more
Template Variables
File-merge supports template variables using {{VARIABLE}} syntax:
- In template filenames:
atom-framework/config-templates/__{{ENV}}.yaml→ resolves to{{ENV}}.yamlin project root - In fragment
_targetPath:_targetPath: "config/{{ENV}}.json"→ resolves to the target path
Variables are resolved from environment variables. If a required variable is missing, the tool will fail with a clear error message.
Example:
# Fragment file: packages/my-package/config.fragment.yaml
_targetPath: "config/{{ENV}}/settings.json"
# ... rest of fragment contentIf ENV=production, this fragment will target config/production/settings.json.
Merge Strategies
deep-merge- Deep merge for JSON objectsyaml-merge- Deep merge for YAML filestoml-merge- Deep merge for TOML filesgitlab-ci- GitLab CI/CD configuration mergingdocker-compose- Docker Compose file mergingtsconfig- TypeScript config mergingvscode-tasks- VS Code tasks.json mergingappend-lines- Line-by-line appending (for .gitignore, etc.)replace- Last source wins
GitLab CI job name prefix override (per fragment)
When merging .gitlab-ci.yml using the gitlab-ci strategy, file-merge normally prefixes jobs based on the fragment file’s folder hierarchy.
You can override this per fragment using __gitlabJobPrefix:
_targetPath: .gitlab-ci.yml
__gitlabJobPrefix: deploy # "" disables prefixing
build:
stage: build
script:
- echo "hello"Development
This project uses mise for tool version management.
# Install tools (node, pnpm)
mise install
# Install dependencies
pnpm install
# Build
pnpm run build
# Watch mode
pnpm run devReleasing
Releases are automated via GitLab CI. When a version tag is pushed, the pipeline publishes the package to npm.
# Patch release (bug fixes): 2.0.1 → 2.0.2
pnpm run release:patch
# Minor release (new features): 2.0.1 → 2.1.0
pnpm run release:minor
# Major release (breaking changes): 2.0.1 → 3.0.0
pnpm run release:majorEach release command will:
- Bump the version in
package.json - Create a git commit with message
chore(release): vX.Y.Z - Create a git tag
vX.Y.Z - Push the commit and tag to origin
The GitLab CI pipeline then automatically publishes to npm.
Manual Publishing
If you need to publish manually:
# Make sure you're logged in to npm with access to @feinarbyte scope
pnpm login
# Publish (will automatically build via prepublishOnly)
pnpm publish --access publicMigration from Hardcoded Paths
If you're using an older version with hardcoded atom-framework/ paths, file-merge will continue to work with the default configuration. To customize for your project:
- Run
file-merge initto create.file-merge.config.json - Edit the config to match your project structure
- Update
templatesDir,fragmentPatterns, andmodulespaths as needed
Example for a different structure:
{
"templatesDir": "config-templates",
"fragmentPatterns": [
"src/**/*.fragment.*",
"libs/**/*.fragment.*"
],
"modules": {
"activeDir": "enabled-modules",
"sourceDir": "src/modules"
}
}License
MIT
