A Node.js TypeScript library for resolving YAML documents containing !reference and !reference-all tags. The library uses the eemeli/yaml package to parse YAML with custom tags and resolve references to external YAML files.
- Custom YAML Tags: Support for
!referenceand!reference-alltags - Recursive Resolution: Automatically resolves nested references
- Circular Reference Detection: Prevents infinite loops with proper error messages
- Glob Pattern Support:
!reference-allsupports glob patterns for multiple files - CLI Interface: Command-line tool for resolving YAML files
- TypeScript Support: Full type definitions included
This Node.js TypeScript library implements the YAML specification for cross-file references in YAML files using tags !reference and !reference-all as defined in the yaml-reference-specs project.
npm install @dsillman2000/yaml-reference-tsOr for global CLI usage:
npm install -g @dsillman2000/yaml-reference-ts# Block mapping syntax
database: !reference
path: ./config/database.yaml
# Inline mapping syntax
settings: !reference {path: ./settings/production.yaml}# Block mapping syntax
configs: !reference-all
glob: ./configs/*.yaml
# Inline mapping syntax
files: !reference-all {glob: ./data/*.yaml}Note: Only mapping syntax is supported. Be sure to conform to the API (!reference {path: <path>} or !reference-all {glob: <glob>}).
Deterministic Ordering: The !reference-all tag resolves files in alphabetical order to ensure consistent, predictable results across different systems and runs.
import { loadYamlWithReferences } from '@dsillman2000/yaml-reference-ts';
async function loadConfig() {
try {
const resolved = await loadYamlWithReferences('./config/main.yaml');
console.log(resolved);
} catch (error) {
console.error('Failed to resolve references:', error);
}
}Loads a YAML file and resolves all !reference and !reference-all tags, returning the fully resolved object.
Parses YAML content with custom tags, setting _location on Reference objects.
Loads a YAML file and resolves all !reference and !reference-all tags, returning the fully resolved object synchronously.
Parses YAML content with custom tags, setting _location on Reference objects synchronously.
Represents a !reference tag with properties:
_location: Absolute path to the file containing the referencepath: Relative path to the referenced YAML file
Represents a !reference-all tag with properties:
_location: Absolute path to the file containing the referenceglob: Glob pattern to match YAML files
The package includes a CLI tool called yaml-reference-cli:
If an example config.yaml contains:
services:
- !reference {path: services/etl-hub.yaml}
- !reference {path: services/etl-worker.yaml}
connections: !reference-all {glob: databases/*.yaml}With other files containing valid YAML data, then we can use the CLI to visualize the resolved YAML as JSON:
# Basic usage (resolve references, stdout as json)
$ yaml-reference-cli config.yaml
{
"connections": [
{
"name": "payments_pg",
"type": "postgres"
},
{
"name": "transactions_redis",
"type": "redis"
}
],
"services": [
{
"name": "etl-hub",
"type": "service"
},
{
"name": "etl-worker",
"type": "service"
}
]
}
# Pipe to a file
$ yaml-reference-cli config.yaml > .compiled/config.jsonIf you have the yq CLI installed (mikefarah/yq), resolved YAML can be pretty-printed as well (with keys sorted):
# Basic usage (resolve references, stdout as json, convert to YAML)
$ yaml-reference-cli config.yaml | yq -P
connections:
- name: payments_pg
type: postgres
- name: transactions_redis
type: redis
services:
- name: etl-hub
type: service
- name: etl-worker
type: service
# Pipe to a file
$ yaml-reference-cli config.yaml | yq -P > .compiled/config.yamlThis basic CLI usage is also explained in the help message.
yaml-reference-cli --helpThe CLI outputs JSON with:
- Keys sorted alphabetically
- 2-space indentation
- Exit code 0 for success, 1 for errors
- The
pathproperty is parsed from the YAML mapping _locationis automatically set to the absolute path of the containing file- The referenced YAML file is read and parsed relative to
_location - Any references within the referenced file are recursively resolved
- The
Referenceobject is replaced with the resolved content
- The
globproperty is parsed from the YAML mapping _locationis automatically set to the absolute path of the containing file- The glob pattern is evaluated relative to
_location - For each matching YAML file:
- The file is read and parsed
- Any references are recursively resolved
- The
ReferenceAllobject is replaced with an array of resolved contents - Files are sorted and resolved in deterministic alphabetical order for consistent results across systems
- If no files match, an error is thrown
Deterministic Behavior: The library ensures predictable output by:
- Sorting
!reference-allfile matches alphabetically before resolution - Rejecting scalar syntax (only mapping syntax is allowed)
- Using consistent error messages for validation failures
The library throws descriptive errors for:
- Missing referenced files
- Invalid YAML syntax
- Circular references (detected via visited file path tracking)
- Invalid glob patterns
- Missing required properties (
pathfor!reference,globfor!reference-all)
yaml-reference-ts/
├── src/
│ ├── index.ts # Main exports
│ ├── Reference.ts # Reference class
│ ├── ReferenceAll.ts # ReferenceAll class
│ ├── resolver.ts # loadAndResolve implementation
│ ├── parser.ts # YAML parser with custom tags
│ └── cli/
│ └── index.ts # CLI implementation
├── __tests__/ # Test files
├── doc/
│ └── Design.md # Design specification
├── package.json
├── tsconfig.json
└── README.md
# Install dependencies
npm install
# Build the project
npm run build
# Watch mode for development
npm run dev# Run tests
npm test
# Watch mode
npm run test:watch
# Coverage report
npm run test:coverage
# Run specific test file
npm test -- __tests__/parser.test.tsnpm run lintyaml(eemeli/yaml): YAML parsing with custom tag supportglob: Pattern matching for!reference-alltags
- TypeScript
- Jest for testing
- ESLint for code quality
Author(s):
- David Sillman dsillman2000@gmail.com