Skip to content

Commit 7861fc0

Browse files
committed
feat: port yamlize + yamlize-cli from cosmology-tech/yamlize into dev-utils
Port the yamlize YAML templating engine and its CLI into the dev-utils monorepo as modernized TypeScript packages. yamlize (core): - import-yaml directive resolution for composing YAML from fragments - ${{yamlize.VAR}} template variable substitution from context - Programmatic API: yamlizeString(), yamlizeObject() (not just file→file) - toYaml/fromYaml wrappers around js-yaml - Deep merge with null-inheritance semantics (merge, mergeNullable) - Typed throughout (YamlNode, YamlizeContext, MergeOptions) - 26 unit tests covering templates, imports, merge, round-tripping yamlize-cli (@yamlize/cli): - CLI wrapper using inquirerer for interactive prompts - --config, --inFile, --outFile flags - Version/help support
1 parent fb2d273 commit 7861fc0

31 files changed

Lines changed: 3862 additions & 5219 deletions

packages/yamlize-cli/README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# @yamlize/cli
2+
3+
CLI for [yamlize](https://github.com/constructive-io/dev-utils/tree/main/packages/yamlize) — generate YAML from templates with imports and variable substitution.
4+
5+
## Install
6+
7+
```sh
8+
npm install -g @yamlize/cli
9+
```
10+
11+
Or locally:
12+
13+
```sh
14+
npm install @yamlize/cli
15+
```
16+
17+
## Usage
18+
19+
```sh
20+
yamlize --config config.yaml --inFile meta.yaml --outFile output.yaml
21+
```
22+
23+
### Options
24+
25+
| Flag | Description |
26+
|---|---|
27+
| `--config` | Path to a YAML config file providing template variables (optional) |
28+
| `--inFile` | Path to the meta YAML template file |
29+
| `--outFile` | Path where the generated YAML file will be saved |
30+
| `--help, -h` | Show help message |
31+
| `--version, -v` | Show version number |
32+
33+
### Config File
34+
35+
The config file provides the context for `${{yamlize.VAR}}` template substitution:
36+
37+
```yaml
38+
git:
39+
USER_NAME: Cosmology
40+
USER_EMAIL: developers@cosmology.zone
41+
NODE_VERSION: '20.x'
42+
```
43+
44+
### Interactive Mode
45+
46+
When run without arguments, the CLI will prompt for each required option interactively.
47+
48+
### Example
49+
50+
Given a template `meta.yaml`:
51+
52+
```yaml
53+
name: Build
54+
on:
55+
workflow_dispatch:
56+
jobs:
57+
build:
58+
runs-on: ubuntu-latest
59+
steps:
60+
- import-yaml: node/setup.yaml
61+
- name: Install
62+
run: yarn
63+
```
64+
65+
And a fragment `node/setup.yaml`:
66+
67+
```yaml
68+
name: Setup Node.js
69+
uses: actions/setup-node@v4
70+
with:
71+
node-version: ${{yamlize.NODE_VERSION}}
72+
```
73+
74+
Running:
75+
76+
```sh
77+
yamlize --config config.yaml --inFile meta.yaml --outFile workflow.yaml
78+
```
79+
80+
Produces the fully resolved `workflow.yaml` with imports inlined and variables substituted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
transform: {
6+
'^.+\\.tsx?$': [
7+
'ts-jest',
8+
{
9+
babelConfig: false,
10+
tsconfig: 'tsconfig.json',
11+
},
12+
],
13+
},
14+
transformIgnorePatterns: [`/node_modules/*`],
15+
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
16+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
17+
modulePathIgnorePatterns: ['dist/*']
18+
};

packages/yamlize-cli/package.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "@yamlize/cli",
3+
"version": "0.10.0",
4+
"description": "yamlize CLI — generate YAML from templates with imports and variable substitution",
5+
"author": "Dan Lynch <pyramation@gmail.com>",
6+
"homepage": "https://github.com/constructive-io/dev-utils",
7+
"license": "MIT",
8+
"main": "index.js",
9+
"module": "esm/index.js",
10+
"types": "index.d.ts",
11+
"bin": {
12+
"yamlize": "index.js"
13+
},
14+
"publishConfig": {
15+
"access": "public",
16+
"directory": "dist"
17+
},
18+
"scripts": {
19+
"copy": "makage assets",
20+
"clean": "makage clean",
21+
"prepublishOnly": "npm run build",
22+
"build": "makage build",
23+
"lint": "eslint . --fix",
24+
"test": "jest",
25+
"test:watch": "jest --watch"
26+
},
27+
"repository": {
28+
"type": "git",
29+
"url": "https://github.com/constructive-io/dev-utils"
30+
},
31+
"keywords": [
32+
"yaml",
33+
"cli",
34+
"template",
35+
"generate"
36+
],
37+
"bugs": {
38+
"url": "https://github.com/constructive-io/dev-utils/issues"
39+
},
40+
"dependencies": {
41+
"inquirerer": "workspace:*",
42+
"js-yaml": "^4.1.0",
43+
"minimist": "1.2.8",
44+
"yamlize": "workspace:*"
45+
},
46+
"devDependencies": {
47+
"@types/js-yaml": "^4.0.9",
48+
"@types/minimist": "^1.2.5",
49+
"makage": "0.1.10"
50+
}
51+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { readFileSync } from 'fs';
2+
import type { CLIOptions, Inquirerer } from 'inquirerer';
3+
import yaml from 'js-yaml';
4+
import type { ParsedArgs } from 'minimist';
5+
import { yamlize } from 'yamlize';
6+
import type { YamlizeContext } from 'yamlize';
7+
8+
import { help } from './usage';
9+
10+
export const commands = async (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => {
11+
if (argv.version || argv.v) {
12+
const pkg = JSON.parse(readFileSync(require.resolve('../package.json'), 'utf-8'));
13+
console.log(pkg.version);
14+
process.exit(0);
15+
}
16+
17+
if (argv.help || argv.h) {
18+
help();
19+
process.exit(0);
20+
}
21+
22+
argv = await prompter.prompt(argv, [
23+
{
24+
type: 'text',
25+
name: 'config',
26+
message: 'path to the config',
27+
required: false,
28+
},
29+
{
30+
type: 'text',
31+
name: 'inFile',
32+
message: 'Provide the path the meta yaml file',
33+
required: true,
34+
},
35+
{
36+
type: 'text',
37+
name: 'outFile',
38+
message: 'Provide the path the output yaml file',
39+
required: true,
40+
},
41+
]);
42+
43+
let context: YamlizeContext = {};
44+
45+
if (argv.config) {
46+
const ctxContent = readFileSync(argv.config, 'utf-8');
47+
context = yaml.load(ctxContent) as YamlizeContext;
48+
}
49+
50+
yamlize(argv.inFile, argv.outFile, context);
51+
52+
return argv;
53+
};

packages/yamlize-cli/src/index.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env node
2+
import { CLI } from 'inquirerer';
3+
import type { CLIOptions } from 'inquirerer';
4+
5+
import { commands } from './commands';
6+
7+
export const options: Partial<CLIOptions> = {
8+
minimistOpts: {
9+
alias: {
10+
v: 'version',
11+
h: 'help',
12+
},
13+
},
14+
};
15+
16+
const app = new CLI(commands, options);
17+
18+
app
19+
.run()
20+
.then(() => {
21+
// all done!
22+
})
23+
.catch((error) => {
24+
console.error(error);
25+
process.exit(1);
26+
});

packages/yamlize-cli/src/usage.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export function help(): void {
2+
console.log(`
3+
Usage:
4+
5+
yamlize --config <path to config file>
6+
--inFile <path to the meta yaml file>
7+
--outFile <path to the output yaml file>
8+
9+
Options:
10+
11+
--help, -h Show this help message.
12+
--version, -v Show the version number.
13+
--config Path to the config file (optional).
14+
--inFile Path to the meta yaml file where the configuration is defined.
15+
--outFile Path where the generated yaml file will be saved.
16+
`);
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "dist/esm",
5+
"module": "es2022"
6+
}
7+
}

packages/yamlize-cli/tsconfig.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"rootDir": "src/"
6+
},
7+
"include": ["src/**/*.ts"],
8+
"exclude": ["dist", "node_modules", "**/*.spec.*", "**/*.test.*"]
9+
}

0 commit comments

Comments
 (0)